1use std::borrow::Cow;
16use std::marker::PhantomData;
17use std::ops::{Index, IndexMut};
18
19use crate::element_op::{ComposableElementOp, ElementOp, ElementOpApply, Identity};
20use crate::{Result, StridedError};
21
22#[inline]
23fn empty_layout(dims: &[usize]) -> bool {
24 dims.iter().any(|&dim| dim == 0)
25}
26
27#[inline]
28fn empty_const_ptr<T>() -> *const T {
29 core::ptr::NonNull::<T>::dangling().as_ptr()
30}
31
32#[inline]
33fn empty_mut_ptr<T>() -> *mut T {
34 core::ptr::NonNull::<T>::dangling().as_ptr()
35}
36
37pub(crate) fn validate_bounds(
43 len: usize,
44 dims: &[usize],
45 strides: &[isize],
46 offset: isize,
47) -> Result<()> {
48 if dims.len() != strides.len() {
49 return Err(StridedError::StrideLengthMismatch);
50 }
51 if dims.iter().any(|&d| d == 0) {
53 return Ok(());
54 }
55 let mut min_offset = offset;
57 let mut max_offset = offset;
58 for (&dim, &stride) in dims.iter().zip(strides.iter()) {
59 if dim > 1 {
60 let last = dim
61 .checked_sub(1)
62 .and_then(|value| isize::try_from(value).ok())
63 .ok_or(StridedError::OffsetOverflow)?;
64 let end = stride
65 .checked_mul(last)
66 .ok_or(StridedError::OffsetOverflow)?;
67 if end >= 0 {
68 max_offset = max_offset
69 .checked_add(end)
70 .ok_or(StridedError::OffsetOverflow)?;
71 } else {
72 min_offset = min_offset
73 .checked_add(end)
74 .ok_or(StridedError::OffsetOverflow)?;
75 }
76 }
77 }
78 if min_offset < 0 || max_offset < 0 {
79 return Err(StridedError::OffsetOverflow);
80 }
81 if max_offset as usize >= len {
82 return Err(StridedError::OffsetOverflow);
83 }
84 Ok(())
85}
86
87pub fn col_major_strides(dims: &[usize]) -> Vec<isize> {
89 let rank = dims.len();
90 if rank == 0 {
91 return vec![];
92 }
93 let mut strides = vec![1isize; rank];
94 for i in 1..rank {
95 strides[i] = strides[i - 1] * dims[i - 1] as isize;
96 }
97 strides
98}
99
100pub fn row_major_strides(dims: &[usize]) -> Vec<isize> {
102 let rank = dims.len();
103 if rank == 0 {
104 return vec![];
105 }
106 let mut strides = vec![1isize; rank];
107 for i in (0..rank - 1).rev() {
108 strides[i] = strides[i + 1] * dims[i + 1] as isize;
109 }
110 strides
111}
112
113pub struct StridedView<'a, T, Op = Identity> {
130 ptr: *const T,
131 data: &'a [T],
132 dims: Cow<'a, [usize]>,
133 strides: Cow<'a, [isize]>,
134 offset: isize,
135 _op: PhantomData<Op>,
136}
137
138unsafe impl<T: Send, Op: Send> Send for StridedView<'_, T, Op> {}
139unsafe impl<T: Sync, Op: Sync> Sync for StridedView<'_, T, Op> {}
140
141impl<T, Op> Clone for StridedView<'_, T, Op> {
142 fn clone(&self) -> Self {
143 Self {
144 ptr: self.ptr,
145 data: self.data,
146 dims: self.dims.clone(),
147 strides: self.strides.clone(),
148 offset: self.offset,
149 _op: PhantomData,
150 }
151 }
152}
153
154impl<T: std::fmt::Debug, Op> std::fmt::Debug for StridedView<'_, T, Op> {
155 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
156 f.debug_struct("StridedView")
157 .field("dims", &self.dims)
158 .field("strides", &self.strides)
159 .field("offset", &self.offset)
160 .finish()
161 }
162}
163
164#[inline]
169fn base_ptr<T>(data: &[T], dims: &[usize], offset: isize) -> *const T {
170 if empty_layout(dims) {
171 empty_const_ptr()
172 } else {
173 unsafe { data.as_ptr().offset(offset) }
174 }
175}
176
177#[inline]
179fn from_meta<'a, T, Op>(
180 data: &'a [T],
181 dims: Cow<'a, [usize]>,
182 strides: Cow<'a, [isize]>,
183 offset: isize,
184) -> StridedView<'a, T, Op> {
185 StridedView {
186 ptr: base_ptr(data, &dims, offset),
187 data,
188 dims,
189 strides,
190 offset,
191 _op: PhantomData,
192 }
193}
194
195impl<'a, T, Op> StridedView<'a, T, Op> {
196 pub fn new(
201 data: &'a [T],
202 dims: &'a [usize],
203 strides: &'a [isize],
204 offset: isize,
205 ) -> Result<Self> {
206 validate_bounds(data.len(), dims, strides, offset)?;
207 Ok(from_meta(
208 data,
209 Cow::Borrowed(dims),
210 Cow::Borrowed(strides),
211 offset,
212 ))
213 }
214
215 pub fn new_owned(
220 data: &'a [T],
221 dims: Vec<usize>,
222 strides: Vec<isize>,
223 offset: isize,
224 ) -> Result<Self> {
225 validate_bounds(data.len(), &dims, &strides, offset)?;
226 Ok(from_meta(
227 data,
228 Cow::Owned(dims),
229 Cow::Owned(strides),
230 offset,
231 ))
232 }
233
234 pub unsafe fn new_unchecked(
239 data: &'a [T],
240 dims: &'a [usize],
241 strides: &'a [isize],
242 offset: isize,
243 ) -> Self {
244 from_meta(data, Cow::Borrowed(dims), Cow::Borrowed(strides), offset)
245 }
246
247 pub unsafe fn new_owned_unchecked(
252 data: &'a [T],
253 dims: Vec<usize>,
254 strides: Vec<isize>,
255 offset: isize,
256 ) -> Self {
257 from_meta(data, Cow::Owned(dims), Cow::Owned(strides), offset)
258 }
259
260 #[inline]
262 pub fn dims(&self) -> &[usize] {
263 &self.dims
264 }
265
266 #[inline]
268 pub fn strides(&self) -> &[isize] {
269 &self.strides
270 }
271
272 #[inline]
274 pub fn offset(&self) -> isize {
275 self.offset
276 }
277
278 #[inline]
280 pub fn ndim(&self) -> usize {
281 self.dims.len()
282 }
283
284 #[inline]
286 pub fn len(&self) -> usize {
287 self.dims.iter().product()
288 }
289
290 #[inline]
292 pub fn is_empty(&self) -> bool {
293 self.dims.iter().any(|&d| d == 0)
294 }
295
296 #[inline]
298 pub fn data(&self) -> &'a [T] {
299 self.data
300 }
301
302 #[inline]
304 pub fn ptr(&self) -> *const T {
305 self.ptr
306 }
307
308 pub fn permute(&self, perm: &[usize]) -> Result<StridedView<'a, T, Op>> {
310 let rank = self.dims.len();
311 if perm.len() != rank {
312 return Err(StridedError::RankMismatch(perm.len(), rank));
313 }
314 let mut seen = vec![false; rank];
315 for &p in perm {
316 if p >= rank {
317 return Err(StridedError::InvalidAxis { axis: p, rank });
318 }
319 if seen[p] {
320 return Err(StridedError::InvalidAxis { axis: p, rank });
321 }
322 seen[p] = true;
323 }
324 let new_dims: Vec<usize> = perm.iter().map(|&p| self.dims[p]).collect();
325 let new_strides: Vec<isize> = perm.iter().map(|&p| self.strides[p]).collect();
326 Ok(from_meta(
327 self.data,
328 Cow::Owned(new_dims),
329 Cow::Owned(new_strides),
330 self.offset,
331 ))
332 }
333
334 pub fn diagonal_view(&self, axis_pairs: &[(usize, usize)]) -> Result<StridedView<'a, T, Op>> {
345 let ndim = self.ndim();
346 let mut dims: Vec<usize> = self.dims().to_vec();
347 let mut strides: Vec<isize> = self.strides().to_vec();
348
349 let mut axes_to_remove = Vec::new();
350 for &(a, b) in axis_pairs {
351 let (lo, hi) = if a < b { (a, b) } else { (b, a) };
352 if lo >= ndim || hi >= ndim {
353 return Err(StridedError::InvalidAxis {
354 axis: hi,
355 rank: ndim,
356 });
357 }
358 if lo == hi {
359 return Err(StridedError::InvalidAxis {
360 axis: lo,
361 rank: ndim,
362 });
363 }
364 strides[lo] += strides[hi];
365 dims[lo] = dims[lo].min(dims[hi]);
366 axes_to_remove.push(hi);
367 }
368
369 axes_to_remove.sort_unstable();
370 axes_to_remove.dedup();
371 for &ax in axes_to_remove.iter().rev() {
372 dims.remove(ax);
373 strides.remove(ax);
374 }
375
376 Ok(from_meta(
377 self.data(),
378 Cow::Owned(dims),
379 Cow::Owned(strides),
380 self.offset(),
381 ))
382 }
383
384 pub fn broadcast(&self, target_dims: &[usize]) -> Result<StridedView<'a, T, Op>> {
388 if self.dims.len() != target_dims.len() {
389 return Err(StridedError::RankMismatch(
390 self.dims.len(),
391 target_dims.len(),
392 ));
393 }
394 let mut new_strides = Vec::with_capacity(self.dims.len());
395 for i in 0..self.dims.len() {
396 if self.dims[i] == target_dims[i] {
397 new_strides.push(self.strides[i]);
398 } else if self.dims[i] == 1 {
399 new_strides.push(0);
400 } else {
401 return Err(StridedError::ShapeMismatch(
402 self.dims.to_vec(),
403 target_dims.to_vec(),
404 ));
405 }
406 }
407 Ok(from_meta(
408 self.data,
409 Cow::Owned(target_dims.to_vec()),
410 Cow::Owned(new_strides),
411 self.offset,
412 ))
413 }
414}
415
416impl<'a, T: Copy + ElementOpApply, Op: ComposableElementOp<T>> StridedView<'a, T, Op> {
418 pub fn transpose_2d(&self) -> Result<StridedView<'a, T, Op::ComposeTranspose>> {
422 if self.dims.len() != 2 {
423 return Err(StridedError::RankMismatch(self.dims.len(), 2));
424 }
425 Ok(from_meta(
426 self.data,
427 Cow::Owned(vec![self.dims[1], self.dims[0]]),
428 Cow::Owned(vec![self.strides[1], self.strides[0]]),
429 self.offset,
430 ))
431 }
432
433 pub fn adjoint_2d(&self) -> Result<StridedView<'a, T, Op::ComposeAdjoint>> {
437 if self.dims.len() != 2 {
438 return Err(StridedError::RankMismatch(self.dims.len(), 2));
439 }
440 Ok(from_meta(
441 self.data,
442 Cow::Owned(vec![self.dims[1], self.dims[0]]),
443 Cow::Owned(vec![self.strides[1], self.strides[0]]),
444 self.offset,
445 ))
446 }
447
448 pub fn conj(&self) -> StridedView<'a, T, Op::ComposeConj> {
452 StridedView {
453 ptr: self.ptr,
454 data: self.data,
455 dims: self.dims.clone(),
456 strides: self.strides.clone(),
457 offset: self.offset,
458 _op: PhantomData,
459 }
460 }
461}
462
463impl<'a, T: Copy, Op: ElementOp<T>> StridedView<'a, T, Op> {
465 pub fn get(&self, indices: &[usize]) -> T {
467 assert_eq!(indices.len(), self.dims.len(), "wrong number of indices");
468 let mut idx = 0isize;
469 for (i, &index) in indices.iter().enumerate() {
470 assert!(
471 index < self.dims[i],
472 "index {} out of bounds for dim {}",
473 index,
474 self.dims[i]
475 );
476 idx += index as isize * self.strides[i];
477 }
478 Op::apply(unsafe { *self.ptr.offset(idx) })
479 }
480
481 #[inline]
486 pub unsafe fn get_unchecked(&self, indices: &[usize]) -> T {
487 let mut idx = 0isize;
488 for (i, &index) in indices.iter().enumerate() {
489 idx += index as isize * self.strides[i];
490 }
491 Op::apply(*self.ptr.offset(idx))
492 }
493}
494
495pub struct StridedViewMut<'a, T> {
504 ptr: *mut T,
505 data: &'a mut [T],
506 dims: Cow<'a, [usize]>,
507 strides: Cow<'a, [isize]>,
508 offset: isize,
509}
510
511unsafe impl<T: Send> Send for StridedViewMut<'_, T> {}
512
513impl<T: std::fmt::Debug> std::fmt::Debug for StridedViewMut<'_, T> {
514 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
515 f.debug_struct("StridedViewMut")
516 .field("dims", &self.dims)
517 .field("strides", &self.strides)
518 .field("offset", &self.offset)
519 .finish()
520 }
521}
522
523impl<'a, T> StridedViewMut<'a, T> {
524 #[inline]
526 fn from_meta(
527 data: &'a mut [T],
528 dims: Cow<'a, [usize]>,
529 strides: Cow<'a, [isize]>,
530 offset: isize,
531 ) -> Self {
532 let ptr = if empty_layout(&dims) {
533 empty_mut_ptr()
534 } else {
535 unsafe { data.as_mut_ptr().offset(offset) }
536 };
537 Self {
538 ptr,
539 data,
540 dims,
541 strides,
542 offset,
543 }
544 }
545
546 pub fn new(
548 data: &'a mut [T],
549 dims: &'a [usize],
550 strides: &'a [isize],
551 offset: isize,
552 ) -> Result<Self> {
553 validate_bounds(data.len(), dims, strides, offset)?;
554 Ok(Self::from_meta(
555 data,
556 Cow::Borrowed(dims),
557 Cow::Borrowed(strides),
558 offset,
559 ))
560 }
561
562 pub unsafe fn new_unchecked(
567 data: &'a mut [T],
568 dims: &'a [usize],
569 strides: &'a [isize],
570 offset: isize,
571 ) -> Self {
572 Self::from_meta(data, Cow::Borrowed(dims), Cow::Borrowed(strides), offset)
573 }
574
575 #[inline]
577 pub fn dims(&self) -> &[usize] {
578 &self.dims
579 }
580
581 #[inline]
583 pub fn strides(&self) -> &[isize] {
584 &self.strides
585 }
586
587 #[inline]
589 pub fn offset(&self) -> isize {
590 self.offset
591 }
592
593 #[inline]
595 pub fn ndim(&self) -> usize {
596 self.dims.len()
597 }
598
599 #[inline]
601 pub fn len(&self) -> usize {
602 self.dims.iter().product()
603 }
604
605 #[inline]
607 pub fn is_empty(&self) -> bool {
608 self.dims.iter().any(|&d| d == 0)
609 }
610
611 #[inline]
613 pub fn ptr(&self) -> *const T {
614 self.ptr as *const T
615 }
616
617 #[inline]
619 pub fn as_mut_ptr(&self) -> *mut T {
620 self.ptr
621 }
622
623 #[inline]
625 pub fn data(&self) -> &[T] {
626 &self.data
627 }
628
629 #[inline]
631 pub fn data_mut(&mut self) -> &mut [T] {
632 &mut self.data
633 }
634
635 pub fn permute(self, perm: &[usize]) -> Result<StridedViewMut<'a, T>> {
640 let rank = self.dims.len();
641 if perm.len() != rank {
642 return Err(StridedError::RankMismatch(perm.len(), rank));
643 }
644 let mut seen = vec![false; rank];
645 for &p in perm {
646 if p >= rank {
647 return Err(StridedError::InvalidAxis { axis: p, rank });
648 }
649 if seen[p] {
650 return Err(StridedError::InvalidAxis { axis: p, rank });
651 }
652 seen[p] = true;
653 }
654 let new_dims: Vec<usize> = perm.iter().map(|&p| self.dims[p]).collect();
655 let new_strides: Vec<isize> = perm.iter().map(|&p| self.strides[p]).collect();
656 Ok(Self::from_meta(
657 self.data,
658 Cow::Owned(new_dims),
659 Cow::Owned(new_strides),
660 self.offset,
661 ))
662 }
663
664 pub fn as_view(&self) -> StridedView<'_, T, Identity> {
669 StridedView {
670 ptr: self.ptr as *const T,
671 data: unsafe { std::slice::from_raw_parts(self.data.as_ptr(), self.data.len()) },
672 dims: Cow::Borrowed(self.dims.as_ref()),
673 strides: Cow::Borrowed(self.strides.as_ref()),
674 offset: self.offset,
675 _op: PhantomData,
676 }
677 }
678}
679
680impl<'a, T: Copy> StridedViewMut<'a, T> {
681 pub fn get(&self, indices: &[usize]) -> T {
683 assert_eq!(indices.len(), self.dims.len());
684 let mut idx = 0isize;
685 for (i, &index) in indices.iter().enumerate() {
686 assert!(index < self.dims[i]);
687 idx += index as isize * self.strides[i];
688 }
689 unsafe { *self.ptr.offset(idx) }
690 }
691
692 pub fn set(&mut self, indices: &[usize], value: T) {
694 assert_eq!(indices.len(), self.dims.len());
695 let mut idx = 0isize;
696 for (i, &index) in indices.iter().enumerate() {
697 assert!(index < self.dims[i]);
698 idx += index as isize * self.strides[i];
699 }
700 unsafe {
701 *self.ptr.offset(idx) = value;
702 }
703 }
704}
705
706pub struct StridedArray<T> {
714 data: Vec<T>,
715 dims: Vec<usize>,
716 strides: Vec<isize>,
717 offset: isize,
718}
719
720impl<T: std::fmt::Debug> std::fmt::Debug for StridedArray<T> {
721 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
722 f.debug_struct("StridedArray")
723 .field("dims", &self.dims)
724 .field("strides", &self.strides)
725 .field("offset", &self.offset)
726 .finish()
727 }
728}
729
730impl<T: Clone> Clone for StridedArray<T> {
731 fn clone(&self) -> Self {
732 Self {
733 data: self.data.clone(),
734 dims: self.dims.clone(),
735 strides: self.strides.clone(),
736 offset: self.offset,
737 }
738 }
739}
740
741impl<T: Clone + Default> StridedArray<T> {
742 pub fn col_major(dims: &[usize]) -> Self {
744 let total: usize = dims.iter().product();
745 let data = vec![T::default(); total];
746 let strides = col_major_strides(dims);
747 Self {
748 data,
749 dims: dims.to_vec(),
750 strides,
751 offset: 0,
752 }
753 }
754
755 pub fn row_major(dims: &[usize]) -> Self {
757 let total: usize = dims.iter().product();
758 let data = vec![T::default(); total];
759 let strides = row_major_strides(dims);
760 Self {
761 data,
762 dims: dims.to_vec(),
763 strides,
764 offset: 0,
765 }
766 }
767
768 pub fn from_fn_col_major(dims: &[usize], mut f: impl FnMut(&[usize]) -> T) -> Self {
772 let total: usize = dims.iter().product();
773 let strides = col_major_strides(dims);
774 let rank = dims.len();
775 let mut data = Vec::with_capacity(total);
776 let mut idx = vec![0usize; rank];
777 for _ in 0..total {
778 data.push(f(&idx));
779 for d in 0..rank {
780 idx[d] += 1;
781 if idx[d] < dims[d] {
782 break;
783 }
784 idx[d] = 0;
785 }
786 }
787 Self {
788 data,
789 dims: dims.to_vec(),
790 strides,
791 offset: 0,
792 }
793 }
794
795 pub fn from_fn_row_major(dims: &[usize], mut f: impl FnMut(&[usize]) -> T) -> Self {
799 let total: usize = dims.iter().product();
800 let strides = row_major_strides(dims);
801 let rank = dims.len();
802 let mut data = Vec::with_capacity(total);
803 let mut idx = vec![0usize; rank];
804 for _ in 0..total {
805 data.push(f(&idx));
806 for d in (0..rank).rev() {
807 idx[d] += 1;
808 if idx[d] < dims[d] {
809 break;
810 }
811 idx[d] = 0;
812 }
813 }
814 Self {
815 data,
816 dims: dims.to_vec(),
817 strides,
818 offset: 0,
819 }
820 }
821}
822
823impl<T> StridedArray<T> {
824 pub fn from_parts(
826 data: Vec<T>,
827 dims: &[usize],
828 strides: &[isize],
829 offset: isize,
830 ) -> Result<Self> {
831 validate_bounds(data.len(), dims, strides, offset)?;
832 Ok(Self {
833 data,
834 dims: dims.to_vec(),
835 strides: strides.to_vec(),
836 offset,
837 })
838 }
839
840 #[inline]
842 pub fn dims(&self) -> &[usize] {
843 &self.dims
844 }
845
846 #[inline]
848 pub fn strides(&self) -> &[isize] {
849 &self.strides
850 }
851
852 #[inline]
854 pub fn ndim(&self) -> usize {
855 self.dims.len()
856 }
857
858 #[inline]
860 pub fn len(&self) -> usize {
861 self.dims.iter().product()
862 }
863
864 #[inline]
866 pub fn is_empty(&self) -> bool {
867 self.dims.iter().any(|&d| d == 0)
868 }
869
870 #[inline]
872 pub fn data(&self) -> &[T] {
873 &self.data
874 }
875
876 #[inline]
878 pub fn data_mut(&mut self) -> &mut [T] {
879 &mut self.data
880 }
881
882 pub fn view(&self) -> StridedView<'_, T> {
884 let ptr = if self.is_empty() {
885 empty_const_ptr()
886 } else {
887 unsafe { self.data.as_ptr().offset(self.offset) }
888 };
889 StridedView {
890 ptr,
891 data: &self.data,
892 dims: Cow::Borrowed(&self.dims),
893 strides: Cow::Borrowed(&self.strides),
894 offset: self.offset,
895 _op: PhantomData,
896 }
897 }
898
899 pub fn view_mut(&mut self) -> StridedViewMut<'_, T> {
901 let ptr = if self.is_empty() {
902 empty_mut_ptr()
903 } else {
904 unsafe { self.data.as_mut_ptr().offset(self.offset) }
905 };
906 StridedViewMut {
907 ptr,
908 data: &mut self.data,
909 dims: Cow::Borrowed(&self.dims),
910 strides: Cow::Borrowed(&self.strides),
911 offset: self.offset,
912 }
913 }
914
915 pub fn permuted(self, perm: &[usize]) -> Result<Self> {
920 let rank = self.dims.len();
921 if perm.len() != rank {
922 return Err(StridedError::RankMismatch(perm.len(), rank));
923 }
924 let mut seen = vec![false; rank];
925 for &p in perm {
926 if p >= rank {
927 return Err(StridedError::InvalidAxis { axis: p, rank });
928 }
929 if seen[p] {
930 return Err(StridedError::InvalidAxis { axis: p, rank });
931 }
932 seen[p] = true;
933 }
934 let new_dims: Vec<usize> = perm.iter().map(|&p| self.dims[p]).collect();
935 let new_strides: Vec<isize> = perm.iter().map(|&p| self.strides[p]).collect();
936 Ok(Self {
937 data: self.data,
938 dims: new_dims,
939 strides: new_strides,
940 offset: self.offset,
941 })
942 }
943
944 pub fn into_data(self) -> Vec<T> {
946 self.data
947 }
948
949 pub fn iter(&self) -> std::slice::Iter<'_, T> {
951 self.data.iter()
952 }
953
954 pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
956 self.data.iter_mut()
957 }
958}
959
960impl<T: Default> StridedArray<T> {
961 pub fn col_major_from_buffer(mut buf: Vec<T>, dims: &[usize]) -> Self {
966 let total: usize = dims.iter().product();
967 if buf.len() >= total {
968 buf.truncate(total);
969 } else {
970 buf.resize_with(total, T::default);
971 }
972 for v in buf.iter_mut() {
974 *v = T::default();
975 }
976 let strides = col_major_strides(dims);
977 Self {
978 data: buf,
979 dims: dims.to_vec(),
980 strides,
981 offset: 0,
982 }
983 }
984}
985
986impl<T: Copy> StridedArray<T> {
987 pub unsafe fn col_major_uninit(dims: &[usize]) -> Self {
992 let total: usize = dims.iter().product();
993 let mut data = Vec::with_capacity(total);
994 data.set_len(total);
995 let strides = col_major_strides(dims);
996 Self {
997 data,
998 dims: dims.to_vec(),
999 strides,
1000 offset: 0,
1001 }
1002 }
1003
1004 pub unsafe fn col_major_from_buffer_uninit(mut buf: Vec<T>, dims: &[usize]) -> Self {
1009 let total: usize = dims.iter().product();
1010 if buf.capacity() < total {
1011 buf.reserve(total - buf.len());
1012 }
1013 buf.set_len(total);
1014 let strides = col_major_strides(dims);
1015 Self {
1016 data: buf,
1017 dims: dims.to_vec(),
1018 strides,
1019 offset: 0,
1020 }
1021 }
1022}
1023
1024impl<T: Copy> StridedArray<T> {
1025 pub fn get(&self, indices: &[usize]) -> T {
1027 self.view().get(indices)
1028 }
1029
1030 pub fn set(&mut self, indices: &[usize], value: T) {
1032 assert_eq!(indices.len(), self.dims.len());
1033 let mut idx = self.offset;
1034 for (i, &index) in indices.iter().enumerate() {
1035 assert!(index < self.dims[i]);
1036 idx += index as isize * self.strides[i];
1037 }
1038 self.data[idx as usize] = value;
1039 }
1040}
1041
1042impl<T: Copy> Index<&[usize]> for StridedArray<T> {
1043 type Output = T;
1044
1045 fn index(&self, indices: &[usize]) -> &T {
1046 let mut idx = self.offset;
1047 for (i, &index) in indices.iter().enumerate() {
1048 assert!(index < self.dims[i]);
1049 idx += index as isize * self.strides[i];
1050 }
1051 &self.data[idx as usize]
1052 }
1053}
1054
1055impl<T: Copy> IndexMut<&[usize]> for StridedArray<T> {
1056 fn index_mut(&mut self, indices: &[usize]) -> &mut T {
1057 let mut idx = self.offset;
1058 for (i, &index) in indices.iter().enumerate() {
1059 assert!(index < self.dims[i]);
1060 idx += index as isize * self.strides[i];
1061 }
1062 &mut self.data[idx as usize]
1063 }
1064}
1065
1066#[cfg(test)]
1071mod tests {
1072 use super::*;
1073
1074 #[test]
1075 fn empty_views_use_dangling_base_pointers_for_extreme_offsets() {
1076 let dims = [0usize];
1077 let strides = [1isize];
1078 let data: [f64; 0] = [];
1079 let view = StridedView::<f64>::new(&data, &dims, &strides, isize::MAX).unwrap();
1080 assert_eq!(view.ptr(), empty_const_ptr());
1081
1082 let mut data: [f64; 0] = [];
1083 let view = StridedViewMut::new(&mut data, &dims, &strides, isize::MAX).unwrap();
1084 assert_eq!(view.ptr(), empty_const_ptr());
1085 assert_eq!(view.as_mut_ptr(), empty_mut_ptr());
1086
1087 let array =
1088 StridedArray::<f64>::from_parts(Vec::new(), &dims, &strides, isize::MAX).unwrap();
1089 assert_eq!(array.view().ptr(), empty_const_ptr());
1090
1091 let mut array =
1092 StridedArray::<f64>::from_parts(Vec::new(), &dims, &strides, isize::MAX).unwrap();
1093 let view = array.view_mut();
1094 assert_eq!(view.ptr(), empty_const_ptr());
1095 assert_eq!(view.as_mut_ptr(), empty_mut_ptr());
1096 }
1097 use num_complex::Complex64;
1098
1099 #[test]
1100 fn test_col_major_strides() {
1101 assert_eq!(col_major_strides(&[3, 4]), vec![1, 3]);
1102 assert_eq!(col_major_strides(&[2, 3, 4]), vec![1, 2, 6]);
1103 }
1104
1105 #[test]
1106 fn test_row_major_strides() {
1107 assert_eq!(row_major_strides(&[3, 4]), vec![4, 1]);
1108 assert_eq!(row_major_strides(&[2, 3, 4]), vec![12, 4, 1]);
1109 }
1110
1111 #[test]
1112 fn test_strided_view_new() {
1113 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
1114 let view = StridedView::<f64>::new(&data, &[2, 3], &[3, 1], 0).unwrap();
1115 assert_eq!(view.ndim(), 2);
1116 assert_eq!(view.dims(), &[2, 3]);
1117 assert_eq!(view.strides(), &[3, 1]);
1118 assert_eq!(view.len(), 6);
1119 }
1120
1121 #[test]
1122 fn test_strided_view_get() {
1123 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
1124 let view = StridedView::<f64>::new(&data, &[2, 3], &[3, 1], 0).unwrap();
1125 assert_eq!(view.get(&[0, 0]), 1.0);
1126 assert_eq!(view.get(&[0, 1]), 2.0);
1127 assert_eq!(view.get(&[0, 2]), 3.0);
1128 assert_eq!(view.get(&[1, 0]), 4.0);
1129 assert_eq!(view.get(&[1, 2]), 6.0);
1130 }
1131
1132 #[test]
1133 fn test_strided_view_col_major() {
1134 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
1136 let view = StridedView::<f64>::new(&data, &[2, 3], &[1, 2], 0).unwrap();
1137 assert_eq!(view.get(&[0, 0]), 1.0); assert_eq!(view.get(&[1, 0]), 2.0); assert_eq!(view.get(&[0, 1]), 3.0); assert_eq!(view.get(&[1, 1]), 4.0); assert_eq!(view.get(&[0, 2]), 5.0); assert_eq!(view.get(&[1, 2]), 6.0); }
1144
1145 #[test]
1146 fn test_strided_view_permute() {
1147 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
1148 let view = StridedView::<f64>::new(&data, &[2, 3], &[3, 1], 0).unwrap();
1149 let perm = view.permute(&[1, 0]).unwrap();
1150 assert_eq!(perm.dims(), &[3, 2]);
1151 assert_eq!(perm.strides(), &[1, 3]);
1152 assert_eq!(perm.get(&[0, 0]), 1.0);
1153 assert_eq!(perm.get(&[1, 0]), 2.0);
1154 assert_eq!(perm.get(&[0, 1]), 4.0);
1155 }
1156
1157 #[test]
1158 fn test_strided_view_transpose_2d() {
1159 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
1160 let view = StridedView::<f64>::new(&data, &[2, 3], &[3, 1], 0).unwrap();
1161 let t = view.transpose_2d().unwrap();
1162 assert_eq!(t.dims(), &[3, 2]);
1163 assert_eq!(t.get(&[0, 0]), 1.0);
1164 assert_eq!(t.get(&[1, 0]), 2.0);
1165 assert_eq!(t.get(&[0, 1]), 4.0);
1166 }
1167
1168 #[test]
1169 fn test_strided_view_conj() {
1170 let data = vec![Complex64::new(1.0, 2.0), Complex64::new(3.0, 4.0)];
1171 let view = StridedView::<Complex64>::new(&data, &[2], &[1], 0).unwrap();
1172 let c = view.conj();
1173 assert_eq!(c.get(&[0]), Complex64::new(1.0, -2.0));
1174 assert_eq!(c.get(&[1]), Complex64::new(3.0, -4.0));
1175 }
1176
1177 #[test]
1178 fn test_strided_view_adjoint_2d() {
1179 let data = vec![
1180 Complex64::new(1.0, 2.0),
1181 Complex64::new(3.0, 4.0),
1182 Complex64::new(5.0, 6.0),
1183 Complex64::new(7.0, 8.0),
1184 ];
1185 let view = StridedView::<Complex64>::new(&data, &[2, 2], &[2, 1], 0).unwrap();
1187 let adj = view.adjoint_2d().unwrap();
1188 assert_eq!(adj.dims(), &[2, 2]);
1189 assert_eq!(adj.get(&[0, 0]), Complex64::new(1.0, -2.0));
1191 assert_eq!(adj.get(&[1, 0]), Complex64::new(3.0, -4.0));
1192 assert_eq!(adj.get(&[0, 1]), Complex64::new(5.0, -6.0));
1193 }
1194
1195 #[test]
1196 fn test_strided_view_broadcast() {
1197 let data = vec![1.0, 2.0, 3.0];
1198 let view = StridedView::<f64>::new(&data, &[1, 3], &[3, 1], 0).unwrap();
1199 let broad = view.broadcast(&[4, 3]).unwrap();
1200 assert_eq!(broad.dims(), &[4, 3]);
1201 for i in 0..4 {
1202 assert_eq!(broad.get(&[i, 0]), 1.0);
1203 assert_eq!(broad.get(&[i, 1]), 2.0);
1204 assert_eq!(broad.get(&[i, 2]), 3.0);
1205 }
1206 }
1207
1208 #[test]
1209 fn test_strided_view_mut() {
1210 let mut data = vec![0.0; 6];
1211 {
1212 let mut view = StridedViewMut::<f64>::new(&mut data, &[2, 3], &[3, 1], 0).unwrap();
1213 view.set(&[0, 0], 1.0);
1214 view.set(&[1, 2], 6.0);
1215 }
1216 assert_eq!(data[0], 1.0);
1217 assert_eq!(data[5], 6.0);
1218 }
1219
1220 #[test]
1221 fn test_strided_view_mut_as_view() {
1222 let mut data = vec![1.0, 2.0, 3.0];
1223 let vm = StridedViewMut::<f64>::new(&mut data, &[3], &[1], 0).unwrap();
1224 let v = vm.as_view();
1225 assert_eq!(v.get(&[0]), 1.0);
1226 assert_eq!(v.get(&[2]), 3.0);
1227 }
1228
1229 #[test]
1230 fn test_strided_tensor_col_major() {
1231 let t = StridedArray::<f64>::from_fn_col_major(&[2, 3], |idx| (idx[0] * 3 + idx[1]) as f64);
1232 assert_eq!(t.dims(), &[2, 3]);
1233 assert_eq!(t.strides(), &[1, 2]); assert_eq!(t.get(&[0, 0]), 0.0);
1235 assert_eq!(t.get(&[1, 0]), 3.0);
1236 assert_eq!(t.get(&[0, 1]), 1.0);
1237 assert_eq!(t.get(&[1, 2]), 5.0);
1238 }
1239
1240 #[test]
1241 fn test_strided_tensor_row_major() {
1242 let t = StridedArray::<f64>::from_fn_row_major(&[2, 3], |idx| (idx[0] * 3 + idx[1]) as f64);
1243 assert_eq!(t.dims(), &[2, 3]);
1244 assert_eq!(t.strides(), &[3, 1]); assert_eq!(t.get(&[0, 0]), 0.0);
1246 assert_eq!(t.get(&[0, 1]), 1.0);
1247 assert_eq!(t.get(&[1, 0]), 3.0);
1248 assert_eq!(t.get(&[1, 2]), 5.0);
1249 }
1250
1251 #[test]
1252 fn test_strided_tensor_view() {
1253 let t =
1254 StridedArray::<f64>::from_fn_col_major(&[2, 3], |idx| (idx[0] * 10 + idx[1]) as f64);
1255 let v = t.view();
1256 assert_eq!(v.get(&[0, 0]), 0.0);
1257 assert_eq!(v.get(&[1, 0]), 10.0);
1258 assert_eq!(v.get(&[0, 2]), 2.0);
1259 }
1260
1261 #[test]
1262 fn test_strided_tensor_view_mut() {
1263 let mut t = StridedArray::<f64>::col_major(&[2, 3]);
1264 {
1265 let mut vm = t.view_mut();
1266 vm.set(&[1, 2], 42.0);
1267 }
1268 assert_eq!(t.get(&[1, 2]), 42.0);
1269 }
1270
1271 #[test]
1272 fn test_strided_tensor_index() {
1273 let t =
1274 StridedArray::<f64>::from_fn_row_major(&[3, 4], |idx| (idx[0] * 10 + idx[1]) as f64);
1275 assert_eq!(t[&[0usize, 0] as &[usize]], 0.0);
1276 assert_eq!(t[&[2usize, 3] as &[usize]], 23.0);
1277 }
1278
1279 #[test]
1280 fn test_strided_tensor_index_mut() {
1281 let mut t = StridedArray::<f64>::row_major(&[2, 3]);
1282 t[&[1usize, 2] as &[usize]] = 99.0;
1283 assert_eq!(t.get(&[1, 2]), 99.0);
1284 }
1285
1286 #[test]
1287 fn test_validate_bounds_ok() {
1288 assert!(validate_bounds(6, &[2, 3], &[3, 1], 0).is_ok());
1289 assert!(validate_bounds(6, &[2, 3], &[1, 2], 0).is_ok());
1290 }
1291
1292 #[test]
1293 fn test_validate_bounds_out_of_range() {
1294 assert!(validate_bounds(5, &[2, 3], &[3, 1], 0).is_err());
1295 }
1296
1297 #[test]
1298 fn test_validate_bounds_empty() {
1299 assert!(validate_bounds(0, &[0, 3], &[3, 1], 0).is_ok());
1300 }
1301
1302 #[test]
1303 fn test_validate_bounds_with_offset() {
1304 assert!(validate_bounds(7, &[2, 3], &[3, 1], 1).is_ok());
1305 assert!(validate_bounds(6, &[2, 3], &[3, 1], 1).is_err());
1306 }
1307
1308 #[test]
1309 fn test_strided_tensor_3d() {
1310 let t = StridedArray::<f64>::from_fn_col_major(&[2, 3, 4], |idx| {
1311 (idx[0] * 100 + idx[1] * 10 + idx[2]) as f64
1312 });
1313 assert_eq!(t.ndim(), 3);
1314 assert_eq!(t.strides(), &[1, 2, 6]); assert_eq!(t.get(&[0, 0, 0]), 0.0);
1316 assert_eq!(t.get(&[1, 0, 0]), 100.0);
1317 assert_eq!(t.get(&[0, 1, 0]), 10.0);
1318 assert_eq!(t.get(&[0, 0, 1]), 1.0);
1319 assert_eq!(t.get(&[1, 2, 3]), 123.0);
1320 }
1321
1322 #[test]
1323 fn test_diagonal_view_2d() {
1324 let data: Vec<f64> = (0..9).map(|x| x as f64).collect();
1327 let view = StridedView::<f64>::new(&data, &[3, 3], &[3, 1], 0).unwrap();
1328 let diag = view.diagonal_view(&[(0, 1)]).unwrap();
1329 assert_eq!(diag.dims(), &[3]);
1330 assert_eq!(diag.strides(), &[4]);
1331 assert_eq!(diag.get(&[0]), 0.0); assert_eq!(diag.get(&[1]), 4.0); assert_eq!(diag.get(&[2]), 8.0); }
1335
1336 #[test]
1337 fn test_diagonal_view_3d_adjacent() {
1338 let data: Vec<f64> = (0..12).map(|x| x as f64).collect();
1341 let view = StridedView::<f64>::new(&data, &[2, 2, 3], &[6, 3, 1], 0).unwrap();
1342 let diag = view.diagonal_view(&[(0, 1)]).unwrap();
1343 assert_eq!(diag.dims(), &[2, 3]);
1344 assert_eq!(diag.strides(), &[9, 1]);
1345 assert_eq!(diag.get(&[0, 0]), 0.0);
1346 assert_eq!(diag.get(&[0, 2]), 2.0);
1347 assert_eq!(diag.get(&[1, 0]), 9.0);
1348 }
1349
1350 #[test]
1351 fn test_diagonal_view_3d_non_adjacent() {
1352 let data: Vec<f64> = (0..12).map(|x| x as f64).collect();
1355 let view = StridedView::<f64>::new(&data, &[2, 3, 2], &[6, 2, 1], 0).unwrap();
1356 let diag = view.diagonal_view(&[(0, 2)]).unwrap();
1357 assert_eq!(diag.dims(), &[2, 3]);
1358 assert_eq!(diag.strides(), &[7, 2]);
1359 assert_eq!(diag.get(&[0, 0]), 0.0);
1360 assert_eq!(diag.get(&[0, 1]), 2.0);
1361 assert_eq!(diag.get(&[1, 0]), 7.0);
1362 assert_eq!(diag.get(&[1, 2]), 11.0);
1363 }
1364
1365 #[test]
1366 fn test_diagonal_view_two_pairs() {
1367 let data: Vec<f64> = (0..36).map(|x| x as f64).collect();
1369 let view = StridedView::<f64>::new(&data, &[2, 3, 2, 3], &[18, 6, 3, 1], 0).unwrap();
1370 let diag = view.diagonal_view(&[(0, 2), (1, 3)]).unwrap();
1371 assert_eq!(diag.dims(), &[2, 3]);
1372 assert_eq!(diag.strides(), &[21, 7]);
1373 assert_eq!(diag.get(&[0, 0]), 0.0);
1374 assert_eq!(diag.get(&[1, 1]), 28.0);
1375 }
1376
1377 #[test]
1378 fn test_custom_type_without_element_op_apply() {
1379 #[derive(Debug, Clone, Copy, PartialEq)]
1382 struct MyScalar(f64);
1383
1384 impl Default for MyScalar {
1385 fn default() -> Self {
1386 MyScalar(0.0)
1387 }
1388 }
1389
1390 let data = vec![MyScalar(1.0), MyScalar(2.0), MyScalar(3.0), MyScalar(4.0)];
1392 let arr = StridedArray::from_parts(data, &[2, 2], &[2, 1], 0).unwrap();
1393
1394 assert_eq!(arr.get(&[0, 0]), MyScalar(1.0));
1396 assert_eq!(arr.get(&[1, 0]), MyScalar(3.0));
1397
1398 let view: StridedView<MyScalar> = arr.view();
1400 assert_eq!(view.get(&[0, 1]), MyScalar(2.0));
1401
1402 let perm = view.permute(&[1, 0]).unwrap();
1404 assert_eq!(perm.get(&[0, 0]), MyScalar(1.0));
1405 assert_eq!(perm.get(&[0, 1]), MyScalar(3.0)); }
1407}