1use std::ops::{Add, Sub};
8
9use aligned_vec::{AVec, CACHELINE_ALIGN, ConstAlign};
10use empty_axis::AxisPosition;
11use iterators::{
12 ArrayDefaultIteratorByRef, ArrayDefaultIteratorByValue, ArrayDefaultIteratorMut,
13 ArrayDiagIteratorByRef, ArrayDiagIteratorByValue, ArrayDiagIteratorMut, ColIterator,
14 ColIteratorMut, RowIterator, RowIteratorMut,
15};
16use itertools::izip;
17use num::{One, Zero, traits::MulAdd};
18use operators::{
19 addition::ArrayAddition, cast::ArrayCast, cmp_wise_division::CmpWiseDivision,
20 cmp_wise_product::CmpWiseProduct, coerce::CoerceArray, mul_add::MulAddImpl, negation::ArrayNeg,
21 reverse_axis::ReverseAxis, scalar_mult::ArrayScalarMult, subtraction::ArraySubtraction,
22 transpose::ArrayTranspose, unary_op::ArrayUnaryOperator,
23};
24use typenum::{Const, NonZero, PInt, ToUInt, U, Unsigned};
25
26use crate::base_types::{c32, c64};
27
28use crate::dense::array::iterators::{MultisliceIterator, MultisliceIteratorMut};
29use crate::{
30 ArrayFromContainerType, Linspace, MutableArrayImpl, RowMajorArrayFromContainerType,
31 ScalarAsArray,
32};
33
34use paste::paste;
35use rand::{Rng, SeedableRng};
36use rand_chacha::ChaCha8Rng;
37use rand_distr::{Distribution, StandardNormal, StandardUniform};
38use reference::{ArrayRef, ArrayRefMut};
39use slice::ArraySlice;
40use subview::ArraySubView;
41
42use crate::{
43 AsMatrixApply, AsMultiIndex, EvaluateArray, EvaluateRowMajorArray, Gemm, IsGreaterByOne,
44 IsGreaterZero, IsSmallerThan, Max, MemoryLayout, NumberDifference, NumberType, RandScalar,
45 RandomAccessByValue, RlstError, RlstResult, RlstScalar, SubtractEqual, TransMode,
46 dense::{
47 array::multislice::Multislice,
48 base_array::BaseArray,
49 data_container::{
50 AlignedVectorContainer, SliceContainer, SliceContainerMut, VectorContainer,
51 },
52 layout::check_multi_index_in_bounds,
53 strided_base_array::{StridedBaseArray, required_storage_len},
54 },
55 traits::{
56 accessors::{
57 RandomAccessByRef, RandomAccessMut, RawAccess, RawAccessMut,
58 UnsafeDisjointRandom1DAccessMut, UnsafeRandom1DAccessByRef,
59 UnsafeRandom1DAccessByValue, UnsafeRandomAccessByRef, UnsafeRandomAccessByValue,
60 UnsafeRandomAccessMut,
61 },
62 base_operations::{BaseItem, ResizeInPlace, Shape, Stride},
63 data_container::ContainerType,
64 },
65};
66
67use super::{data_container::ArrayContainer, layout::row_major_stride_from_shape};
68
69pub mod empty_axis;
70pub mod iterators;
71pub mod mult_into;
72pub mod operations;
73pub mod operators;
74pub mod flattened;
76pub mod multislice;
77pub mod reference;
78pub mod shared_array;
79pub mod slice;
80pub mod subview;
81pub mod zero_dim;
82
83pub use zero_dim::ZeroDimArray;
84
85pub type DynArray<Item, const NDIM: usize> = Array<BaseArray<VectorContainer<Item>, NDIM>, NDIM>;
91
92pub type AlignedDynArray<Item, const NDIM: usize, const ALIGNMENT: usize = CACHELINE_ALIGN> =
94 Array<BaseArray<AlignedVectorContainer<Item, ALIGNMENT>, NDIM>, NDIM>;
95
96pub type StridedDynArray<Item, const NDIM: usize> =
100 Array<StridedBaseArray<VectorContainer<Item>, NDIM>, NDIM>;
101
102pub type StaticArray<Item, const NDIM: usize, const N: usize> =
107 Array<BaseArray<ArrayContainer<Item, N>, NDIM>, NDIM>;
108
109pub type SliceArray<'a, Item, const NDIM: usize> =
111 Array<BaseArray<SliceContainer<'a, Item>, NDIM>, NDIM>;
112
113pub type StridedSliceArray<'a, Item, const NDIM: usize> =
115 Array<StridedBaseArray<SliceContainer<'a, Item>, NDIM>, NDIM>;
116
117pub type SliceArrayMut<'a, Item, const NDIM: usize> =
119 Array<BaseArray<SliceContainerMut<'a, Item>, NDIM>, NDIM>;
120
121pub type StridedSliceArrayMut<'a, Item, const NDIM: usize> =
123 Array<StridedBaseArray<SliceContainerMut<'a, Item>, NDIM>, NDIM>;
124
125pub struct Array<ArrayImpl, const NDIM: usize>(ArrayImpl);
131
132impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM> {
133 pub fn new(arr: ArrayImpl) -> Self {
138 Self(arr)
139 }
140
141 #[inline(always)]
143 pub fn imp(&self) -> &ArrayImpl {
144 &self.0
145 }
146
147 #[inline(always)]
149 pub fn imp_mut(&mut self) -> &mut ArrayImpl {
150 &mut self.0
151 }
152
153 #[inline(always)]
155 pub fn into_imp(self) -> ArrayImpl {
156 self.0
157 }
158
159 #[inline(always)]
164 pub fn r(&self) -> Array<ArrayRef<'_, ArrayImpl, NDIM>, NDIM> {
165 Array::new(ArrayRef::new(self))
166 }
167
168 #[inline(always)]
172 pub fn r_mut(&mut self) -> Array<ArrayRefMut<'_, ArrayImpl, NDIM>, NDIM> {
173 Array::new(ArrayRefMut::new(self))
174 }
175}
176
177impl<ArrayImpl, const NDIM: usize> BaseItem for Array<ArrayImpl, NDIM>
178where
179 ArrayImpl: BaseItem,
180{
181 type Item = ArrayImpl::Item;
182}
183
184impl<ArrayImpl: Shape<NDIM>, const NDIM: usize> Array<ArrayImpl, NDIM> {
185 #[inline(always)]
187 pub fn number_of_elements(&self) -> usize {
188 self.0.shape().iter().product()
189 }
190}
191
192impl<Item: Copy + Default, const NDIM: usize> DynArray<Item, NDIM> {
193 #[inline(always)]
197 pub fn from_shape(shape: [usize; NDIM]) -> Self {
198 let size = shape.iter().product();
199 Self::new(BaseArray::new(VectorContainer::new(size), shape))
200 }
201
202 #[inline(always)]
210 pub fn from_shape_and_vec(shape: [usize; NDIM], data: Vec<Item>) -> Self {
211 assert_eq!(
212 data.len(),
213 shape.iter().product::<usize>(),
214 "Data length does not match the shape: {} != {}",
215 data.len(),
216 shape.iter().product::<usize>()
217 );
218 Self::new(BaseArray::new(VectorContainer::from_vec(data), shape))
219 }
220}
221
222impl<Item: Copy + Default, const NDIM: usize, const ALIGNMENT: usize>
223 AlignedDynArray<Item, NDIM, ALIGNMENT>
224{
225 #[inline(always)]
229 pub fn from_shape(shape: [usize; NDIM]) -> Self {
230 let size = shape.iter().product();
231 Self::new(BaseArray::new(AlignedVectorContainer::new(size), shape))
232 }
233
234 #[inline(always)]
240 pub fn from_shape_and_avec(
241 shape: [usize; NDIM],
242 data: AVec<Item, ConstAlign<ALIGNMENT>>,
243 ) -> Self {
244 assert_eq!(
245 data.len(),
246 shape.iter().product::<usize>(),
247 "Data length does not match the shape: {} != {}",
248 data.len(),
249 shape.iter().product::<usize>()
250 );
251 Self::new(BaseArray::new(
252 AlignedVectorContainer::from_avec(data),
253 shape,
254 ))
255 }
256}
257
258impl<Item: Copy + Default> DynArray<Item, 2> {
259 pub fn from_iter_aij<Iter: Iterator<Item = ([usize; 2], Item)>>(
261 shape: [usize; 2],
262 iter: Iter,
263 ) -> DynArray<Item, 2> {
264 let mut out = DynArray::<Item, 2>::from_shape(shape);
265
266 for (index, item) in iter {
267 out[index] = item;
268 }
269
270 out
271 }
272}
273
274impl<Item: Copy + Default, const ALIGNMENT: usize> AlignedDynArray<Item, 2, ALIGNMENT> {
275 pub fn from_iter_aij<Iter: Iterator<Item = ([usize; 2], Item)>>(
277 shape: [usize; 2],
278 iter: Iter,
279 ) -> AlignedDynArray<Item, 2, ALIGNMENT> {
280 let mut out = AlignedDynArray::<Item, 2, ALIGNMENT>::from_shape(shape);
281
282 for (index, item) in iter {
283 out[index] = item;
284 }
285
286 out
287 }
288}
289
290impl<Item: Copy + Default> From<&[Item]> for DynArray<Item, 1> {
291 fn from(value: &[Item]) -> Self {
292 DynArray::<Item, 1>::from_shape_and_vec([value.len()], value.to_vec())
293 }
294}
295
296impl<Item: Copy + Default, const N: usize> From<[Item; N]> for StaticArray<Item, 1, N> {
297 fn from(value: [Item; N]) -> Self {
298 StaticArray::new(BaseArray::new(value.into(), [N]))
299 }
300}
301
302impl<Item: Copy + Default> From<Vec<Item>> for DynArray<Item, 1> {
303 fn from(value: Vec<Item>) -> Self {
304 DynArray::<Item, 1>::from_shape_and_vec([value.len()], value)
305 }
306}
307
308impl<Item: Copy + Default> From<Vec<Vec<Item>>> for DynArray<Item, 2> {
309 fn from(value: Vec<Vec<Item>>) -> Self {
310 let nrows = value.len();
311 if nrows == 0 {
312 empty_array()
313 } else {
314 let ncols = value.first().unwrap().len();
315 for row in value.iter() {
318 assert_eq!(ncols, row.len(), "All rows must have equal length.");
319 }
320
321 let mut out = DynArray::<Item, 2>::from_shape([nrows, ncols]);
324
325 for (row_index, row) in value.iter().enumerate() {
326 for (col_index, &elem) in row.iter().enumerate() {
327 out[[row_index, col_index]] = elem;
328 }
329 }
330
331 out
332 }
333 }
334}
335
336impl<Item: Copy + Default, const NDIM: usize> StridedDynArray<Item, NDIM> {
337 #[inline(always)]
348 pub fn from_shape_and_stride(shape: [usize; NDIM], stride: [usize; NDIM]) -> Self {
349 let size = required_storage_len(shape, stride);
350 Self::new(StridedBaseArray::new(
351 VectorContainer::new(size),
352 shape,
353 stride,
354 ))
355 }
356}
357
358impl<Item: Copy + Default, const NDIM: usize>
359 Array<StridedBaseArray<VectorContainer<Item>, NDIM>, NDIM>
360{
361 #[inline(always)]
363 pub fn row_major(shape: [usize; NDIM]) -> Self {
364 let size = shape.iter().product();
365 Self::new(StridedBaseArray::new(
366 VectorContainer::new(size),
367 shape,
368 row_major_stride_from_shape(shape),
369 ))
370 }
371}
372
373impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
374where
375 ArrayImpl: Shape<NDIM>,
376{
377 #[inline(always)]
382 pub fn shape(&self) -> [usize; NDIM] {
383 self.0.shape()
384 }
385}
386
387impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
388where
389 ArrayImpl: Shape<NDIM>,
390{
391 #[inline(always)]
397 pub fn len(&self) -> usize {
398 self.0.len()
399 }
400
401 #[inline(always)]
407 pub fn is_empty(&self) -> bool {
408 self.len() == 0
409 }
410}
411
412impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
413where
414 ArrayImpl: UnsafeRandomAccessByValue<NDIM>,
415{
416 #[inline(always)]
424 pub unsafe fn get_value_unchecked(&self, multi_index: [usize; NDIM]) -> ArrayImpl::Item {
425 unsafe { self.0.get_value_unchecked(multi_index) }
426 }
427}
428
429impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
430where
431 ArrayImpl: UnsafeRandomAccessByRef<NDIM>,
432{
433 #[inline(always)]
441 pub unsafe fn get_unchecked(&self, multi_index: [usize; NDIM]) -> &ArrayImpl::Item {
442 unsafe { self.0.get_unchecked(multi_index) }
443 }
444}
445
446impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
447where
448 ArrayImpl: UnsafeRandomAccessMut<NDIM>,
449{
450 #[inline(always)]
458 pub unsafe fn get_unchecked_mut(&mut self, multi_index: [usize; NDIM]) -> &mut ArrayImpl::Item {
459 unsafe { self.0.get_unchecked_mut(multi_index) }
460 }
461}
462
463impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
464where
465 ArrayImpl: RandomAccessByValue<NDIM>,
466{
467 #[inline(always)]
472 pub fn get_value(&self, multi_index: [usize; NDIM]) -> Option<ArrayImpl::Item> {
473 self.0.get_value(multi_index)
474 }
475}
476
477impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
478where
479 ArrayImpl: RandomAccessByRef<NDIM>,
480{
481 #[inline(always)]
486 pub fn get(&self, multi_index: [usize; NDIM]) -> Option<&ArrayImpl::Item> {
487 self.0.get(multi_index)
488 }
489}
490
491impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
492where
493 ArrayImpl: RandomAccessMut<NDIM>,
494{
495 #[inline(always)]
500 pub fn get_mut(&mut self, multi_index: [usize; NDIM]) -> Option<&mut ArrayImpl::Item> {
501 self.0.get_mut(multi_index)
502 }
503}
504
505impl<ArrayImpl, const NDIM: usize> std::ops::Index<[usize; NDIM]> for Array<ArrayImpl, NDIM>
506where
507 ArrayImpl: RandomAccessByRef<NDIM>,
508{
509 type Output = ArrayImpl::Item;
510 #[inline(always)]
511 fn index(&self, index: [usize; NDIM]) -> &Self::Output {
512 self.0.get(index).unwrap()
513 }
514}
515
516impl<ArrayImpl, const NDIM: usize> std::ops::IndexMut<[usize; NDIM]> for Array<ArrayImpl, NDIM>
517where
518 Array<ArrayImpl, NDIM>: std::ops::Index<[usize; NDIM], Output = ArrayImpl::Item>,
519 ArrayImpl: RandomAccessMut<NDIM>,
520{
521 #[inline(always)]
522 fn index_mut(&mut self, index: [usize; NDIM]) -> &mut ArrayImpl::Item {
523 self.0.get_mut(index).unwrap()
524 }
525}
526
527impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
528where
529 ArrayImpl: RawAccess,
530{
531 #[inline(always)]
536 pub fn data(&self) -> Option<&[ArrayImpl::Item]> {
537 self.0.data()
538 }
539}
540
541impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
542where
543 ArrayImpl: RawAccessMut,
544{
545 #[inline(always)]
549 pub fn data_mut(&mut self) -> Option<&mut [ArrayImpl::Item]> {
550 self.0.data_mut()
551 }
552}
553
554impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
555where
556 ArrayImpl: Stride<NDIM>,
557{
558 #[inline(always)]
563 pub fn stride(&self) -> [usize; NDIM] {
564 self.0.stride()
565 }
566}
567
568impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
569where
570 ArrayImpl: Stride<NDIM> + Shape<NDIM>,
571{
572 #[inline(always)]
576 pub fn memory_layout(&self) -> MemoryLayout {
577 self.0.memory_layout()
578 }
579
580 pub fn is_contiguous(&self) -> bool {
584 self.0.is_contiguous()
585 }
586}
587
588impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
589where
590 ArrayImpl: ResizeInPlace<NDIM>,
591{
592 pub fn resize_in_place(&mut self, shape: [usize; NDIM]) {
599 self.0.resize_in_place(shape)
600 }
601}
602
603impl<Item, ArrayImpl, const NDIM: usize> EvaluateArray<Item, NDIM> for Array<ArrayImpl, NDIM>
604where
605 Item: Copy + Default,
606 ArrayImpl: UnsafeRandom1DAccessByValue<Item = Item> + Shape<NDIM> + ContainerType,
607{
608 type OutputImpl =
609 <<ArrayImpl as ContainerType>::Type as ArrayFromContainerType>::OutputImpl<Item, NDIM>;
610
611 fn eval(&self) -> Array<Self::OutputImpl, NDIM> {
612 let mut out = <<ArrayImpl as ContainerType>::Type as ArrayFromContainerType>::new_arr::<
613 Item,
614 NDIM,
615 >(self.shape());
616
617 out.fill_from(self);
618
619 out
620 }
621}
622
623impl<Item, ArrayImpl, const NDIM: usize> EvaluateRowMajorArray<Item, NDIM>
624 for Array<ArrayImpl, NDIM>
625where
626 Item: Copy + Default,
627 ArrayImpl: UnsafeRandom1DAccessByValue<Item = Item> + Shape<NDIM> + ContainerType,
628{
629 type OutputImpl =
630 <<ArrayImpl as ContainerType>::Type as RowMajorArrayFromContainerType>::OutputImpl<
631 Item,
632 NDIM,
633 >;
634
635 fn eval_row_major(&self) -> Array<Self::OutputImpl, NDIM> {
636 let mut out =
637 <<ArrayImpl as ContainerType>::Type as RowMajorArrayFromContainerType>::new_row_major_arr::<
638 Item,
639 NDIM,
640 >(self.shape());
641
642 out.fill_from(self);
643
644 out
645 }
646}
647
648pub fn empty_array<Item, const NDIM: usize>() -> Array<BaseArray<VectorContainer<Item>, NDIM>, NDIM>
653where
654 Item: Copy + Default,
655{
656 let shape = [0; NDIM];
657 let container = VectorContainer::new(0);
658 Array::new(BaseArray::new(container, shape))
659}
660
661impl<'a, Item, const NDIM: usize> SliceArray<'a, Item, NDIM>
662where
663 Item: Copy + Default,
664{
665 pub fn from_shape(slice: &'a [Item], shape: [usize; NDIM]) -> Self {
667 assert_eq!(
668 slice.len(),
669 shape.iter().product::<usize>(),
670 "Slice length does not match the shape: {} != {}",
671 slice.len(),
672 shape.iter().product::<usize>()
673 );
674 Array::new(BaseArray::new(SliceContainer::new(slice), shape))
675 }
676}
677
678impl<'a, Item, const NDIM: usize> SliceArrayMut<'a, Item, NDIM>
679where
680 Item: Copy + Default,
681{
682 pub fn from_shape(slice: &'a mut [Item], shape: [usize; NDIM]) -> Self {
684 assert_eq!(
685 slice.len(),
686 shape.iter().product::<usize>(),
687 "Slice length does not match the shape: {} != {}",
688 slice.len(),
689 shape.iter().product::<usize>()
690 );
691 Array::new(BaseArray::new(SliceContainerMut::new(slice), shape))
692 }
693}
694
695impl<'a, Item, const NDIM: usize> StridedSliceArray<'a, Item, NDIM>
696where
697 Item: Copy + Default,
698{
699 pub fn from_shape_and_stride(
701 slice: &'a [Item],
702 shape: [usize; NDIM],
703 stride: [usize; NDIM],
704 ) -> Self {
705 Array::new(StridedBaseArray::new(
706 SliceContainer::new(slice),
707 shape,
708 stride,
709 ))
710 }
711}
712
713impl<'a, Item, const NDIM: usize> StridedSliceArrayMut<'a, Item, NDIM>
714where
715 Item: Copy + Default,
716{
717 pub fn from_shape_and_stride(
719 slice: &'a mut [Item],
720 shape: [usize; NDIM],
721 stride: [usize; NDIM],
722 ) -> Self {
723 Array::new(StridedBaseArray::new(
724 SliceContainerMut::new(slice),
725 shape,
726 stride,
727 ))
728 }
729}
730
731impl<ArrayImpl: Shape<NDIM>, const NDIM: usize> std::fmt::Debug for Array<ArrayImpl, NDIM> {
732 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
733 let shape = self.shape();
734 write!(f, "Array[").unwrap();
735 for item in shape {
736 write!(f, "{item},").unwrap();
737 }
738 write!(f, "]")
739 }
740}
741
742impl<Item, const NDIM: usize> DynArray<Item, NDIM>
743where
744 Item: Copy + Default,
745{
746 pub fn new_from<ArrayImpl>(arr: &Array<ArrayImpl, NDIM>) -> Self
748 where
749 ArrayImpl: UnsafeRandom1DAccessByValue<Item = Item> + Shape<NDIM>,
750 {
751 let mut output = empty_array::<Item, NDIM>();
752 output.fill_from_resize(arr);
753 output
754 }
755}
756
757impl<Item, const NDIM: usize> StridedDynArray<Item, NDIM>
758where
759 Item: Copy + Default,
760{
761 pub fn new_from<ArrayImpl>(stride: [usize; NDIM], arr: &Array<ArrayImpl, NDIM>) -> Self
763 where
764 ArrayImpl: UnsafeRandom1DAccessByValue<Item = Item> + Shape<NDIM>,
765 {
766 let mut output = StridedDynArray::from_shape_and_stride(arr.shape(), stride);
767 output.fill_from(arr);
768 output
769 }
770
771 pub fn row_major_from<ArrayImpl>(arr: &Array<ArrayImpl, NDIM>) -> Self
773 where
774 ArrayImpl: UnsafeRandom1DAccessByValue<Item = Item> + Shape<NDIM>,
775 {
776 StridedDynArray::new_from(row_major_stride_from_shape(arr.shape()), arr)
777 }
778}
779
780impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
781where
782 ArrayImpl: UnsafeRandom1DAccessByValue + Shape<NDIM>,
783{
784 #[inline(always)]
792 pub fn iter_value(&self) -> ArrayDefaultIteratorByValue<'_, ArrayImpl, NDIM> {
793 ArrayDefaultIteratorByValue::new(self)
794 }
795}
796
797impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
798where
799 ArrayImpl: UnsafeRandom1DAccessByRef + Shape<NDIM>,
800{
801 #[inline(always)]
809 pub fn iter_ref(&self) -> ArrayDefaultIteratorByRef<'_, ArrayImpl, NDIM> {
810 ArrayDefaultIteratorByRef::new(self)
811 }
812}
813
814impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
815where
816 ArrayImpl: UnsafeDisjointRandom1DAccessMut + Shape<NDIM>,
817{
818 #[inline(always)]
826 pub fn iter_mut(&mut self) -> ArrayDefaultIteratorMut<'_, ArrayImpl, NDIM> {
827 ArrayDefaultIteratorMut::new(self)
828 }
829}
830
831impl<Item, ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
832where
833 ArrayImpl: UnsafeRandomAccessByValue<NDIM, Item = Item> + Shape<NDIM>,
834{
835 #[inline(always)]
841 pub fn diag_iter_value(&self) -> ArrayDiagIteratorByValue<'_, ArrayImpl, NDIM> {
842 ArrayDiagIteratorByValue::new(self)
843 }
844}
845
846impl<Item, ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
847where
848 ArrayImpl: UnsafeRandomAccessByRef<NDIM, Item = Item> + Shape<NDIM>,
849{
850 #[inline(always)]
856 pub fn diag_iter_ref(&self) -> ArrayDiagIteratorByRef<'_, ArrayImpl, NDIM> {
857 ArrayDiagIteratorByRef::new(self)
858 }
859}
860
861impl<Item, ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
862where
863 ArrayImpl: UnsafeRandomAccessMut<NDIM, Item = Item> + Shape<NDIM>,
864{
865 #[inline(always)]
871 pub fn diag_iter_mut(&mut self) -> ArrayDiagIteratorMut<'_, ArrayImpl, NDIM> {
872 ArrayDiagIteratorMut::new(self)
873 }
874}
875
876impl<Item, ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
877where
878 ArrayImpl: UnsafeDisjointRandom1DAccessMut<Item = Item> + Shape<NDIM>,
879{
880 #[inline(always)]
886 pub fn fill_from<ArrayImplOther>(&mut self, other: &Array<ArrayImplOther, NDIM>)
887 where
888 ArrayImplOther: UnsafeRandom1DAccessByValue<Item = Item> + Shape<NDIM>,
889 {
890 assert_eq!(self.shape(), other.shape());
891
892 for (item, other_item) in self.iter_mut().zip(other.iter_value()) {
893 *item = other_item;
894 }
895 }
896}
897
898impl<Item, ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
899where
900 Const<NDIM>: ToUInt,
901 <Const<NDIM> as ToUInt>::Output: Unsigned + NonZero,
902 ArrayImpl: UnsafeRandom1DAccessByValue<Item = Item>
903 + UnsafeRandomAccessByValue<NDIM, Item = Item>
904 + Shape<NDIM>,
905{
906 pub fn multislice_iter<const SDIM: usize, const OUTDIM: usize>(
914 &self,
915 axes: [usize; SDIM],
916 ) -> MultisliceIterator<'_, Item, ArrayImpl, NDIM, SDIM, OUTDIM>
917 where
918 Const<SDIM>: ToUInt,
919 Const<OUTDIM>: ToUInt,
920 <Const<SDIM> as ToUInt>::Output: Unsigned + NonZero,
921 <Const<OUTDIM> as ToUInt>::Output: Unsigned + NonZero,
922 NumberType<SDIM>: IsSmallerThan<NDIM>,
923 PInt<U<OUTDIM>>: Add<PInt<U<SDIM>>, Output = PInt<U<NDIM>>>,
924 PInt<U<NDIM>>: Sub<PInt<U<SDIM>>>,
925 {
926 MultisliceIterator::new(self, axes)
927 }
928}
929
930impl<Item, ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
931where
932 Const<NDIM>: ToUInt,
933 <Const<NDIM> as ToUInt>::Output: Unsigned + NonZero,
934 ArrayImpl: UnsafeDisjointRandom1DAccessMut<Item = Item>
935 + UnsafeRandomAccessMut<NDIM, Item = Item>
936 + Shape<NDIM>,
937{
938 pub fn multislice_iter_mut<const SDIM: usize, const OUTDIM: usize>(
946 &mut self,
947 axes: [usize; SDIM],
948 ) -> MultisliceIteratorMut<'_, Item, ArrayImpl, NDIM, SDIM, OUTDIM>
949 where
950 Const<SDIM>: ToUInt,
951 Const<OUTDIM>: ToUInt,
952 <Const<SDIM> as ToUInt>::Output: Unsigned + NonZero,
953 <Const<OUTDIM> as ToUInt>::Output: Unsigned + NonZero,
954 NumberType<SDIM>: IsSmallerThan<NDIM>,
955 PInt<U<OUTDIM>>: Add<PInt<U<SDIM>>, Output = PInt<U<NDIM>>>,
956 PInt<U<NDIM>>: Sub<PInt<U<SDIM>>>,
957 {
958 MultisliceIteratorMut::new(self, axes)
959 }
960}
961
962impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
963where
964 ArrayImpl: UnsafeDisjointRandom1DAccessMut + Shape<NDIM>,
965{
966 #[inline(always)]
971 pub fn fill_from_iter<Iter>(&mut self, iter: Iter)
972 where
973 Iter: Iterator<Item = ArrayImpl::Item>,
974 {
975 for (item, other_item) in izip!(self.iter_mut(), iter) {
976 *item = other_item;
977 }
978 }
979}
980
981impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
982where
983 ArrayImpl: ResizeInPlace<NDIM> + Shape<NDIM> + UnsafeDisjointRandom1DAccessMut,
984{
985 #[inline(always)]
993 pub fn fill_from_resize<ArrayImplOther>(&mut self, other: &Array<ArrayImplOther, NDIM>)
994 where
995 ArrayImplOther: Shape<NDIM> + UnsafeRandom1DAccessByValue<Item = ArrayImpl::Item>,
996 {
997 self.resize_in_place(other.shape());
998 self.fill_from(other);
999 }
1000}
1001
1002impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
1003where
1004 ArrayImpl: UnsafeDisjointRandom1DAccessMut + Shape<NDIM>,
1005{
1006 #[inline(always)]
1012 pub fn fill_with_value(&mut self, value: ArrayImpl::Item) {
1013 for item in self.iter_mut() {
1014 *item = value;
1015 }
1016 }
1017}
1018
1019impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
1020where
1021 ArrayImpl: UnsafeDisjointRandom1DAccessMut + Shape<NDIM>,
1022{
1023 pub fn set_zero(&mut self) {
1025 for item in self.iter_mut() {
1026 *item = Default::default();
1027 }
1028 }
1029}
1030
1031impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
1032where
1033 ArrayImpl: UnsafeDisjointRandom1DAccessMut + UnsafeRandomAccessMut<NDIM> + Shape<NDIM>,
1034 ArrayImpl::Item: One,
1035{
1036 pub fn set_identity(&mut self) {
1038 self.set_zero();
1039 self.diag_iter_mut().for_each(|elem| *elem = One::one());
1040 }
1041}
1042
1043impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
1044where
1045 ArrayImpl: UnsafeRandomAccessByValue<NDIM> + Shape<NDIM>,
1046 ArrayImpl::Item: std::iter::Sum,
1047{
1048 #[inline(always)]
1056 pub fn trace(&self) -> ArrayImpl::Item {
1057 self.diag_iter_value().sum()
1058 }
1059}
1060
1061impl<Item, ArrayImpl> Array<ArrayImpl, 1>
1062where
1063 ArrayImpl: UnsafeRandom1DAccessByValue<Item = Item> + Shape<1>,
1064 ArrayImpl::Item: Conj<Output = Item>
1065 + std::ops::Mul<Output = ArrayImpl::Item>
1066 + std::ops::Add<Output = Item>,
1067{
1068 #[inline(always)]
1080 pub fn inner<ArrayImplOther>(&self, other: &Array<ArrayImplOther, 1>) -> Option<Item>
1081 where
1082 ArrayImplOther: UnsafeRandom1DAccessByValue<Item = Item> + Shape<1>,
1083 {
1084 assert_eq!(self.shape(), other.shape());
1085 izip!(self.iter_value(), other.iter_value())
1086 .map(|(x, y)| x * y.conj())
1087 .reduce(std::ops::Add::add)
1088 }
1089}
1090
1091impl<Item, ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
1092where
1093 ArrayImpl: UnsafeRandom1DAccessByValue<Item = Item> + Shape<NDIM>,
1094 Item: Abs,
1095 <Item as Abs>::Output: Max<Output = <Item as Abs>::Output>,
1096{
1097 #[inline(always)]
1108 pub fn max_abs(&self) -> Option<<Item as Abs>::Output> {
1109 self.iter_value().map(|elem| elem.abs()).reduce(Max::max)
1110 }
1111}
1112
1113impl<Item, ArrayImpl> Array<ArrayImpl, 1>
1114where
1115 ArrayImpl: UnsafeRandom1DAccessByValue<Item = Item> + Shape<1>,
1116 Item: Abs,
1117 <Item as Abs>::Output: std::ops::Add<Output = <Item as Abs>::Output>,
1118{
1119 #[inline(always)]
1131 pub fn norm_1(&self) -> Option<<Item as Abs>::Output> {
1132 self.iter_value()
1133 .map(|elem| elem.abs())
1134 .reduce(std::ops::Add::add)
1135 }
1136}
1137
1138impl<Item, ArrayImpl> Array<ArrayImpl, 1>
1139where
1140 ArrayImpl: UnsafeRandom1DAccessByValue<Item = Item> + Shape<1>,
1141 Item: AbsSquare,
1142 <Item as AbsSquare>::Output: Sqrt<Output = <Item as AbsSquare>::Output>
1143 + std::ops::Add<Output = <Item as AbsSquare>::Output>,
1144{
1145 #[inline(always)]
1154 pub fn norm_2(&self) -> Option<<Item as AbsSquare>::Output> {
1155 self.iter_value()
1156 .map(|elem| elem.abs_square())
1157 .reduce(std::ops::Add::add)
1158 .map(|elem| elem.sqrt())
1159 }
1160}
1161
1162impl<Item, ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
1163where
1164 ArrayImpl: UnsafeRandom1DAccessByValue<Item = Item> + Shape<NDIM>,
1165 Item: AbsSquare,
1166 <Item as AbsSquare>::Output: Sqrt<Output = <Item as AbsSquare>::Output>
1167 + std::ops::Add<Output = <Item as AbsSquare>::Output>
1168 + Copy
1169 + Default,
1170{
1171 #[inline(always)]
1180 pub fn norm_fro(&self) -> Option<<Item as AbsSquare>::Output> {
1181 self.r()
1182 .abs_square()
1183 .iter_value()
1184 .reduce(std::ops::Add::add)
1185 .map(|elem| elem.sqrt())
1186 }
1187}
1188
1189impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
1190where
1191 ArrayImpl: UnsafeRandom1DAccessByValue + Shape<NDIM>,
1192{
1193 #[allow(clippy::type_complexity)]
1201 pub fn into_type<T>(
1202 self,
1203 ) -> Array<
1204 ArrayUnaryOperator<ArrayImpl::Item, T, ArrayImpl, fn(ArrayImpl::Item) -> T, NDIM>,
1205 NDIM,
1206 >
1207 where
1208 ArrayImpl::Item: Into<T>,
1209 {
1210 Array::new(ArrayUnaryOperator::new(self, |item| item.into()))
1211 }
1212}
1213
1214impl<ArrayImpl> Array<ArrayImpl, 2>
1215where
1216 ArrayImpl: Shape<2> + UnsafeRandomAccessByValue<2>,
1217{
1218 pub fn col_iter(&self) -> ColIterator<'_, ArrayImpl, 2> {
1224 ColIterator::new(self)
1225 }
1226}
1227
1228impl<ArrayImpl> Array<ArrayImpl, 2>
1229where
1230 ArrayImpl: Shape<2> + UnsafeRandomAccessMut<2>,
1231{
1232 pub fn col_iter_mut(&mut self) -> ColIteratorMut<'_, ArrayImpl, 2> {
1238 ColIteratorMut::new(self)
1239 }
1240}
1241
1242impl<ArrayImpl> Array<ArrayImpl, 2>
1243where
1244 ArrayImpl: Shape<2> + UnsafeRandomAccessByValue<2>,
1245{
1246 pub fn row_iter(&self) -> RowIterator<'_, ArrayImpl, 2> {
1252 RowIterator::new(self)
1253 }
1254}
1255
1256impl<ArrayImpl> Array<ArrayImpl, 2>
1257where
1258 ArrayImpl: Shape<2> + UnsafeRandomAccessByValue<2>,
1259{
1260 pub fn row_iter_mut(&mut self) -> RowIteratorMut<'_, ArrayImpl, 2> {
1266 RowIteratorMut::new(self)
1267 }
1268}
1269
1270impl<ArrayImpl> Array<ArrayImpl, 2>
1271where
1272 ArrayImpl: UnsafeRandom1DAccessByValue + Shape<2>,
1273{
1274 pub fn iter_aij_value(&self) -> impl Iterator<Item = ([usize; 2], ArrayImpl::Item)> + '_ {
1283 let iter = ArrayDefaultIteratorByValue::new(self);
1284 AsMultiIndex::multi_index(std::iter::Iterator::enumerate(iter), self.shape())
1285 }
1286}
1287
1288impl<ArrayImpl> Array<ArrayImpl, 2>
1289where
1290 ArrayImpl: UnsafeRandom1DAccessByRef + Shape<2>,
1291{
1292 pub fn iter_aij_ref(&self) -> impl Iterator<Item = ([usize; 2], &ArrayImpl::Item)> + '_ {
1301 let iter = ArrayDefaultIteratorByRef::new(self);
1302 AsMultiIndex::multi_index(std::iter::Iterator::enumerate(iter), self.shape())
1303 }
1304}
1305
1306impl<ArrayImpl> Array<ArrayImpl, 2>
1307where
1308 ArrayImpl: UnsafeDisjointRandom1DAccessMut + Shape<2>,
1309{
1310 pub fn iter_aij_mut(
1319 &mut self,
1320 ) -> impl Iterator<Item = ([usize; 2], &mut ArrayImpl::Item)> + '_ {
1321 let shape = self.shape();
1322 let iter = ArrayDefaultIteratorMut::new(self);
1323 AsMultiIndex::multi_index(std::iter::Iterator::enumerate(iter), shape)
1324 }
1325}
1326
1327impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM> {
1328 pub fn cast<Target>(self) -> Array<ArrayCast<Target, ArrayImpl, NDIM>, NDIM> {
1333 Array::new(ArrayCast::new(self))
1334 }
1335}
1336
1337impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM> {
1338 pub fn coerce_dim<const CDIM: usize>(
1343 self,
1344 ) -> RlstResult<Array<CoerceArray<ArrayImpl, NDIM, CDIM>, CDIM>> {
1345 if CDIM == NDIM {
1346 Ok(Array::new(CoerceArray::new(self)))
1348 } else {
1349 Err(RlstError::GeneralError(
1351 format!("Cannot coerce array: dimensions do not match {CDIM} != {NDIM}.")
1352 .to_string(),
1353 ))
1354 }
1355 }
1356}
1357
1358impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
1359where
1360 ArrayImpl: Shape<NDIM>,
1361{
1362 pub fn permute_axes(
1372 self,
1373 permutation: [usize; NDIM],
1374 ) -> Array<ArrayTranspose<ArrayImpl, NDIM>, NDIM> {
1375 Array::new(ArrayTranspose::new(self, permutation))
1376 }
1377
1378 pub fn transpose(self) -> Array<ArrayTranspose<ArrayImpl, NDIM>, NDIM> {
1382 let mut permutation = [0; NDIM];
1383
1384 for (ind, p) in (0..NDIM).rev().enumerate() {
1385 permutation[ind] = p;
1386 }
1387
1388 self.permute_axes(permutation)
1389 }
1390}
1391
1392impl<Item, ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
1393where
1394 Item: RandScalar + RlstScalar,
1395 ArrayImpl: UnsafeDisjointRandom1DAccessMut<Item = Item> + Shape<NDIM>,
1396 StandardNormal: Distribution<Item::Real>,
1397 StandardUniform: Distribution<Item::Real>,
1398{
1399 pub fn fill_from_standard_normal<R: Rng>(&mut self, rng: &mut R) {
1406 let dist = StandardNormal;
1407 self.iter_mut()
1408 .for_each(|val| *val = <Item>::random_scalar(rng, &dist));
1409 }
1410
1411 pub fn fill_from_equally_distributed<R: Rng>(&mut self, rng: &mut R) {
1418 let dist = StandardUniform;
1419 self.iter_mut()
1420 .for_each(|val| *val = <Item>::random_scalar(rng, &dist));
1421 }
1422
1423 pub fn fill_from_seed_equally_distributed(&mut self, seed: usize) {
1430 let mut rng = ChaCha8Rng::seed_from_u64(seed as u64);
1431 let dist = StandardUniform;
1432 self.iter_mut()
1433 .for_each(|val| *val = <Item>::random_scalar(&mut rng, &dist));
1434 }
1435
1436 pub fn fill_from_seed_normally_distributed(&mut self, seed: usize) {
1443 let mut rng = ChaCha8Rng::seed_from_u64(seed as u64);
1444 let dist = StandardNormal;
1445 self.iter_mut()
1446 .for_each(|val| *val = <Item>::random_scalar(&mut rng, &dist));
1447 }
1448}
1449
1450impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM> {
1451 pub fn reverse_axis(self, axis: usize) -> Array<ReverseAxis<ArrayImpl, NDIM>, NDIM> {
1457 assert!(axis < NDIM, "Axis out of bounds");
1458 Array::new(ReverseAxis::new(self, axis))
1459 }
1460}
1461
1462impl<ArrayImpl, const ADIM: usize> Array<ArrayImpl, ADIM>
1463where
1464 ArrayImpl: Shape<ADIM>,
1465{
1466 pub fn slice<const OUTDIM: usize>(
1478 self,
1479 axis: usize,
1480 index: usize,
1481 ) -> Array<ArraySlice<ArrayImpl, ADIM, OUTDIM>, OUTDIM>
1482 where
1483 NumberType<ADIM>: IsGreaterByOne<OUTDIM>,
1484 NumberType<OUTDIM>: IsGreaterZero,
1485 {
1486 Array::new(ArraySlice::new(self, [axis, index]))
1487 }
1488
1489 pub fn multislice<const SDIM: usize, const OUTDIM: usize>(
1496 self,
1497 axes: [usize; SDIM],
1498 indices: [usize; SDIM],
1499 ) -> Array<Multislice<ArrayImpl, ADIM, SDIM, OUTDIM>, OUTDIM>
1500 where
1501 NumberType<SDIM>: IsSmallerThan<ADIM>,
1502 NumberDifference<ADIM, SDIM>: SubtractEqual<OUTDIM>,
1503 {
1504 Array::new(Multislice::new(self, axes, indices))
1505 }
1506}
1507
1508impl<ArrayImpl> Array<ArrayImpl, 2>
1509where
1510 ArrayImpl: Shape<2>,
1511{
1512 pub fn row(self, row_index: usize) -> Array<ArraySlice<ArrayImpl, 2, 1>, 1> {
1514 self.slice::<1>(0, row_index)
1515 }
1516
1517 pub fn col(self, col_index: usize) -> Array<ArraySlice<ArrayImpl, 2, 1>, 1> {
1519 self.slice::<1>(1, col_index)
1520 }
1521}
1522
1523impl<ArrayImpl: Shape<NDIM>, const NDIM: usize> Array<ArrayImpl, NDIM> {
1524 pub fn into_subview(
1529 self,
1530 offset: [usize; NDIM],
1531 shape: [usize; NDIM],
1532 ) -> Array<ArraySubView<ArrayImpl, NDIM>, NDIM> {
1533 Array::new(ArraySubView::new(self, offset, shape))
1534 }
1535}
1536
1537impl<Item, ArrayImpl1, ArrayImpl2, const NDIM: usize> MulAdd<Item, Array<ArrayImpl2, NDIM>>
1538 for Array<ArrayImpl1, NDIM>
1539where
1540 ArrayImpl1: BaseItem<Item = Item> + Shape<NDIM>,
1541 ArrayImpl2: BaseItem<Item = Item> + Shape<NDIM>,
1542 Item: MulAdd<Output = Item> + Copy,
1543{
1544 type Output = Array<MulAddImpl<ArrayImpl1, ArrayImpl2, Item, NDIM>, NDIM>;
1545 fn mul_add(
1549 self,
1550 a: Item,
1551 b: Array<ArrayImpl2, NDIM>,
1552 ) -> Array<MulAddImpl<ArrayImpl1, ArrayImpl2, Item, NDIM>, NDIM>
1553 where
1554 ArrayImpl1: BaseItem<Item = Item> + Shape<NDIM>,
1555 ArrayImpl2: BaseItem<Item = Item> + Shape<NDIM>,
1556 Item: MulAdd<Output = Item> + Copy,
1557 {
1558 Array::new(MulAddImpl::new(self, b, a))
1559 }
1560}
1561
1562impl<ArrayImpl1, ArrayImpl2, const NDIM: usize> std::ops::Add<Array<ArrayImpl2, NDIM>>
1563 for Array<ArrayImpl1, NDIM>
1564where
1565 ArrayImpl1: Shape<NDIM>,
1566 ArrayImpl2: Shape<NDIM>,
1567{
1568 type Output = Array<ArrayAddition<ArrayImpl1, ArrayImpl2, NDIM>, NDIM>;
1569
1570 #[inline(always)]
1571 fn add(self, rhs: Array<ArrayImpl2, NDIM>) -> Self::Output {
1572 Array::new(ArrayAddition::new(self, rhs))
1573 }
1574}
1575
1576impl<Item, ArrayImpl1, ArrayImpl2, const NDIM: usize> std::ops::AddAssign<Array<ArrayImpl2, NDIM>>
1577 for Array<ArrayImpl1, NDIM>
1578where
1579 ArrayImpl1: Shape<NDIM> + UnsafeDisjointRandom1DAccessMut<Item = Item>,
1580 ArrayImpl2: Shape<NDIM> + UnsafeRandom1DAccessByValue<Item = Item>,
1581 Item: std::ops::AddAssign,
1582{
1583 #[inline(always)]
1584 fn add_assign(&mut self, rhs: Array<ArrayImpl2, NDIM>) {
1585 assert_eq!(self.shape(), rhs.shape());
1586 for (item1, item2) in izip!(self.iter_mut(), rhs.iter_value()) {
1587 *item1 += item2;
1588 }
1589 }
1590}
1591
1592impl<ArrayImpl1, ArrayImpl2, const NDIM: usize> std::ops::Sub<Array<ArrayImpl2, NDIM>>
1593 for Array<ArrayImpl1, NDIM>
1594where
1595 ArrayImpl1: Shape<NDIM>,
1596 ArrayImpl2: Shape<NDIM>,
1597{
1598 type Output = Array<ArraySubtraction<ArrayImpl1, ArrayImpl2, NDIM>, NDIM>;
1599
1600 fn sub(self, rhs: Array<ArrayImpl2, NDIM>) -> Self::Output {
1601 Array::new(ArraySubtraction::new(self, rhs))
1602 }
1603}
1604
1605impl<Item, ArrayImpl1, ArrayImpl2, const NDIM: usize> std::ops::SubAssign<Array<ArrayImpl2, NDIM>>
1606 for Array<ArrayImpl1, NDIM>
1607where
1608 ArrayImpl1: Shape<NDIM> + UnsafeDisjointRandom1DAccessMut<Item = Item>,
1609 ArrayImpl2: Shape<NDIM> + UnsafeRandom1DAccessByValue<Item = Item>,
1610 Item: std::ops::SubAssign,
1611{
1612 #[inline(always)]
1613 fn sub_assign(&mut self, rhs: Array<ArrayImpl2, NDIM>) {
1614 assert_eq!(self.shape(), rhs.shape());
1615 for (item1, item2) in izip!(self.iter_mut(), rhs.iter_value()) {
1616 *item1 -= item2;
1617 }
1618 }
1619}
1620
1621impl<Item, ArrayImpl, const NDIM: usize> std::ops::Neg for Array<ArrayImpl, NDIM>
1622where
1623 ArrayImpl: BaseItem<Item = Item>,
1624 Item: std::ops::Neg<Output = Item>,
1625{
1626 type Output = Array<ArrayNeg<ArrayImpl, NDIM>, NDIM>;
1627
1628 fn neg(self) -> Self::Output {
1629 Array::new(ArrayNeg::new(self))
1630 }
1631}
1632
1633impl<ArrayImpl1, ArrayImpl2, const NDIM: usize> std::ops::Div<Array<ArrayImpl2, NDIM>>
1634 for Array<ArrayImpl1, NDIM>
1635where
1636 ArrayImpl1: Shape<NDIM>,
1637 ArrayImpl2: Shape<NDIM>,
1638{
1639 type Output = Array<CmpWiseDivision<ArrayImpl1, ArrayImpl2, NDIM>, NDIM>;
1640
1641 fn div(self, rhs: Array<ArrayImpl2, NDIM>) -> Self::Output {
1642 Array::new(CmpWiseDivision::new(self, rhs))
1643 }
1644}
1645
1646impl<Item, ArrayImpl, const NDIM: usize> std::ops::Div<Item> for Array<ArrayImpl, NDIM>
1647where
1648 ArrayImpl: Shape<NDIM> + BaseItem<Item = Item>,
1649 Item: Recip<Output = Item> + std::ops::Div<Output = Item>,
1650{
1651 type Output = Array<ArrayScalarMult<Item, ArrayImpl, NDIM>, NDIM>;
1652
1653 fn div(self, rhs: Item) -> Self::Output {
1654 Array::new(ArrayScalarMult::new(rhs.recip(), self))
1655 }
1656}
1657
1658impl<Item, ArrayImpl, const NDIM: usize> std::ops::DivAssign<Item> for Array<ArrayImpl, NDIM>
1659where
1660 ArrayImpl: Shape<NDIM> + UnsafeDisjointRandom1DAccessMut<Item = Item>,
1661 Item: std::ops::DivAssign + Copy,
1662{
1663 fn div_assign(&mut self, rhs: Item) {
1664 for item in self.iter_mut() {
1665 *item /= rhs;
1666 }
1667 }
1668}
1669
1670impl<ArrayImpl1, ArrayImpl2, const NDIM: usize> std::ops::Mul<Array<ArrayImpl2, NDIM>>
1671 for Array<ArrayImpl1, NDIM>
1672where
1673 ArrayImpl1: Shape<NDIM>,
1674 ArrayImpl2: Shape<NDIM>,
1675{
1676 type Output = Array<CmpWiseProduct<ArrayImpl1, ArrayImpl2, NDIM>, NDIM>;
1677
1678 fn mul(self, rhs: Array<ArrayImpl2, NDIM>) -> Self::Output {
1679 Array::new(CmpWiseProduct::new(self, rhs))
1680 }
1681}
1682
1683impl<Item, ArrayImpl1, ArrayImpl2, const NDIM: usize> std::ops::MulAssign<Array<ArrayImpl2, NDIM>>
1684 for Array<ArrayImpl1, NDIM>
1685where
1686 ArrayImpl1: Shape<NDIM> + UnsafeDisjointRandom1DAccessMut<Item = Item>,
1687 ArrayImpl2: Shape<NDIM> + UnsafeRandom1DAccessByValue<Item = Item>,
1688 Item: std::ops::MulAssign,
1689{
1690 fn mul_assign(&mut self, rhs: Array<ArrayImpl2, NDIM>) {
1691 for (item1, item2) in izip!(self.iter_mut(), rhs.iter_value()) {
1692 *item1 *= item2;
1693 }
1694 }
1695}
1696
1697impl<Item, ArrayImpl1, ArrayImpl2, const NDIM: usize> std::ops::DivAssign<Array<ArrayImpl2, NDIM>>
1698 for Array<ArrayImpl1, NDIM>
1699where
1700 ArrayImpl1: Shape<NDIM> + UnsafeDisjointRandom1DAccessMut<Item = Item>,
1701 ArrayImpl2: Shape<NDIM> + UnsafeRandom1DAccessByValue<Item = Item>,
1702 Item: std::ops::DivAssign,
1703{
1704 fn div_assign(&mut self, rhs: Array<ArrayImpl2, NDIM>) {
1705 for (item1, item2) in izip!(self.iter_mut(), rhs.iter_value()) {
1706 *item1 /= item2;
1707 }
1708 }
1709}
1710
1711macro_rules! impl_scalar_mult {
1712 ($ScalarType:ty) => {
1713 impl<ArrayImpl, const NDIM: usize> std::ops::Mul<Array<ArrayImpl, NDIM>> for $ScalarType {
1714 type Output = Array<ArrayScalarMult<$ScalarType, ArrayImpl, NDIM>, NDIM>;
1715
1716 fn mul(self, rhs: Array<ArrayImpl, NDIM>) -> Self::Output {
1717 Array::new(ArrayScalarMult::new(self, rhs))
1718 }
1719 }
1720
1721 impl<ArrayImpl, const NDIM: usize> std::ops::Mul<$ScalarType> for Array<ArrayImpl, NDIM>
1722 where
1723 ArrayImpl: Shape<NDIM> + BaseItem<Item = $ScalarType>,
1724 {
1725 type Output = Array<ArrayScalarMult<$ScalarType, ArrayImpl, NDIM>, NDIM>;
1726
1727 fn mul(self, rhs: $ScalarType) -> Self::Output {
1728 Array::new(ArrayScalarMult::new(rhs, self))
1729 }
1730 }
1731 };
1732}
1733
1734impl_scalar_mult!(f64);
1735impl_scalar_mult!(f32);
1736impl_scalar_mult!(c64);
1737impl_scalar_mult!(c32);
1738impl_scalar_mult!(usize);
1739impl_scalar_mult!(i8);
1740impl_scalar_mult!(i16);
1741impl_scalar_mult!(i32);
1742impl_scalar_mult!(i64);
1743impl_scalar_mult!(u8);
1744impl_scalar_mult!(u16);
1745impl_scalar_mult!(u32);
1746impl_scalar_mult!(u64);
1747
1748impl<Item, ArrayImpl, const NDIM: usize> std::ops::MulAssign<Item> for Array<ArrayImpl, NDIM>
1749where
1750 ArrayImpl: Shape<NDIM> + UnsafeDisjointRandom1DAccessMut<Item = Item>,
1751 Item: std::ops::MulAssign + Copy,
1752{
1753 fn mul_assign(&mut self, rhs: Item) {
1754 for item in self.iter_mut() {
1755 *item *= rhs;
1756 }
1757 }
1758}
1759
1760impl<ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM> {
1761 pub fn unary_op<OpItem, OpTarget, Op: Fn(OpItem) -> OpTarget>(
1763 self,
1764 op: Op,
1765 ) -> Array<ArrayUnaryOperator<OpItem, OpTarget, ArrayImpl, Op, NDIM>, NDIM> {
1766 Array::new(ArrayUnaryOperator::new(self, op))
1767 }
1768}
1769
1770impl<Item: Default + Copy + std::ops::Mul<Output = Item>, ArrayImpl, const NDIM: usize>
1771 Array<ArrayImpl, NDIM>
1772where
1773 ArrayImpl: BaseItem<Item = Item>,
1774{
1775 pub fn scalar_mul(self, scalar: Item) -> Array<ArrayScalarMult<Item, ArrayImpl, NDIM>, NDIM> {
1780 Array::new(ArrayScalarMult::new(scalar, self))
1781 }
1782}
1783
1784macro_rules! impl_unary_op_trait {
1785 ($name:ident, $method_name:ident) => {
1786 paste! {
1787
1788 use crate::traits::number_traits::$name;
1789 impl<Item: $name, ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
1790 where
1791 ArrayImpl: BaseItem<Item = Item>,
1792 {
1793 #[inline(always)]
1794 #[doc = "Componentwise apply `" $method_name "` to the array."]
1795 pub fn $method_name(self) -> Array<ArrayUnaryOperator<Item, <Item as $name>::Output, ArrayImpl, fn(Item) -> <Item as $name>::Output, NDIM>, NDIM> {
1796 self.unary_op(|x| x.$method_name())
1797 }
1798 }
1799 }
1800
1801 };
1802}
1803
1804impl_unary_op_trait!(Conj, conj);
1805impl_unary_op_trait!(Abs, abs);
1806impl_unary_op_trait!(Square, square);
1807impl_unary_op_trait!(AbsSquare, abs_square);
1808impl_unary_op_trait!(Sqrt, sqrt);
1809impl_unary_op_trait!(Exp, exp);
1810impl_unary_op_trait!(Ln, ln);
1811impl_unary_op_trait!(Recip, recip);
1812impl_unary_op_trait!(Sin, sin);
1813impl_unary_op_trait!(Cos, cos);
1814impl_unary_op_trait!(Tan, tan);
1815impl_unary_op_trait!(Asin, asin);
1816impl_unary_op_trait!(Acos, acos);
1817impl_unary_op_trait!(Atan, atan);
1818impl_unary_op_trait!(Sinh, sinh);
1819impl_unary_op_trait!(Cosh, cosh);
1820impl_unary_op_trait!(Tanh, tanh);
1821impl_unary_op_trait!(Asinh, asinh);
1822impl_unary_op_trait!(Acosh, acosh);
1823impl_unary_op_trait!(Atanh, atanh);
1824
1825impl<Item, ArrayImplX, ArrayImplY, ArrayImpl>
1826 AsMatrixApply<Array<ArrayImplX, 2>, Array<ArrayImplY, 2>> for Array<ArrayImpl, 2>
1827where
1828 Item: Gemm + Copy,
1829 ArrayImplX: RawAccess<Item = Item> + Stride<2> + Shape<2>,
1830 ArrayImplY: RawAccessMut<Item = Item> + Stride<2> + Shape<2>,
1831 ArrayImpl: RawAccess<Item = Item> + Stride<2> + Shape<2>,
1832{
1833 fn apply(
1834 &self,
1835 alpha: Self::Item,
1836 x: &Array<ArrayImplX, 2>,
1837 beta: Self::Item,
1838 y: &mut Array<ArrayImplY, 2>,
1839 ) {
1840 let stride_a = self.stride();
1841 let stride_x = x.stride();
1842 let stride_y = y.stride();
1843
1844 let shape_a = self.shape();
1845 let shape_x = x.shape();
1846 let shape_y = y.shape();
1847
1848 assert_eq!(
1849 shape_a[0], shape_y[0],
1850 "`y` has incompatible shape {shape_y:#?} with `self` {shape_a:#?}."
1851 );
1852
1853 assert_eq!(
1854 shape_a[1], shape_x[0],
1855 "`x` has incompatible shape {shape_x:#?} with `self` {shape_a:#?}."
1856 );
1857
1858 assert_eq!(
1859 shape_y[1], shape_x[1],
1860 "`x` has incompatible shape {shape_x:#?} with `y` {shape_y:#?}."
1861 );
1862
1863 let m = shape_a[0];
1864 let n = shape_x[1];
1865 let k = shape_a[1];
1866
1867 <Item as Gemm>::gemm(
1868 TransMode::NoTrans,
1869 TransMode::NoTrans,
1870 m,
1871 n,
1872 k,
1873 alpha,
1874 self.data().unwrap(),
1875 stride_a[0],
1876 stride_a[1],
1877 x.data().unwrap(),
1878 stride_x[0],
1879 stride_x[1],
1880 beta,
1881 y.data_mut().unwrap(),
1882 stride_y[0],
1883 stride_y[1],
1884 );
1885 }
1886}
1887
1888impl<Item, ArrayImplX, ArrayImplY, ArrayImpl>
1889 AsMatrixApply<Array<ArrayImplX, 1>, Array<ArrayImplY, 1>> for Array<ArrayImpl, 2>
1890where
1891 Item: Gemm + Copy,
1892 ArrayImplX: RawAccess<Item = Item> + Stride<1> + Shape<1>,
1893 ArrayImplY: RawAccessMut<Item = Item> + Stride<1> + Shape<1>,
1894 ArrayImpl: RawAccess<Item = Item> + Stride<2> + Shape<2>,
1895{
1896 fn apply(
1897 &self,
1898 alpha: Self::Item,
1899 x: &Array<ArrayImplX, 1>,
1900 beta: Self::Item,
1901 y: &mut Array<ArrayImplY, 1>,
1902 ) {
1903 self.apply(
1904 alpha,
1905 &x.r().insert_empty_axis::<2>(AxisPosition::Back),
1906 beta,
1907 &mut y.r_mut().insert_empty_axis::<2>(AxisPosition::Back),
1908 );
1909 }
1910}
1911
1912impl<Item, ArrayImpl> Array<ArrayImpl, 2>
1913where
1914 ArrayImpl: RawAccess<Item = Item> + Stride<2> + Shape<2>,
1915 Item: Gemm + Copy + Default + One + Zero,
1916{
1917 pub fn dot<ArrayImplOther, const NDIM: usize>(
1919 &self,
1920 other: &Array<ArrayImplOther, NDIM>,
1921 ) -> DynArray<Item, NDIM>
1922 where
1923 ArrayImplOther: RawAccess<Item = Item> + Shape<NDIM> + Stride<NDIM>,
1924 {
1925 let a_shape = self.shape();
1926 let x_shape = other.shape();
1927
1928 let mut out = empty_array::<Item, NDIM>();
1929
1930 if NDIM == 1 {
1931 let mut out = out.r_mut().coerce_dim::<1>().unwrap();
1932 out.resize_in_place([a_shape[0]]);
1933
1934 self.apply(
1935 Item::one(),
1936 &other.r().coerce_dim::<1>().unwrap(),
1937 Item::zero(),
1938 &mut out,
1939 );
1940 } else if NDIM == 2 {
1941 let mut out = out.r_mut().coerce_dim::<2>().unwrap();
1942 out.resize_in_place([a_shape[0], x_shape[1]]);
1943
1944 self.apply(
1945 Item::one(),
1946 &other.r().coerce_dim::<2>().unwrap(),
1947 Item::zero(),
1948 &mut out,
1949 )
1950 } else {
1951 panic!("NDIM = {NDIM} not supported.");
1952 }
1953
1954 out
1955 }
1956}
1957
1958impl<Item, ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
1959where
1960 ArrayImpl: UnsafeRandomAccessMut<NDIM, Item = Item>,
1961 Item: Copy,
1962{
1963 #[inline(always)]
1969 pub unsafe fn swap_unsafe(&mut self, pos1: [usize; NDIM], pos2: [usize; NDIM]) {
1970 let elem1 = *unsafe { self.get_unchecked_mut(pos1) };
1971 let elem2 = *unsafe { self.get_unchecked_mut(pos2) };
1972
1973 *unsafe { self.get_unchecked_mut(pos1) } = elem2;
1974 *unsafe { self.get_unchecked_mut(pos2) } = elem1;
1975 }
1976}
1977
1978impl<Item, ArrayImpl, const NDIM: usize> Array<ArrayImpl, NDIM>
1979where
1980 ArrayImpl: UnsafeRandomAccessMut<NDIM, Item = Item> + Shape<NDIM>,
1981 Item: Copy,
1982{
1983 #[inline(always)]
1987 pub fn swap(&mut self, pos1: [usize; NDIM], pos2: [usize; NDIM]) -> RlstResult<()> {
1988 let shape = self.shape();
1989 if !check_multi_index_in_bounds(pos1, shape) {
1990 Err(RlstError::GeneralError(format!(
1991 "Index `pos1` = {:#?} out of bounds.",
1992 pos1
1993 )))
1994 } else if !check_multi_index_in_bounds(pos2, shape) {
1995 Err(RlstError::GeneralError(format!(
1996 "Index `pos2` = {:#?} out of bounds.",
1997 pos2
1998 )))
1999 } else {
2000 unsafe {
2001 self.swap_unsafe(pos1, pos2);
2002 }
2003 Ok(())
2004 }
2005 }
2006}
2007
2008impl<Item> ScalarAsArray for Item
2009where
2010 Item: Default + Copy,
2011{
2012 fn as_array<const NDIM: usize>(&self) -> StaticArray<Self, NDIM, 1> {
2013 let mut arr = Array::new(BaseArray::new(ArrayContainer::<Item, 1>::new(), [1; NDIM]));
2014 *unsafe { arr.get_unchecked_mut([0; NDIM]) } = *self;
2015 arr
2016 }
2017}
2018
2019impl<Item, const NDIM: usize> StaticArray<Item, NDIM, 1>
2020where
2021 Item: Copy + Default,
2022{
2023 pub fn one_element_array() -> Self {
2025 Array::new(BaseArray::new(ArrayContainer::<Item, 1>::new(), [1; NDIM]))
2026 }
2027}
2028
2029macro_rules! impl_linspace_float {
2030 ($dtype:ty) => {
2031 impl<ArrayImpl> Linspace<$dtype> for Array<ArrayImpl, 1>
2032 where
2033 ArrayImpl: MutableArrayImpl<$dtype, 1>,
2034 {
2035 fn linspace(&mut self, a: $dtype, b: $dtype) {
2036 let n = self.len() - 1;
2037
2038 assert!(b > a, "`linspace` requires `{b} = b > a = {a} ");
2039 assert!(n > 1, "`linspace` requires `{n} = self.len() > 1");
2040
2041 let delta = (b - a) / (n as $dtype);
2042
2043 for (ind, elem) in self.iter_mut().enumerate().take(n) {
2044 *elem = a + delta * ind as $dtype;
2045 }
2046
2047 self[[n]] = b;
2048 }
2049 }
2050 };
2051}
2052
2053impl_linspace_float!(f32);
2054impl_linspace_float!(f64);
2055
2056#[cfg(test)]
2057mod test {
2058
2059 use approx::assert_relative_eq;
2060
2061 use crate::assert_array_relative_eq;
2062
2063 use super::*;
2064
2065 #[test]
2066 pub fn test_add() {
2067 let a: DynArray<_, 1> = vec![1.0, 2.0, 3.0].into();
2068 let b: DynArray<_, 1> = vec![1.5, 2.3, 4.0].into();
2069 let expected: DynArray<_, 1> = vec![2.5, 4.3, 7.0].into();
2070
2071 crate::assert_array_relative_eq!((a.r() + b.r()).eval(), expected, 1E-10);
2072 }
2073
2074 #[test]
2075 pub fn test_add_assign() {
2076 let mut a: DynArray<_, 1> = vec![1.0, 2.0, 3.0].into();
2077 let b: DynArray<_, 1> = vec![1.5, 2.3, 4.0].into();
2078 let expected: DynArray<_, 1> = vec![2.5, 4.3, 7.0].into();
2079
2080 a += b;
2081
2082 crate::assert_array_relative_eq!(a, expected, 1E-10);
2083 }
2084
2085 #[test]
2086 pub fn test_sub() {
2087 let a: DynArray<_, 1> = vec![1.0, 2.0, 3.0].into();
2088 let b: DynArray<_, 1> = vec![1.5, 2.3, 4.0].into();
2089 let expected: DynArray<_, 1> = vec![-0.5, -0.3, -1.0].into();
2090
2091 crate::assert_array_relative_eq!((a.r() - b.r()).eval(), expected, 1E-10);
2092 }
2093
2094 #[test]
2095 pub fn test_sub_assign() {
2096 let mut a: DynArray<_, 1> = vec![1.0, 2.0, 3.0].into();
2097 let b: DynArray<_, 1> = vec![1.5, 2.3, 4.0].into();
2098 let expected: DynArray<_, 1> = vec![-0.5, -0.3, -1.0].into();
2099
2100 a -= b;
2101
2102 crate::assert_array_relative_eq!(a, expected, 1E-10);
2103 }
2104
2105 #[test]
2106 pub fn test_cmp_mul() {
2107 let a: DynArray<_, 1> = vec![1.0, 2.0, 3.0].into();
2108 let b: DynArray<_, 1> = vec![1.5, 2.3, 4.0].into();
2109 let expected: DynArray<_, 1> = vec![1.5, 4.6, 12.0].into();
2110
2111 crate::assert_array_relative_eq!(a.r() * b.r(), expected, 1E-10);
2112 }
2113
2114 #[test]
2115 pub fn test_cmp_mul_assign() {
2116 let mut a: DynArray<_, 1> = vec![1.0, 2.0, 3.0].into();
2117 let b: DynArray<_, 1> = vec![1.5, 2.3, 4.0].into();
2118 let expected: DynArray<_, 1> = vec![1.5, 4.6, 12.0].into();
2119
2120 a *= b;
2121
2122 crate::assert_array_relative_eq!(a, expected, 1E-10);
2123 }
2124
2125 #[test]
2126 pub fn test_scalar_mul() {
2127 let a: DynArray<_, 1> = vec![1.0, 2.0, 3.0].into();
2128 let expected: DynArray<_, 1> = vec![2.0, 4.0, 6.0].into();
2129
2130 crate::assert_array_relative_eq!(2.0_f64 * a.r(), expected, 1E-10);
2131 }
2132
2133 #[test]
2134 pub fn test_scalar_mul_assign() {
2135 let mut a: DynArray<_, 1> = vec![1.0, 2.0, 3.0].into();
2136 let expected: DynArray<_, 1> = vec![2.0, 4.0, 6.0].into();
2137
2138 a *= 2.0;
2139
2140 crate::assert_array_relative_eq!(a.r(), expected, 1E-10);
2141 }
2142
2143 #[test]
2144 pub fn test_cmp_div() {
2145 let a: DynArray<_, 1> = vec![1.5, 4.6, 12.0].into();
2146 let b: DynArray<_, 1> = vec![1.0, 2.0, 3.0].into();
2147 let expected: DynArray<_, 1> = vec![1.5, 2.3, 4.0].into();
2148
2149 crate::assert_array_relative_eq!(a.r() / b.r(), expected, 1E-10);
2150 }
2151
2152 #[test]
2153 pub fn test_cmp_div_assign() {
2154 let mut a: DynArray<_, 1> = vec![1.5, 4.6, 12.0].into();
2155 let b: DynArray<_, 1> = vec![1.0, 2.0, 3.0].into();
2156 let expected: DynArray<_, 1> = vec![1.5, 2.3, 4.0].into();
2157
2158 a /= b;
2159
2160 crate::assert_array_relative_eq!(a, expected, 1E-10);
2161 }
2162
2163 #[test]
2164 pub fn test_scalar_div() {
2165 let a: DynArray<_, 1> = vec![2.0, 4.0, 6.0].into();
2166 let expected: DynArray<_, 1> = vec![1.0, 2.0, 3.0].into();
2167
2168 crate::assert_array_relative_eq!(a.r() / 2.0, expected, 1E-10);
2169 }
2170
2171 #[test]
2172 pub fn test_scalar_div_assign() {
2173 let mut a: DynArray<_, 1> = vec![2.0, 4.0, 6.0].into();
2174 let expected: DynArray<_, 1> = vec![1.0, 2.0, 3.0].into();
2175
2176 a /= 2.0;
2177
2178 crate::assert_array_relative_eq!(a.r(), expected, 1E-10);
2179 }
2180
2181 #[test]
2182 pub fn test_into_subview() {
2183 let mut rng = ChaCha8Rng::seed_from_u64(0);
2184 let mut a = DynArray::<f64, 3>::from_shape([7, 5, 9]);
2185 a.fill_from_equally_distributed(&mut rng);
2186
2187 let view = a.r().into_subview([1, 0, 3], [2, 3, 4]);
2188
2189 assert_eq!(view[[1, 2, 3]], a[[2, 2, 6]])
2190 }
2191
2192 #[test]
2193 pub fn test_apply() {
2194 let mut rng = ChaCha8Rng::seed_from_u64(0);
2195
2196 let alpha = 1.5;
2197 let beta = 3.6;
2198
2199 let mut a = DynArray::<f64, 2>::from_shape([3, 2]);
2200 a.fill_from_equally_distributed(&mut rng);
2201
2202 let mut x = DynArray::<f64, 1>::from_shape([2]);
2203 x.fill_from_equally_distributed(&mut rng);
2204
2205 let mut y = DynArray::<f64, 1>::from_shape([3]);
2206 y.fill_from_equally_distributed(&mut rng);
2207 let y2 = y.eval();
2208
2209 a.apply(alpha, &x, beta, &mut y);
2210
2211 for (row_index, row) in a.row_iter().enumerate() {
2212 assert_relative_eq!(
2213 alpha * row.inner(&x).unwrap() + beta * y2[[row_index]],
2214 y[[row_index]],
2215 epsilon = 1E-10
2216 );
2217 }
2218
2219 let mut x = DynArray::<f64, 2>::from_shape([2, 5]);
2220 x.fill_from_equally_distributed(&mut rng);
2221
2222 let mut y = DynArray::<f64, 2>::from_shape([3, 5]);
2223 y.fill_from_equally_distributed(&mut rng);
2224 let y2 = y.eval();
2225
2226 a.apply(alpha, &x, beta, &mut y);
2227
2228 for (row_index, row) in a.row_iter().enumerate() {
2229 for (col_index, col) in x.col_iter().enumerate() {
2230 assert_relative_eq!(
2231 alpha * row.inner(&col).unwrap() + beta * y2[[row_index, col_index]],
2232 y[[row_index, col_index]],
2233 epsilon = 1E-10
2234 );
2235 }
2236 }
2237 }
2238
2239 #[test]
2240 pub fn test_dot() {
2241 let mut rng = ChaCha8Rng::seed_from_u64(0);
2242
2243 let mut a = DynArray::<f64, 2>::from_shape([3, 2]);
2244 a.fill_from_equally_distributed(&mut rng);
2245
2246 let mut x = DynArray::<f64, 1>::from_shape([2]);
2247 x.fill_from_equally_distributed(&mut rng);
2248
2249 let mut y = DynArray::<f64, 1>::from_shape([3]);
2250
2251 a.apply(1.0, &x, 0.0, &mut y);
2252
2253 crate::assert_array_relative_eq!(y, a.dot(&x), 1E-10);
2254
2255 let mut x = DynArray::<f64, 2>::from_shape([2, 5]);
2256 x.fill_from_equally_distributed(&mut rng);
2257
2258 let mut y = DynArray::<f64, 2>::from_shape([3, 5]);
2259
2260 a.apply(1.0, &x, 0.0, &mut y);
2261
2262 crate::assert_array_relative_eq!(y, a.dot(&x), 1E-10);
2263 }
2264
2265 #[test]
2266 pub fn test_swap() {
2267 let mut a = DynArray::<usize, 1>::from_shape([2]);
2268 a[[0]] = 1;
2269 a[[1]] = 2;
2270
2271 a.swap([0], [1]).unwrap();
2272 assert_eq!(a[[0]], 2);
2273 assert_eq!(a[[1]], 1);
2274 }
2275
2276 #[test]
2277 pub fn test_multislice_iterator() {
2278 let mut arr = DynArray::<f64, _>::from_shape([2, 3, 4, 5]);
2279 arr.fill_from_seed_equally_distributed(0);
2280
2281 let mut count = 0;
2282 for (indices, slice) in arr.r().multislice_iter::<_, 2>([2, 3]) {
2283 assert_array_relative_eq!(slice, arr.r().multislice::<_, 2>([2, 3], indices), 1E-12);
2284 count += 1;
2285 }
2286 assert_eq!(count, 20);
2287 }
2288
2289 #[test]
2290 pub fn test_multislice_iterator_mut() {
2291 let mut arr = DynArray::<f64, _>::from_shape([2, 3, 4, 5]);
2292 arr.fill_from_seed_equally_distributed(0);
2293 let expected = arr.eval();
2294
2295 let mut count = 0;
2296 for (indices, slice) in arr.r_mut().multislice_iter_mut::<_, 2>([2, 3]) {
2297 assert_array_relative_eq!(
2298 slice,
2299 expected.r().multislice::<_, 2>([2, 3], indices),
2300 1E-12
2301 );
2302 count += 1;
2303 }
2304 assert_eq!(count, 20);
2305 }
2306}