1use std::fmt::Debug;
2use std::ops::{Add, AddAssign, Mul, Sub, SubAssign};
3
4use crate::error::LaError;
5use crate::scalar::Scale;
6use crate::{Context, IndexType, Scalar, Vector, VectorIndex, VectorViewMut};
7
8use extract_block::combine;
9use num_traits::{One, Zero};
10use sparsity::{Dense, MatrixSparsity, MatrixSparsityRef};
11
12#[cfg(feature = "cuda")]
13#[allow(deprecated)]
14pub mod cuda;
15
16#[cfg(feature = "cuda-oxide")]
17pub mod cuda_oxide;
18
19#[cfg(feature = "nalgebra")]
20pub mod dense_nalgebra_serial;
21
22#[cfg(feature = "faer")]
23pub mod dense_faer_serial;
24
25#[cfg(feature = "faer")]
26pub mod sparse_faer;
27
28pub mod default_solver;
29pub mod extract_block;
30pub mod sparsity;
31
32pub trait MatrixCommon: Sized + Debug {
34 type V: Vector<T = Self::T, C = Self::C, Index: VectorIndex<C = Self::C>>;
35 type T: Scalar;
36 type C: Context;
37 type Inner;
38
39 fn nrows(&self) -> IndexType;
41 fn ncols(&self) -> IndexType;
43 fn inner(&self) -> &Self::Inner;
45}
46
47impl<M> MatrixCommon for &M
48where
49 M: MatrixCommon,
50{
51 type T = M::T;
52 type V = M::V;
53 type C = M::C;
54 type Inner = M::Inner;
55
56 fn nrows(&self) -> IndexType {
57 M::nrows(*self)
58 }
59 fn ncols(&self) -> IndexType {
60 M::ncols(*self)
61 }
62 fn inner(&self) -> &Self::Inner {
63 M::inner(*self)
64 }
65}
66
67impl<M> MatrixCommon for &mut M
68where
69 M: MatrixCommon,
70{
71 type T = M::T;
72 type V = M::V;
73 type C = M::C;
74 type Inner = M::Inner;
75
76 fn ncols(&self) -> IndexType {
77 M::ncols(*self)
78 }
79 fn nrows(&self) -> IndexType {
80 M::nrows(*self)
81 }
82 fn inner(&self) -> &Self::Inner {
83 M::inner(*self)
84 }
85}
86
87pub trait MatrixOpsByValue<Rhs = Self, Output = Self>:
91 MatrixCommon + Add<Rhs, Output = Output> + Sub<Rhs, Output = Output>
92{
93}
94
95impl<M, Rhs, Output> MatrixOpsByValue<Rhs, Output> for M where
96 M: MatrixCommon + Add<Rhs, Output = Output> + Sub<Rhs, Output = Output>
97{
98}
99
100pub trait MatrixMutOpsByValue<Rhs = Self>: MatrixCommon + AddAssign<Rhs> + SubAssign<Rhs> {}
104
105impl<M, Rhs> MatrixMutOpsByValue<Rhs> for M where M: MatrixCommon + AddAssign<Rhs> + SubAssign<Rhs> {}
106
107pub trait MatrixRef<M: MatrixCommon>: Mul<Scale<M::T>, Output = M> {}
109impl<RefT, M: MatrixCommon> MatrixRef<M> for RefT where RefT: Mul<Scale<M::T>, Output = M> {}
110
111pub trait Matrix:
124 MatrixCommon + Mul<Scale<Self::T>, Output = Self> + Clone + Send + 'static
125{
126 type Sparsity: MatrixSparsity<Self>;
127 type SparsityRef<'a>: MatrixSparsityRef<'a, Self>
128 where
129 Self: 'a;
130
131 fn sparsity(&self) -> Option<Self::SparsityRef<'_>>;
133
134 fn context(&self) -> &Self::C;
136
137 fn inner_mut(&mut self) -> &mut Self::Inner;
139
140 fn is_sparse() -> bool {
142 Self::zeros(1, 1, Default::default()).sparsity().is_some()
143 }
144
145 fn partition_indices_by_zero_diagonal(
152 &self,
153 ) -> (<Self::V as Vector>::Index, <Self::V as Vector>::Index);
154
155 fn gemv(&self, alpha: Self::T, x: &Self::V, beta: Self::T, y: &mut Self::V);
157
158 fn copy_from(&mut self, other: &Self);
160
161 fn zeros(nrows: IndexType, ncols: IndexType, ctx: Self::C) -> Self;
163
164 fn new_from_sparsity(
166 nrows: IndexType,
167 ncols: IndexType,
168 sparsity: Option<Self::Sparsity>,
169 ctx: Self::C,
170 ) -> Self;
171
172 fn from_diagonal(v: &Self::V) -> Self;
174
175 fn set_column(&mut self, j: IndexType, v: &Self::V);
179
180 fn add_column_to_vector(&self, j: IndexType, v: &mut Self::V);
182
183 fn add_columns_to_batched_vector(&self, v: &mut Self::V);
186
187 fn set_data_with_indices(
193 &mut self,
194 dst_indices: &<Self::V as Vector>::Index,
195 src_indices: &<Self::V as Vector>::Index,
196 data: &Self::V,
197 );
198
199 fn gather(&mut self, other: &Self, indices: &<Self::V as Vector>::Index);
205
206 fn split(
222 &self,
223 algebraic_indices: &<Self::V as Vector>::Index,
224 ) -> [(Self, <Self::V as Vector>::Index); 4] {
225 match self.sparsity() {
226 Some(sp) => sp.split(algebraic_indices).map(|(sp, src_indices)| {
227 let mut m = Self::new_from_sparsity(
228 sp.nrows(),
229 sp.ncols(),
230 Some(sp),
231 self.context().clone(),
232 );
233 m.gather(self, &src_indices);
234 (m, src_indices)
235 }),
236 None => Dense::<Self>::new(self.nrows(), self.ncols())
237 .split(algebraic_indices)
238 .map(|(sp, src_indices)| {
239 let mut m = Self::new_from_sparsity(
240 sp.nrows(),
241 sp.ncols(),
242 None,
243 self.context().clone(),
244 );
245 m.gather(self, &src_indices);
246 (m, src_indices)
247 }),
248 }
249 }
250
251 fn combine(
256 ul: &Self,
257 ur: &Self,
258 ll: &Self,
259 lr: &Self,
260 algebraic_indices: &<Self::V as Vector>::Index,
261 ) -> Self {
262 combine(ul, ur, ll, lr, algebraic_indices)
263 }
264
265 fn scale_add_and_assign(&mut self, x: &Self, beta: Self::T, y: &Self);
270
271 fn triplet_iter(
278 &self,
279 ) -> (
280 impl Iterator<Item = (IndexType, IndexType)> + '_,
281 impl Iterator<Item = Self::T> + '_,
282 );
283
284 fn try_from_triplets(
290 nrows: IndexType,
291 ncols: IndexType,
292 indices: Vec<(IndexType, IndexType)>,
293 values: Vec<Self::T>,
294 ctx: Self::C,
295 ) -> Result<Self, LaError>;
296}
297
298pub const MAX_SMALL_COLS: usize = 8;
310
311pub trait DenseMatrix:
321 Matrix + for<'b> MatrixOpsByValue<&'b Self, Self> + for<'b> MatrixMutOpsByValue<&'b Self>
322{
323 fn update_backward_diff(&mut self, order: IndexType, d: &Self::V);
334
335 fn update_backward_diff_transpose(&mut self, order: IndexType, d_bar: &mut Self::V) {
350 let n = order + 3;
351 assert!(n <= MAX_SMALL_COLS, "order out of bounds");
352 let ones = [Self::T::one(); MAX_SMALL_COLS];
353 self.gemv_cols(0, n, Self::T::one(), &ones, Self::T::zero(), d_bar);
354
355 let mut t = [Self::T::zero(); MAX_SMALL_COLS * MAX_SMALL_COLS];
357 for j in 0..=order {
358 for i in 0..=j {
359 t[j * n + i] = Self::T::one();
360 }
361 }
362 t[(order + 1) * n + order + 2] = -Self::T::one();
363 self.mul_cols_by(n, &t[..n * n]);
364 }
365
366 fn fill(&mut self, value: Self::T) {
371 let col = Self::V::from_element(self.nrows(), value, self.context().clone());
372 for j in 0..self.ncols() {
373 self.column_mut(j).copy_from(&col);
374 }
375 }
376
377 fn mul_cols_by_transpose(&mut self, ncols: IndexType, rhs: &[Self::T]) {
386 assert!(ncols <= MAX_SMALL_COLS, "ncols out of bounds");
387 assert_eq!(rhs.len(), ncols * ncols, "rhs must be ncols x ncols");
388 let mut rhs_t = [Self::T::zero(); MAX_SMALL_COLS * MAX_SMALL_COLS];
389 for j in 0..ncols {
390 for i in 0..ncols {
391 rhs_t[j * ncols + i] = rhs[i * ncols + j];
392 }
393 }
394 self.mul_cols_by(ncols, &rhs_t[..ncols * ncols]);
395 }
396
397 fn mul_cols_by(&mut self, ncols: IndexType, rhs: &[Self::T]);
409
410 fn gemv_cols(
434 &self,
435 start: IndexType,
436 end: IndexType,
437 alpha: Self::T,
438 x: &[Self::T],
439 beta: Self::T,
440 y: &mut Self::V,
441 );
442
443 fn ger_cols(
458 &mut self,
459 start: IndexType,
460 end: IndexType,
461 alpha: Self::T,
462 x: &[Self::T],
463 y: &Self::V,
464 ) {
465 assert!(
466 x.len() >= end.saturating_sub(start),
467 "ger_cols needs a coefficient per column in the range"
468 );
469 for j in start..end {
470 self.column_mut(j)
471 .axpy(alpha * x[j - start], y, Self::T::one());
472 }
473 }
474
475 fn column(&self, i: IndexType) -> <Self::V as Vector>::View<'_>;
477
478 fn column_mut(&mut self, i: IndexType) -> <Self::V as Vector>::ViewMut<'_>;
480
481 fn set_index(&mut self, i: IndexType, j: IndexType, value: Self::T);
486
487 fn set_index_batch(&mut self, batch: IndexType, i: IndexType, j: IndexType, value: Self::T);
492
493 fn get_index(&self, i: IndexType, j: IndexType) -> Self::T;
498
499 fn resize_cols(&mut self, ncols: IndexType);
503
504 fn from_vec(nrows: IndexType, ncols: IndexType, data: Vec<Self::T>, ctx: Self::C) -> Self;
508}
509
510#[cfg(test)]
511#[allow(clippy::items_after_test_module)]
512pub(crate) mod tests {
513 use std::ops::{Add, Mul, Sub};
514
515 use super::{
516 DenseMatrix, Matrix, MatrixCommon, MatrixSparsity, MatrixSparsityRef, MAX_SMALL_COLS,
517 };
518 use crate::scalar::Scale;
519 use crate::{scalar::IndexType, Context, Vector, VectorIndex, VectorView, VectorViewMut};
520 use num_traits::{FromPrimitive, One, Zero};
521
522 fn f<M: Matrix>(x: f64) -> M::T {
523 M::T::from_f64(x).unwrap()
524 }
525
526 fn at<M: DenseMatrix>(a: &M, batch: usize, i: IndexType, j: IndexType) -> M::T {
529 a.column(j).into_owned().get_batch(batch).get_index(i)
530 }
531
532 pub(crate) fn triplet_values<M: Matrix>(m: &M) -> Vec<M::T> {
533 let (_, vals) = m.triplet_iter();
534 vals.collect()
535 }
536
537 fn triplet_indices<M: Matrix>(m: &M) -> Vec<(IndexType, IndexType)> {
538 let (idx, _) = m.triplet_iter();
539 idx.collect()
540 }
541
542 pub fn test_partition_indices_by_zero_diagonal<M: Matrix>() {
543 let indices = vec![(0, 0), (1, 1), (3, 3)];
544 let values = vec![M::T::one(), M::T::from_f64(2.0).unwrap(), M::T::one()];
545 let m = M::try_from_triplets(4, 4, indices, values, Default::default()).unwrap();
546 let (zero_diagonal_indices, non_zero_diagonal_indices) =
547 m.partition_indices_by_zero_diagonal();
548 assert_eq!(zero_diagonal_indices.clone_as_vec(), vec![2]);
549 assert_eq!(non_zero_diagonal_indices.clone_as_vec(), vec![0, 1, 3]);
550
551 let indices = vec![(0, 0), (1, 1), (2, 2), (3, 3)];
552 let values = vec![
553 M::T::one(),
554 M::T::from_f64(2.0).unwrap(),
555 M::T::zero(),
556 M::T::one(),
557 ];
558 let m = M::try_from_triplets(4, 4, indices, values, Default::default()).unwrap();
559 let (zero_diagonal_indices, non_zero_diagonal_indices) =
560 m.partition_indices_by_zero_diagonal();
561 assert_eq!(zero_diagonal_indices.clone_as_vec(), vec![2]);
562 assert_eq!(non_zero_diagonal_indices.clone_as_vec(), vec![0, 1, 3]);
563
564 let indices = vec![(0, 0), (1, 1), (2, 2), (3, 3)];
565 let values = vec![
566 M::T::one(),
567 M::T::from_f64(2.0).unwrap(),
568 M::T::from_f64(3.0).unwrap(),
569 M::T::one(),
570 ];
571 let m = M::try_from_triplets(4, 4, indices, values, Default::default()).unwrap();
572 let (zero_diagonal_indices, non_zero_diagonal_indices) =
573 m.partition_indices_by_zero_diagonal();
574 assert_eq!(
575 zero_diagonal_indices.clone_as_vec(),
576 Vec::<IndexType>::new()
577 );
578 assert_eq!(non_zero_diagonal_indices.clone_as_vec(), vec![0, 1, 2, 3]);
579
580 let indices = vec![(3, 2)];
583 let values = vec![M::T::one()];
584 let m = M::try_from_triplets(4, 4, indices, values, Default::default()).unwrap();
585 let (zero_diagonal_indices, non_zero_diagonal_indices) =
586 m.partition_indices_by_zero_diagonal();
587 assert_eq!(zero_diagonal_indices.clone_as_vec(), vec![0, 1, 2, 3]);
588 assert_eq!(
589 non_zero_diagonal_indices.clone_as_vec(),
590 Vec::<IndexType>::new()
591 );
592 }
593
594 pub fn test_zeros<M: Matrix>() {
597 let a = M::zeros(2, 3, Default::default());
598 assert_eq!(a.nrows(), 2);
599 assert_eq!(a.ncols(), 3);
600 let vals = triplet_values(&a);
601 assert!(vals.is_empty() || vals.iter().all(|v| v.is_zero()));
602 assert_eq!(M::is_sparse(), a.sparsity().is_some());
603 }
604
605 pub fn test_sparsity<M: Matrix>() {
611 let a = M::Sparsity::try_from_indices(2, 2, vec![(0, 0), (1, 1)]).unwrap();
612 assert_eq!(MatrixSparsity::<M>::nrows(&a), 2);
613 assert_eq!(MatrixSparsity::<M>::ncols(&a), 2);
614 assert_eq!(
615 M::is_sparse(),
616 <M::Sparsity as MatrixSparsity<M>>::is_sparse()
617 );
618 let _ = a.indices();
619 let diag = M::Sparsity::new_diagonal(3);
620 assert_eq!(MatrixSparsity::<M>::nrows(&diag), 3);
621 assert_eq!(MatrixSparsity::<M>::ncols(&diag), 3);
622
623 let b = M::Sparsity::try_from_indices(2, 2, vec![(0, 1)]).unwrap();
624 let unioned = a.clone().union(b.as_ref()).unwrap();
625 assert_eq!(MatrixSparsity::<M>::nrows(&unioned), 2);
626 assert_eq!(MatrixSparsity::<M>::ncols(&unioned), 2);
627
628 let idx = a.get_index(&[(0, 0), (1, 1)], Default::default());
629 assert_eq!(idx.len(), 2);
630
631 let a_ref = a.as_ref();
632 assert_eq!(MatrixSparsityRef::<M>::nrows(&a_ref), 2);
633 assert_eq!(MatrixSparsityRef::<M>::ncols(&a_ref), 2);
634 assert_eq!(
635 M::is_sparse(),
636 <M::SparsityRef<'_> as MatrixSparsityRef<M>>::is_sparse()
637 );
638 let _ = a_ref.indices();
639 let owned = a_ref.to_owned();
640 assert_eq!(MatrixSparsity::<M>::nrows(&owned), 2);
641
642 let algebraic = <M::V as Vector>::Index::from_vec(vec![1], Default::default());
643 let [(ul, _), (_, _), (_, _), (lr, _)] = a_ref.split(&algebraic);
644 assert_eq!(MatrixSparsity::<M>::nrows(&ul), 1);
645 assert_eq!(MatrixSparsity::<M>::nrows(&lr), 1);
646 }
647
648 pub fn test_matrix_common_by_ref<M: Matrix>() {
649 fn via_common<T: MatrixCommon>(m: T) -> (IndexType, IndexType) {
650 let dims = (m.nrows(), m.ncols());
651 let _ = m.inner();
652 dims
653 }
654 let mut a = M::zeros(2, 3, Default::default());
655 assert_eq!(via_common(&a), (2, 3));
656 assert_eq!(via_common(&mut a), (2, 3));
657 }
658
659 pub fn test_from_diagonal<M: Matrix>() {
660 let v = M::V::from_vec(
661 vec![f::<M>(2.0), f::<M>(3.0), f::<M>(5.0)],
662 Default::default(),
663 );
664 let a = M::from_diagonal(&v);
665 assert_eq!(a.nrows(), 3);
666 assert_eq!(a.ncols(), 3);
667 let idx = triplet_indices(&a);
668 let vals = triplet_values(&a);
669 for &(i, j) in &idx {
671 let pos = idx.iter().position(|&x| x == (i, j)).unwrap();
672 if i == j {
673 assert!(
674 vals[pos] != M::T::zero(),
675 "diagonal entry should be non-zero"
676 );
677 } else {
678 assert!(vals[pos].is_zero(), "off-diagonal entry should be zero");
679 }
680 }
681 }
682
683 pub fn test_from_diagonal_dense<M: DenseMatrix>() {
684 let v = M::V::from_vec(
685 vec![f::<M>(2.0), f::<M>(3.0), f::<M>(5.0)],
686 Default::default(),
687 );
688 let a = M::from_diagonal(&v);
689 assert_eq!(a.nrows(), 3);
690 assert_eq!(a.ncols(), 3);
691 assert_eq!(a.get_index(0, 0), f::<M>(2.0));
692 assert_eq!(a.get_index(1, 1), f::<M>(3.0));
693 assert_eq!(a.get_index(2, 2), f::<M>(5.0));
694 assert_eq!(a.get_index(0, 1), f::<M>(0.0));
695 assert_eq!(a.get_index(1, 0), f::<M>(0.0));
696 }
697
698 pub fn test_gemv<M: Matrix>() {
699 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
700 let values = vec![f::<M>(1.0), f::<M>(3.0), f::<M>(2.0), f::<M>(4.0)];
701 let a = M::try_from_triplets(2, 2, indices, values, Default::default()).unwrap();
702 let x = M::V::from_vec(vec![f::<M>(1.0), f::<M>(2.0)], Default::default());
703 let mut y = M::V::zeros(2, Default::default());
704 a.gemv(f::<M>(1.0), &x, f::<M>(0.0), &mut y);
705 assert_eq!(y.clone_as_vec(), vec![f::<M>(5.0), f::<M>(11.0)]);
706
707 a.gemv(f::<M>(1.0), &x, f::<M>(1.0), &mut y);
709 assert_eq!(y.clone_as_vec(), vec![f::<M>(10.0), f::<M>(22.0)]);
710 }
711
712 pub fn test_set_column<M: Matrix>() {
713 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
714 let values = vec![f::<M>(0.0), f::<M>(0.0), f::<M>(0.0), f::<M>(0.0)];
715 let mut a = M::try_from_triplets(2, 2, indices, values, Default::default()).unwrap();
716 let v = M::V::from_vec(vec![f::<M>(7.0), f::<M>(8.0)], Default::default());
717 a.set_column(1, &v);
718 let idx = triplet_indices(&a);
719 let vals = triplet_values(&a);
720 assert_eq!(idx, vec![(0, 0), (1, 0), (0, 1), (1, 1)]);
721 assert_eq!(
722 vals,
723 vec![f::<M>(0.0), f::<M>(0.0), f::<M>(7.0), f::<M>(8.0)]
724 );
725 }
726
727 pub fn test_copy_from<M: Matrix>() {
728 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
729 let values = vec![f::<M>(1.0), f::<M>(2.0), f::<M>(3.0), f::<M>(4.0)];
730 let a = M::try_from_triplets(2, 2, indices, values, Default::default()).unwrap();
731 let mut b = M::zeros(2, 2, Default::default());
732 b.copy_from(&a);
733 let vals = triplet_values(&b);
734 assert_eq!(
735 vals,
736 vec![f::<M>(1.0), f::<M>(2.0), f::<M>(3.0), f::<M>(4.0)]
737 );
738 }
739
740 pub fn test_scale_add_and_assign<M: Matrix>() {
741 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
742 let x_vals = vec![f::<M>(1.0), f::<M>(2.0), f::<M>(3.0), f::<M>(4.0)];
743 let y_vals = vec![f::<M>(10.0), f::<M>(20.0), f::<M>(30.0), f::<M>(40.0)];
744 let x = M::try_from_triplets(2, 2, indices.clone(), x_vals, Default::default()).unwrap();
745 let y = M::try_from_triplets(2, 2, indices, y_vals, Default::default()).unwrap();
746 let mut result = M::zeros(2, 2, Default::default());
747 result.copy_from(&x);
748 result.scale_add_and_assign(&x, f::<M>(2.0), &y);
749 let vals = triplet_values(&result);
750 assert_eq!(
751 vals,
752 vec![f::<M>(21.0), f::<M>(42.0), f::<M>(63.0), f::<M>(84.0)]
753 );
754 }
755
756 pub fn test_sparsity_dense_errors<M: DenseMatrix>() {
762 assert!(M::Sparsity::try_from_indices(0, 3, vec![]).is_err());
763 let a = M::Sparsity::try_from_indices(2, 2, vec![]).unwrap();
764 let b = M::Sparsity::try_from_indices(3, 3, vec![]).unwrap();
765 assert!(a.union(b.as_ref()).is_err());
766 }
767
768 pub fn test_update_backward_diff<M: DenseMatrix>() {
773 let order = 1;
774 let mut a = M::from_vec(
775 2,
776 4,
777 vec![
778 f::<M>(1.0),
779 f::<M>(10.0),
780 f::<M>(2.0),
781 f::<M>(20.0),
782 f::<M>(3.0),
783 f::<M>(30.0),
784 f::<M>(0.0),
785 f::<M>(0.0),
786 ],
787 Default::default(),
788 );
789 let d = M::V::from_vec(vec![f::<M>(100.0), f::<M>(1000.0)], Default::default());
790
791 a.update_backward_diff(order, &d);
792
793 assert_eq!(a.get_index(0, 3), f::<M>(97.0));
794 assert_eq!(a.get_index(1, 3), f::<M>(970.0));
795 assert_eq!(a.get_index(0, 2), f::<M>(100.0));
796 assert_eq!(a.get_index(1, 2), f::<M>(1000.0));
797 assert_eq!(a.get_index(0, 1), f::<M>(102.0));
798 assert_eq!(a.get_index(1, 1), f::<M>(1020.0));
799 assert_eq!(a.get_index(0, 0), f::<M>(103.0));
800 assert_eq!(a.get_index(1, 0), f::<M>(1030.0));
801 }
802
803 fn rand_mat<M: DenseMatrix>(nrows: usize, ncols: usize, seed: f64) -> M {
806 let mut m = M::zeros(nrows, ncols, Default::default());
807 for j in 0..ncols {
808 let col = M::V::rand(nrows, seed * (j + 1) as f64, Default::default());
809 m.column_mut(j).copy_from(&col);
810 }
811 m
812 }
813
814 fn mat_dot<M: DenseMatrix>(a: &M, b: &M, cols: std::ops::Range<usize>) -> M::T {
816 cols.fold(M::T::zero(), |acc, j| {
817 acc + a.column(j).into_owned().dot(&b.column(j).into_owned())
818 })
819 }
820
821 fn assert_cols_eq<M: DenseMatrix>(a: &M, b: &M, cols: std::ops::Range<usize>) {
823 assert_eq!(a.nrows(), b.nrows());
824 for j in cols {
825 a.column(j)
826 .into_owned()
827 .assert_eq_st(&b.column(j).into_owned(), M::T::zero());
828 }
829 }
830
831 fn assert_mat_eq<M: DenseMatrix>(a: &M, b: &M) {
833 assert_eq!(a.ncols(), b.ncols());
834 assert_cols_eq(a, b, 0..a.ncols());
835 }
836
837 fn assert_close<M: Matrix>(a: M::T, b: M::T) {
838 use num_traits::Signed;
839 let scale = if a.abs() > b.abs() { a.abs() } else { b.abs() };
840 let tol = f::<M>(1e-4) * (M::T::one() + scale);
841 assert!((a - b).abs() <= tol, "{a} != {b}");
842 }
843
844 pub fn test_update_backward_diff_transpose<M: DenseMatrix>() {
849 let nrows = 3;
850 let ncols = MAX_SMALL_COLS;
851 for order in 1..=5 {
852 let d = M::V::rand(nrows, 0.7, Default::default());
853 let d_mat = rand_mat::<M>(nrows, ncols, 1.3);
854 let c0 = rand_mat::<M>(nrows, ncols, 2.9);
855
856 let mut u = d_mat.clone();
857 u.update_backward_diff(order, &d);
858 let lhs = mat_dot(&c0, &u, 0..ncols);
859
860 let mut c = c0.clone();
861 let mut d_bar = M::V::zeros(nrows, Default::default());
862 c.update_backward_diff_transpose(order, &mut d_bar);
863 let rhs = mat_dot(&c, &d_mat, 0..ncols) + d_bar.dot(&d);
864 assert_close::<M>(lhs, rhs);
865
866 assert_cols_eq(&c, &c0, order + 3..ncols);
867 }
868 }
869
870 pub fn test_mul_cols_by_transpose<M: DenseMatrix>() {
873 let nrows = 3;
874 let ncols = 5;
875 let ntot = 7;
876 let r = M::V::rand(ncols * ncols, 0.37, Default::default()).clone_as_vec();
877 let mut r_t = r.clone();
878 for j in 0..ncols {
879 for i in 0..ncols {
880 r_t[j * ncols + i] = r[i * ncols + j];
881 }
882 }
883 let d = rand_mat::<M>(nrows, ntot, 1.1);
884 let c = rand_mat::<M>(nrows, ntot, 2.3);
885
886 let mut a = d.clone();
887 let mut b = d.clone();
888 a.mul_cols_by_transpose(ncols, &r);
889 b.mul_cols_by(ncols, &r_t);
890 assert_mat_eq(&a, &b);
891
892 let mut dr = d.clone();
893 dr.mul_cols_by(ncols, &r);
894 let mut cr = c.clone();
895 cr.mul_cols_by_transpose(ncols, &r);
896 assert_close::<M>(mat_dot(&c, &dr, 0..ncols), mat_dot(&cr, &d, 0..ncols));
899 assert_cols_eq(&cr, &c, ncols..ntot);
900 }
901
902 pub fn test_ger_cols<M: DenseMatrix>() {
903 let mk = || {
905 M::from_vec(
906 2,
907 4,
908 (1..=4)
909 .flat_map(|j| [f::<M>(j as f64), f::<M>(10.0 * j as f64)])
910 .collect(),
911 Default::default(),
912 )
913 };
914 let y = M::V::from_vec(vec![f::<M>(1.0), f::<M>(-1.0)], Default::default());
915
916 let mut a = mk();
919 a.ger_cols(1, 3, f::<M>(2.0), &[f::<M>(3.0), f::<M>(5.0)], &y);
920 let expected = M::from_vec(
921 2,
922 4,
923 [1.0, 10.0, 8.0, 14.0, 13.0, 20.0, 4.0, 40.0]
924 .into_iter()
925 .map(f::<M>)
926 .collect(),
927 Default::default(),
928 );
929 assert_mat_eq(&a, &expected);
930
931 let mut a = mk();
933 a.ger_cols(2, 2, f::<M>(2.0), &[], &y);
934 assert_mat_eq(&a, &mk());
935 }
936
937 pub fn test_ger_cols_transpose<M: DenseMatrix>() {
940 let (nrows, ncols, start, end) = (3, 6, 1, 5);
941 let a = rand_mat::<M>(nrows, ncols, 0.9);
942 let y = M::V::rand(nrows, 1.7, Default::default());
943 let x = M::V::rand(end - start, 2.3, Default::default()).clone_as_vec();
944 let alpha = f::<M>(-0.6);
945
946 let mut update = M::zeros(nrows, ncols, Default::default());
947 update.ger_cols(start, end, alpha, &x, &y);
948 let mut ax = M::V::zeros(nrows, Default::default());
949 a.gemv_cols(start, end, alpha, &x, f::<M>(0.0), &mut ax);
950 assert_close::<M>(mat_dot(&update, &a, 0..ncols), y.dot(&ax));
951 }
952
953 pub fn test_gemv_cols<M: DenseMatrix>() {
954 let a = M::from_vec(
956 2,
957 4,
958 (1..=4)
959 .flat_map(|j| [f::<M>(j as f64), f::<M>(10.0 * j as f64)])
960 .collect(),
961 Default::default(),
962 );
963 let ones = |n: usize| vec![f::<M>(1.0); n];
964 let mut y = M::V::from_vec(vec![f::<M>(-1.0), f::<M>(-1.0)], Default::default());
965
966 a.gemv_cols(0, 3, f::<M>(1.0), &ones(3), f::<M>(0.0), &mut y);
968 assert_eq!(y.clone_as_vec(), vec![f::<M>(6.0), f::<M>(60.0)]);
969
970 let w4 = vec![f::<M>(1.0), f::<M>(2.0), f::<M>(3.0), f::<M>(4.0)];
972 a.gemv_cols(0, 4, f::<M>(1.0), &w4, f::<M>(0.0), &mut y);
973 assert_eq!(y.clone_as_vec(), vec![f::<M>(30.0), f::<M>(300.0)]);
974
975 let w23 = vec![f::<M>(2.0), f::<M>(3.0)];
977 a.gemv_cols(2, 4, f::<M>(1.0), &w23, f::<M>(0.0), &mut y);
978 assert_eq!(y.clone_as_vec(), vec![f::<M>(18.0), f::<M>(180.0)]);
979
980 a.gemv_cols(2, 4, f::<M>(2.0), &w23, f::<M>(0.0), &mut y);
982 assert_eq!(y.clone_as_vec(), vec![f::<M>(36.0), f::<M>(360.0)]);
983
984 let half = vec![f::<M>(0.5)];
986 a.gemv_cols(1, 2, f::<M>(1.0), &half, f::<M>(0.0), &mut y);
987 assert_eq!(y.clone_as_vec(), vec![f::<M>(1.0), f::<M>(10.0)]);
988 a.gemv_cols(1, 2, f::<M>(1.0), &half, f::<M>(1.0), &mut y);
989 assert_eq!(y.clone_as_vec(), vec![f::<M>(2.0), f::<M>(20.0)]);
990
991 a.gemv_cols(1, 2, f::<M>(1.0), &half, f::<M>(3.0), &mut y);
993 assert_eq!(y.clone_as_vec(), vec![f::<M>(7.0), f::<M>(70.0)]);
994
995 a.gemv_cols(1, 1, f::<M>(1.0), &ones(0), f::<M>(2.0), &mut y);
997 assert_eq!(y.clone_as_vec(), vec![f::<M>(14.0), f::<M>(140.0)]);
998 a.gemv_cols(1, 1, f::<M>(1.0), &ones(0), f::<M>(1.0), &mut y);
999 assert_eq!(y.clone_as_vec(), vec![f::<M>(14.0), f::<M>(140.0)]);
1000 a.gemv_cols(1, 1, f::<M>(1.0), &ones(0), f::<M>(0.0), &mut y);
1001 assert_eq!(y.clone_as_vec(), vec![f::<M>(0.0), f::<M>(0.0)]);
1002 }
1003
1004 fn mat_at<M: DenseMatrix>(m: &M, b: usize, i: usize, j: usize) -> M::T {
1009 m.column(j).into_owned().clone_as_vec()[b * m.nrows() + i]
1010 }
1011
1012 pub fn test_mul_cols_by<M: DenseMatrix>() {
1013 let mk = || {
1015 M::from_vec(
1016 2,
1017 4,
1018 (1..=4)
1019 .flat_map(|j| [f::<M>(j as f64), f::<M>(10.0 * j as f64)])
1020 .collect(),
1021 Default::default(),
1022 )
1023 };
1024 let untouched = mk();
1025
1026 let mut a = mk();
1029 a.mul_cols_by(2, &[f::<M>(1.0), f::<M>(0.0), f::<M>(0.0), f::<M>(1.0)]);
1030 assert_mat_eq(&a, &untouched);
1031
1032 let mut a = mk();
1034 a.mul_cols_by(0, &[]);
1035 assert_mat_eq(&a, &untouched);
1036
1037 let mut a = mk();
1039 a.mul_cols_by(1, &[f::<M>(3.0)]);
1040 let expected = M::from_vec(
1041 2,
1042 4,
1043 vec![
1044 f::<M>(3.0),
1045 f::<M>(30.0),
1046 f::<M>(2.0),
1047 f::<M>(20.0),
1048 f::<M>(3.0),
1049 f::<M>(30.0),
1050 f::<M>(4.0),
1051 f::<M>(40.0),
1052 ],
1053 Default::default(),
1054 );
1055 assert_mat_eq(&a, &expected);
1056
1057 let mut a = mk();
1063 a.mul_cols_by(2, &[f::<M>(1.0), f::<M>(3.0), f::<M>(2.0), f::<M>(4.0)]);
1064 let expected = M::from_vec(
1065 2,
1066 4,
1067 vec![
1068 f::<M>(7.0),
1069 f::<M>(70.0),
1070 f::<M>(10.0),
1071 f::<M>(100.0),
1072 f::<M>(3.0),
1073 f::<M>(30.0),
1074 f::<M>(4.0),
1075 f::<M>(40.0),
1076 ],
1077 Default::default(),
1078 );
1079 assert_mat_eq(&a, &expected);
1080
1081 let ncols = 6;
1083 let mut wide = M::from_vec(
1084 2,
1085 ncols,
1086 (1..=ncols)
1087 .flat_map(|j| [f::<M>(j as f64), f::<M>(10.0 * j as f64)])
1088 .collect(),
1089 Default::default(),
1090 );
1091 let wide_before = wide.clone();
1092 let mut id = vec![f::<M>(0.0); ncols * ncols];
1093 for j in 0..ncols {
1094 id[j * ncols + j] = f::<M>(1.0);
1095 }
1096 wide.mul_cols_by(ncols, &id);
1097 assert_mat_eq(&wide, &wide_before);
1098
1099 let nrows = 700;
1101 let mut tall = M::from_vec(
1102 nrows,
1103 2,
1104 (0..2 * nrows).map(|i| f::<M>(i as f64)).collect(),
1105 Default::default(),
1106 );
1107 tall.mul_cols_by(2, &[f::<M>(1.0), f::<M>(3.0), f::<M>(2.0), f::<M>(4.0)]);
1108 let c0 = |i: usize| f::<M>(i as f64);
1110 let c1 = |i: usize| f::<M>((nrows + i) as f64);
1111 let expected = M::from_vec(
1112 nrows,
1113 2,
1114 (0..nrows)
1115 .map(|i| c0(i) + f::<M>(3.0) * c1(i))
1116 .chain((0..nrows).map(|i| f::<M>(2.0) * c0(i) + f::<M>(4.0) * c1(i)))
1117 .collect(),
1118 Default::default(),
1119 );
1120 assert_mat_eq(&tall, &expected);
1121 }
1122
1123 pub fn test_fill<M: DenseMatrix>(ctx: M::C) {
1125 let (nrows, ncols) = (3, 4);
1126 let mut m = M::zeros(nrows, ncols, ctx.clone());
1127 for j in 0..ncols {
1128 let col = M::V::rand(nrows, (j + 1) as f64, ctx.clone());
1129 m.column_mut(j).copy_from(&col);
1130 }
1131 m.fill(f::<M>(2.5));
1132 assert_eq!((m.nrows(), m.ncols()), (nrows, ncols));
1133 let expected = M::V::from_element(nrows, f::<M>(2.5), ctx);
1134 for j in 0..ncols {
1135 m.column(j)
1136 .into_owned()
1137 .assert_eq_st(&expected, f::<M>(0.0));
1138 }
1139 }
1140
1141 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1144 pub fn test_batched_mul_cols_by<M: DenseMatrix>(ctx: M::C) {
1145 assert_eq!(ctx.nbatch(), 2);
1146 let mut a = M::from_vec(
1148 2,
1149 2,
1150 (1..=4)
1151 .flat_map(|j| [f::<M>(j as f64), f::<M>(10.0 * j as f64)])
1152 .collect(),
1153 ctx.clone(),
1154 );
1155 a.mul_cols_by(2, &[f::<M>(1.0), f::<M>(3.0), f::<M>(2.0), f::<M>(4.0)]);
1156 let expected = M::from_vec(
1159 2,
1160 2,
1161 [7.0, 70.0, 10.0, 100.0, 15.0, 150.0, 22.0, 220.0]
1162 .into_iter()
1163 .map(f::<M>)
1164 .collect(),
1165 ctx,
1166 );
1167 assert_mat_eq(&a, &expected);
1168 }
1169
1170 pub fn test_gemv_cols_many_columns<M: DenseMatrix>() {
1173 let ncols = MAX_SMALL_COLS;
1174 let a = M::from_vec(
1176 2,
1177 ncols,
1178 (1..=ncols)
1179 .flat_map(|j| [f::<M>(j as f64), f::<M>(10.0 * j as f64)])
1180 .collect(),
1181 Default::default(),
1182 );
1183 let x = vec![f::<M>(1.0); ncols];
1184 let mut y = M::V::from_vec(vec![f::<M>(-1.0), f::<M>(-1.0)], Default::default());
1185 a.gemv_cols(0, ncols, f::<M>(1.0), &x, f::<M>(0.0), &mut y);
1186 let total = f::<M>((ncols * (ncols + 1) / 2) as f64);
1188 assert_eq!(y.clone_as_vec(), vec![total, f::<M>(10.0) * total]);
1189 }
1190
1191 pub fn test_batched_ger_cols<M: DenseMatrix>(ctx: M::C) {
1193 assert_eq!(ctx.nbatch(), 2);
1194 let mut a = M::from_vec(
1196 2,
1197 2,
1198 (1..=4)
1199 .flat_map(|j| [f::<M>(j as f64), f::<M>(10.0 * j as f64)])
1200 .collect(),
1201 ctx.clone(),
1202 );
1203 let y = M::V::from_vec(
1205 vec![f::<M>(1.0), f::<M>(0.0), f::<M>(0.0), f::<M>(1.0)],
1206 ctx.clone(),
1207 );
1208 a.ger_cols(0, 2, f::<M>(1.0), &[f::<M>(2.0), f::<M>(3.0)], &y);
1209 let expected = M::from_vec(
1210 2,
1211 2,
1212 [3.0, 10.0, 5.0, 20.0, 3.0, 32.0, 4.0, 43.0]
1213 .into_iter()
1214 .map(f::<M>)
1215 .collect(),
1216 ctx,
1217 );
1218 assert_mat_eq(&a, &expected);
1219 }
1220
1221 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1224 pub fn test_batched_gemv_cols_m<M: DenseMatrix>(ctx: M::C) {
1225 assert_eq!(ctx.nbatch(), 2);
1226
1227 let a = M::from_vec(
1229 2,
1230 2,
1231 (1..=4)
1232 .flat_map(|j| [f::<M>(j as f64), f::<M>(10.0 * j as f64)])
1233 .collect(),
1234 ctx.clone(),
1235 );
1236 let mut y = M::V::from_vec(
1237 vec![f::<M>(-1.0), f::<M>(-1.0), f::<M>(-1.0), f::<M>(-1.0)],
1238 ctx,
1239 );
1240
1241 let ones = vec![f::<M>(1.0), f::<M>(1.0)];
1242 a.gemv_cols(0, 2, f::<M>(1.0), &ones, f::<M>(0.0), &mut y);
1243 assert_eq!(
1244 y.clone_as_vec(),
1245 vec![f::<M>(3.0), f::<M>(30.0), f::<M>(7.0), f::<M>(70.0)]
1246 );
1247
1248 let w23 = vec![f::<M>(2.0), f::<M>(3.0)];
1249 a.gemv_cols(0, 2, f::<M>(1.0), &w23, f::<M>(0.0), &mut y);
1250 assert_eq!(
1251 y.clone_as_vec(),
1252 vec![f::<M>(8.0), f::<M>(80.0), f::<M>(18.0), f::<M>(180.0)]
1253 );
1254
1255 let half = vec![f::<M>(0.5)];
1256 a.gemv_cols(1, 2, f::<M>(1.0), &half, f::<M>(0.0), &mut y);
1257 assert_eq!(
1258 y.clone_as_vec(),
1259 vec![f::<M>(1.0), f::<M>(10.0), f::<M>(2.0), f::<M>(20.0)]
1260 );
1261
1262 a.gemv_cols(1, 2, f::<M>(1.0), &half, f::<M>(1.0), &mut y);
1264 assert_eq!(
1265 y.clone_as_vec(),
1266 vec![f::<M>(2.0), f::<M>(20.0), f::<M>(4.0), f::<M>(40.0)]
1267 );
1268 }
1269
1270 pub fn test_resize_cols<M: DenseMatrix>() {
1271 let mut a = M::zeros(2, 2, Default::default());
1272 a.set_index(0, 0, M::T::one());
1273 a.set_index(0, 1, M::T::from_f64(2.0).unwrap());
1274 a.set_index(1, 0, M::T::from_f64(3.0).unwrap());
1275 a.set_index(1, 1, M::T::from_f64(4.0).unwrap());
1276
1277 a.resize_cols(2);
1279 assert_eq!(a.ncols(), 2);
1280 assert_eq!(a.get_index(0, 0), M::T::one());
1281
1282 a.resize_cols(3);
1283 assert_eq!(a.ncols(), 3);
1284 assert_eq!(a.nrows(), 2);
1285 assert_eq!(a.get_index(0, 0), M::T::one());
1286 assert_eq!(a.get_index(0, 1), M::T::from_f64(2.0).unwrap());
1287 assert_eq!(a.get_index(1, 0), M::T::from_f64(3.0).unwrap());
1288 assert_eq!(a.get_index(1, 1), M::T::from_f64(4.0).unwrap());
1289
1290 a.set_index(0, 2, M::T::from_f64(5.0).unwrap());
1291 a.set_index(1, 2, M::T::from_f64(6.0).unwrap());
1292 assert_eq!(a.get_index(0, 2), M::T::from_f64(5.0).unwrap());
1293 assert_eq!(a.get_index(1, 2), M::T::from_f64(6.0).unwrap());
1294
1295 a.resize_cols(2);
1296 assert_eq!(a.ncols(), 2);
1297 assert_eq!(a.nrows(), 2);
1298 assert_eq!(a.get_index(0, 0), M::T::one());
1299 assert_eq!(a.get_index(0, 1), M::T::from_f64(2.0).unwrap());
1300 assert_eq!(a.get_index(1, 0), M::T::from_f64(3.0).unwrap());
1301 assert_eq!(a.get_index(1, 1), M::T::from_f64(4.0).unwrap());
1302 }
1303
1304 pub fn test_from_vec<M: DenseMatrix>() {
1305 let a = M::from_vec(
1306 2,
1307 2,
1308 vec![f::<M>(1.0), f::<M>(3.0), f::<M>(2.0), f::<M>(4.0)],
1309 Default::default(),
1310 );
1311 assert_eq!(a.nrows(), 2);
1312 assert_eq!(a.ncols(), 2);
1313 assert_eq!(a.get_index(0, 0), f::<M>(1.0));
1314 assert_eq!(a.get_index(1, 0), f::<M>(3.0));
1315 assert_eq!(a.get_index(0, 1), f::<M>(2.0));
1316 assert_eq!(a.get_index(1, 1), f::<M>(4.0));
1317 }
1318
1319 pub fn test_column_view<M: DenseMatrix>() {
1320 let a = M::from_vec(
1321 2,
1322 2,
1323 vec![f::<M>(1.0), f::<M>(3.0), f::<M>(2.0), f::<M>(4.0)],
1324 Default::default(),
1325 );
1326 let col = a.column(1);
1327 use crate::VectorView;
1328 assert_eq!(col.get_index(0), f::<M>(2.0));
1329 assert_eq!(col.get_index(1), f::<M>(4.0));
1330 }
1331
1332 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1335 pub fn test_batched_zeros_m<M: Matrix>(ctx: M::C) {
1336 assert_eq!(ctx.nbatch(), 2);
1337 let a = M::zeros(2, 3, ctx);
1338 assert_eq!(a.nrows(), 2);
1339 assert_eq!(a.ncols(), 3);
1340 let vals = triplet_values(&a);
1341 assert!(vals.is_empty() || vals.iter().all(|v| v.is_zero()));
1342 }
1343
1344 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1345 pub fn test_batched_gemv_m<M: Matrix>(ctx: M::C) {
1346 assert_eq!(ctx.nbatch(), 2);
1347 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
1348 let values = vec![
1349 f::<M>(1.0),
1350 f::<M>(3.0),
1351 f::<M>(2.0),
1352 f::<M>(4.0), f::<M>(5.0),
1354 f::<M>(7.0),
1355 f::<M>(6.0),
1356 f::<M>(8.0), ];
1358 let a = M::try_from_triplets(2, 2, indices, values, ctx.clone()).unwrap();
1359 let x = M::V::from_vec(
1360 vec![f::<M>(1.0), f::<M>(2.0), f::<M>(1.0), f::<M>(1.0)],
1361 ctx.clone(),
1362 );
1363 let mut y = M::V::zeros(2, ctx);
1364 a.gemv(f::<M>(1.0), &x, f::<M>(0.0), &mut y);
1365 assert_eq!(
1366 y.clone_as_vec(),
1367 vec![f::<M>(5.0), f::<M>(11.0), f::<M>(11.0), f::<M>(15.0)]
1368 );
1369 }
1370
1371 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1372 pub fn test_batched_gemv_broadcast_x_m<M: Matrix>(ctx: M::C) {
1373 assert_eq!(ctx.nbatch(), 2);
1374 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
1375 let values = vec![
1376 f::<M>(1.0),
1377 f::<M>(3.0),
1378 f::<M>(2.0),
1379 f::<M>(4.0),
1380 f::<M>(5.0),
1381 f::<M>(7.0),
1382 f::<M>(6.0),
1383 f::<M>(8.0),
1384 ];
1385 let a = M::try_from_triplets(2, 2, indices, values, ctx.clone()).unwrap();
1386 let x = M::V::from_vec(vec![f::<M>(1.0), f::<M>(2.0)], Default::default());
1387 let mut y = M::V::zeros(2, ctx);
1388 a.gemv(f::<M>(1.0), &x, f::<M>(0.0), &mut y);
1389 assert_eq!(
1390 y.clone_as_vec(),
1391 vec![f::<M>(5.0), f::<M>(11.0), f::<M>(17.0), f::<M>(23.0)]
1392 );
1393 }
1394
1395 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1396 pub fn test_batched_gemv_broadcast_mat_m<M: Matrix>(ctx: M::C) {
1397 assert_eq!(ctx.nbatch(), 2);
1398 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
1399 let values = vec![f::<M>(1.0), f::<M>(3.0), f::<M>(2.0), f::<M>(4.0)];
1400 let a =
1401 M::try_from_triplets(2, 2, indices, values, ctx.clone_with_nbatch(1).unwrap()).unwrap();
1402 let x = M::V::from_vec(
1403 vec![f::<M>(1.0), f::<M>(2.0), f::<M>(3.0), f::<M>(4.0)],
1404 ctx.clone(),
1405 );
1406 let mut y = M::V::zeros(2, ctx);
1407 a.gemv(f::<M>(1.0), &x, f::<M>(0.0), &mut y);
1408 assert_eq!(
1409 y.clone_as_vec(),
1410 vec![f::<M>(5.0), f::<M>(11.0), f::<M>(11.0), f::<M>(25.0)]
1411 );
1412 }
1413
1414 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1415 pub fn test_batched_from_diagonal_m<M: Matrix>(ctx: M::C) {
1416 assert_eq!(ctx.nbatch(), 2);
1417 let v = M::V::from_vec(
1418 vec![f::<M>(2.0), f::<M>(3.0), f::<M>(4.0), f::<M>(5.0)],
1419 ctx,
1420 );
1421 let a = M::from_diagonal(&v);
1422 assert_eq!(a.nrows(), 2);
1423 assert_eq!(a.ncols(), 2);
1424 let idx = triplet_indices(&a);
1425 let vals = triplet_values(&a);
1426 for &(i, j) in &idx {
1427 let pos = idx.iter().position(|&x| x == (i, j)).unwrap();
1428 if i == j {
1429 assert!(
1430 vals[pos] != M::T::zero(),
1431 "diagonal entry should be non-zero"
1432 );
1433 } else {
1434 assert!(vals[pos].is_zero(), "off-diagonal entry should be zero");
1435 }
1436 }
1437 }
1438
1439 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1440 pub fn test_batched_copy_from_m<M: Matrix>(ctx: M::C) {
1441 assert_eq!(ctx.nbatch(), 2);
1442 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
1443 let values = vec![
1444 f::<M>(1.0),
1445 f::<M>(2.0),
1446 f::<M>(3.0),
1447 f::<M>(4.0),
1448 f::<M>(5.0),
1449 f::<M>(6.0),
1450 f::<M>(7.0),
1451 f::<M>(8.0),
1452 ];
1453 let a = M::try_from_triplets(2, 2, indices, values, ctx.clone()).unwrap();
1454 let mut b = M::zeros(2, 2, ctx);
1455 b.copy_from(&a);
1456 let vals = triplet_values(&b);
1457 assert_eq!(
1458 vals,
1459 vec![
1460 f::<M>(1.0),
1461 f::<M>(2.0),
1462 f::<M>(3.0),
1463 f::<M>(4.0),
1464 f::<M>(5.0),
1465 f::<M>(6.0),
1466 f::<M>(7.0),
1467 f::<M>(8.0),
1468 ]
1469 );
1470 }
1471
1472 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1475 pub fn test_batched_copy_from_broadcast_m<M: Matrix>(ctx: M::C) {
1476 assert_eq!(ctx.nbatch(), 2);
1477 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
1478 let values = vec![f::<M>(1.0), f::<M>(2.0), f::<M>(3.0), f::<M>(4.0)];
1479 let a = M::try_from_triplets(2, 2, indices, values, M::C::default()).unwrap();
1480 let mut b = M::zeros(2, 2, ctx);
1481 b.copy_from(&a);
1482 let vals = triplet_values(&b);
1483 assert_eq!(
1484 vals,
1485 vec![
1486 f::<M>(1.0),
1487 f::<M>(2.0),
1488 f::<M>(3.0),
1489 f::<M>(4.0),
1490 f::<M>(1.0),
1491 f::<M>(2.0),
1492 f::<M>(3.0),
1493 f::<M>(4.0),
1494 ]
1495 );
1496 }
1497
1498 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1499 pub fn test_batched_set_column_m<M: Matrix>(ctx: M::C) {
1500 assert_eq!(ctx.nbatch(), 2);
1501 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
1502 let values = vec![
1503 f::<M>(0.0),
1504 f::<M>(0.0),
1505 f::<M>(0.0),
1506 f::<M>(0.0),
1507 f::<M>(0.0),
1508 f::<M>(0.0),
1509 f::<M>(0.0),
1510 f::<M>(0.0),
1511 ];
1512 let mut a = M::try_from_triplets(2, 2, indices, values, ctx.clone()).unwrap();
1513 let v = M::V::from_vec(
1514 vec![f::<M>(5.0), f::<M>(6.0), f::<M>(7.0), f::<M>(8.0)],
1515 ctx,
1516 );
1517 a.set_column(0, &v);
1518 let vals = triplet_values(&a);
1519 assert_eq!(
1520 vals,
1521 vec![
1522 f::<M>(5.0),
1523 f::<M>(6.0),
1524 f::<M>(0.0),
1525 f::<M>(0.0),
1526 f::<M>(7.0),
1527 f::<M>(8.0),
1528 f::<M>(0.0),
1529 f::<M>(0.0),
1530 ]
1531 );
1532 }
1533
1534 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1535 pub fn test_batched_scale_add_and_assign_m<M: Matrix>(ctx: M::C) {
1536 assert_eq!(ctx.nbatch(), 2);
1537 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
1538 let x_vals = vec![
1539 f::<M>(1.0),
1540 f::<M>(2.0),
1541 f::<M>(3.0),
1542 f::<M>(4.0),
1543 f::<M>(5.0),
1544 f::<M>(6.0),
1545 f::<M>(7.0),
1546 f::<M>(8.0),
1547 ];
1548 let y_vals = vec![
1549 f::<M>(10.0),
1550 f::<M>(20.0),
1551 f::<M>(30.0),
1552 f::<M>(40.0),
1553 f::<M>(50.0),
1554 f::<M>(60.0),
1555 f::<M>(70.0),
1556 f::<M>(80.0),
1557 ];
1558 let x = M::try_from_triplets(2, 2, indices.clone(), x_vals, ctx.clone()).unwrap();
1559 let y = M::try_from_triplets(2, 2, indices, y_vals, ctx.clone()).unwrap();
1560 let mut result = M::zeros(2, 2, ctx);
1561 result.copy_from(&x);
1562 result.scale_add_and_assign(&x, f::<M>(2.0), &y);
1563 let vals = triplet_values(&result);
1564 assert_eq!(
1565 vals,
1566 vec![
1567 f::<M>(21.0),
1568 f::<M>(42.0),
1569 f::<M>(63.0),
1570 f::<M>(84.0),
1571 f::<M>(105.0),
1572 f::<M>(126.0),
1573 f::<M>(147.0),
1574 f::<M>(168.0),
1575 ]
1576 );
1577 }
1578
1579 pub fn test_owned_rhs_m<M>()
1584 where
1585 M: DenseMatrix,
1586 for<'a> &'a M: Add<M, Output = M> + Sub<M, Output = M>,
1587 {
1588 let values = vec![f::<M>(1.0), f::<M>(3.0), f::<M>(2.0), f::<M>(4.0)];
1589 let a = M::from_vec(
1590 2,
1591 2,
1592 vec![f::<M>(10.0), f::<M>(30.0), f::<M>(20.0), f::<M>(40.0)],
1593 Default::default(),
1594 );
1595
1596 let b = M::from_vec(2, 2, values.clone(), Default::default());
1597 let c = &a - b;
1598 assert_eq!(c.get_index(0, 0), f::<M>(9.0));
1599 assert_eq!(c.get_index(1, 1), f::<M>(36.0));
1600
1601 let b = M::from_vec(2, 2, values, Default::default());
1602 let c = &a + b;
1603 assert_eq!(c.get_index(0, 0), f::<M>(11.0));
1604 assert_eq!(c.get_index(1, 1), f::<M>(44.0));
1605 }
1606
1607 pub fn test_batched_owned_rhs_broadcast_m<M>(ctx: M::C)
1610 where
1611 M: Matrix + DenseMatrix,
1612 for<'a> &'a M: Sub<M, Output = M>,
1613 {
1614 assert_eq!(ctx.nbatch(), 2);
1615 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
1616 let one_batch = vec![f::<M>(1.0), f::<M>(2.0), f::<M>(3.0), f::<M>(4.0)];
1617 let two_batches = vec![
1618 f::<M>(10.0),
1619 f::<M>(20.0),
1620 f::<M>(30.0),
1621 f::<M>(40.0),
1622 f::<M>(50.0),
1623 f::<M>(60.0),
1624 f::<M>(70.0),
1625 f::<M>(80.0),
1626 ];
1627
1628 let a = M::try_from_triplets(2, 2, indices.clone(), one_batch.clone(), M::C::default())
1630 .unwrap();
1631 let b =
1632 M::try_from_triplets(2, 2, indices.clone(), two_batches.clone(), ctx.clone()).unwrap();
1633 let c = &a - b;
1634 assert_eq!(c.context().nbatch(), 2);
1635 assert_eq!(
1636 triplet_values(&c),
1637 vec![
1638 f::<M>(-9.0),
1639 f::<M>(-18.0),
1640 f::<M>(-27.0),
1641 f::<M>(-36.0),
1642 f::<M>(-49.0),
1643 f::<M>(-58.0),
1644 f::<M>(-67.0),
1645 f::<M>(-76.0),
1646 ]
1647 );
1648 }
1649
1650 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1652 pub fn test_batched_owned_rhs_narrow_m<M>(ctx: M::C)
1653 where
1654 M: Matrix + DenseMatrix,
1655 for<'a> &'a M: Sub<M, Output = M>,
1656 {
1657 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
1658 let wide = (1..=8).map(|i| f::<M>(i as f64)).collect::<Vec<_>>();
1659 let narrow = (1..=4).map(|i| f::<M>(i as f64)).collect::<Vec<_>>();
1660 let a = M::try_from_triplets(2, 2, indices.clone(), wide, ctx).unwrap();
1661 let b = M::try_from_triplets(2, 2, indices, narrow, M::C::default()).unwrap();
1662 let _ = &a - b;
1663 }
1664
1665 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1667 pub fn test_batched_owned_lhs_broadcast_m<M>(ctx: M::C)
1668 where
1669 M: Matrix + for<'a> Sub<&'a M, Output = M>,
1670 {
1671 assert_eq!(ctx.nbatch(), 2);
1672 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
1673 let one_batch = vec![f::<M>(1.0), f::<M>(2.0), f::<M>(3.0), f::<M>(4.0)];
1674 let two_batches = vec![
1675 f::<M>(10.0),
1676 f::<M>(20.0),
1677 f::<M>(30.0),
1678 f::<M>(40.0),
1679 f::<M>(50.0),
1680 f::<M>(60.0),
1681 f::<M>(70.0),
1682 f::<M>(80.0),
1683 ];
1684
1685 let a =
1687 M::try_from_triplets(2, 2, indices.clone(), two_batches.clone(), ctx.clone()).unwrap();
1688 let b = M::try_from_triplets(2, 2, indices.clone(), one_batch.clone(), M::C::default())
1689 .unwrap();
1690 let c = a - &b;
1691 assert_eq!(c.context().nbatch(), 2);
1692 assert_eq!(
1693 triplet_values(&c),
1694 vec![
1695 f::<M>(9.0),
1696 f::<M>(18.0),
1697 f::<M>(27.0),
1698 f::<M>(36.0),
1699 f::<M>(49.0),
1700 f::<M>(58.0),
1701 f::<M>(67.0),
1702 f::<M>(76.0),
1703 ]
1704 );
1705 }
1706
1707 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1709 pub fn test_batched_owned_lhs_narrow_m<M>(ctx: M::C)
1710 where
1711 M: Matrix + for<'a> Sub<&'a M, Output = M>,
1712 {
1713 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
1714 let narrow = (1..=4).map(|i| f::<M>(i as f64)).collect::<Vec<_>>();
1715 let wide = (1..=8).map(|i| f::<M>(10.0 * i as f64)).collect::<Vec<_>>();
1716 let a = M::try_from_triplets(2, 2, indices.clone(), narrow, M::C::default()).unwrap();
1717 let b = M::try_from_triplets(2, 2, indices, wide, ctx).unwrap();
1718 let _ = a - &b;
1719 }
1720
1721 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1722 pub fn test_batched_scale_add_and_assign_broadcast_m<M: Matrix>(ctx: M::C) {
1723 assert_eq!(ctx.nbatch(), 2);
1724 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
1725 let x_vals = vec![f::<M>(1.0), f::<M>(2.0), f::<M>(3.0), f::<M>(4.0)];
1726 let y_vals = vec![f::<M>(10.0), f::<M>(20.0), f::<M>(30.0), f::<M>(40.0)];
1727 let x =
1729 M::try_from_triplets(2, 2, indices.clone(), x_vals.clone(), M::C::default()).unwrap();
1730 let y = M::try_from_triplets(2, 2, indices.clone(), y_vals, M::C::default()).unwrap();
1731 let mut result_vals = x_vals.clone();
1733 result_vals.extend(x_vals);
1734 let mut result = M::try_from_triplets(2, 2, indices, result_vals, ctx).unwrap();
1735 result.scale_add_and_assign(&x, f::<M>(2.0), &y);
1736 let vals = triplet_values(&result);
1737 assert_eq!(
1738 vals,
1739 vec![
1740 f::<M>(21.0),
1741 f::<M>(42.0),
1742 f::<M>(63.0),
1743 f::<M>(84.0),
1744 f::<M>(21.0),
1745 f::<M>(42.0),
1746 f::<M>(63.0),
1747 f::<M>(84.0),
1748 ]
1749 );
1750 }
1751
1752 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1755 pub fn test_batched_mul_scalar_ref_m<M>(ctx: M::C)
1756 where
1757 M: Matrix,
1758 for<'a> &'a M: Mul<Scale<M::T>, Output = M>,
1759 {
1760 assert_eq!(ctx.nbatch(), 2);
1761 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
1762 let values = (1..=8).map(|i| f::<M>(i as f64)).collect::<Vec<_>>();
1763 let a = M::try_from_triplets(2, 2, indices, values, ctx).unwrap();
1764 let result = &a * Scale(f::<M>(2.0));
1765 assert_eq!(result.context().nbatch(), 2);
1766 assert_eq!(
1767 triplet_values(&result),
1768 (1..=8).map(|i| f::<M>(2.0 * i as f64)).collect::<Vec<_>>()
1769 );
1770 }
1771
1772 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1775 pub fn test_batched_add_assign_broadcast_m<M: DenseMatrix>(ctx: M::C) {
1776 assert_eq!(ctx.nbatch(), 2);
1777 let mut a = M::from_vec(
1778 2,
1779 2,
1780 (1..=8).map(|i| f::<M>(i as f64)).collect(),
1781 ctx.clone(),
1782 );
1783 let b = M::from_vec(
1784 2,
1785 2,
1786 (1..=4).map(|i| f::<M>(10.0 * i as f64)).collect(),
1787 M::C::default(),
1788 );
1789 a += &b;
1790 let expected = (1..=4)
1792 .map(|i| f::<M>(i as f64 + 10.0 * i as f64))
1793 .chain((5..=8).map(|i| f::<M>(i as f64 + 10.0 * (i - 4) as f64)))
1794 .collect::<Vec<_>>();
1795 assert_eq!(triplet_values(&a), expected);
1796 }
1797
1798 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1801 pub fn test_batched_owned_lhs_add_broadcast_m<M>(ctx: M::C)
1802 where
1803 M: Matrix + for<'a> Add<&'a M, Output = M>,
1804 {
1805 assert_eq!(ctx.nbatch(), 2);
1806 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
1807 let narrow = M::try_from_triplets(
1808 2,
1809 2,
1810 indices.clone(),
1811 (1..=4).map(|i| f::<M>(i as f64)).collect(),
1812 M::C::default(),
1813 )
1814 .unwrap();
1815 let wide = M::try_from_triplets(
1816 2,
1817 2,
1818 indices,
1819 (1..=8).map(|i| f::<M>(10.0 * i as f64)).collect(),
1820 ctx,
1821 )
1822 .unwrap();
1823 let c = wide + &narrow;
1825 assert_eq!(c.context().nbatch(), 2);
1826 let expected = (1..=4)
1827 .map(|i| f::<M>(10.0 * i as f64 + i as f64))
1828 .chain((5..=8).map(|i| f::<M>(10.0 * i as f64 + (i - 4) as f64)))
1829 .collect::<Vec<_>>();
1830 assert_eq!(triplet_values(&c), expected);
1831 }
1832
1833 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1836 pub fn test_batched_gemv_beta_m<M: Matrix>(ctx: M::C) {
1837 assert_eq!(ctx.nbatch(), 2);
1838 let indices = vec![(0, 0), (1, 1)];
1840 let values = vec![f::<M>(1.0), f::<M>(1.0), f::<M>(2.0), f::<M>(2.0)];
1841 let a = M::try_from_triplets(2, 2, indices, values, ctx.clone()).unwrap();
1842 let x = M::V::from_vec(
1843 vec![f::<M>(1.0), f::<M>(2.0), f::<M>(3.0), f::<M>(4.0)],
1844 ctx.clone(),
1845 );
1846 let mut y = M::V::from_vec(
1847 vec![f::<M>(1.0), f::<M>(1.0), f::<M>(1.0), f::<M>(1.0)],
1848 ctx,
1849 );
1850 a.gemv(f::<M>(1.0), &x, f::<M>(2.0), &mut y);
1852 assert_eq!(
1853 y.clone_as_vec(),
1854 vec![f::<M>(3.0), f::<M>(4.0), f::<M>(8.0), f::<M>(10.0)]
1855 );
1856 }
1857
1858 fn ctx4<M: Matrix>(ctx2: &M::C) -> M::C {
1865 assert_eq!(ctx2.nbatch(), 2);
1866 ctx2.clone_with_nbatch(4).unwrap()
1867 }
1868
1869 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1872 pub fn test_grouped_gemv_m<M: Matrix>(ctx2: M::C) {
1873 let wide = ctx4::<M>(&ctx2);
1874 let indices = vec![(0, 0), (1, 1)];
1876 let values = vec![f::<M>(1.0), f::<M>(1.0), f::<M>(2.0), f::<M>(2.0)];
1877 let a = M::try_from_triplets(2, 2, indices, values, ctx2).unwrap();
1878 let x = M::V::from_vec((1..=8).map(|i| f::<M>(i as f64)).collect(), wide.clone());
1879 let mut y = M::V::zeros(2, wide);
1880 a.gemv(f::<M>(1.0), &x, f::<M>(0.0), &mut y);
1881 assert_eq!(
1882 y.clone_as_vec(),
1883 vec![
1884 f::<M>(1.0),
1885 f::<M>(2.0),
1886 f::<M>(3.0),
1887 f::<M>(4.0),
1888 f::<M>(10.0),
1889 f::<M>(12.0),
1890 f::<M>(14.0),
1891 f::<M>(16.0),
1892 ]
1893 );
1894 }
1895
1896 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1900 pub fn test_grouped_gemv_x_m<M: Matrix>(ctx2: M::C) {
1901 let wide = ctx4::<M>(&ctx2);
1902 let indices = vec![(0, 0), (1, 1)];
1904 let values = (1..=4).flat_map(|i| [f::<M>(i as f64); 2]).collect();
1905 let a = M::try_from_triplets(2, 2, indices, values, wide.clone()).unwrap();
1906 let x = M::V::from_vec((1..=4).map(|i| f::<M>(i as f64)).collect(), ctx2);
1907 let mut y = M::V::zeros(2, wide);
1908 a.gemv(f::<M>(1.0), &x, f::<M>(0.0), &mut y);
1909 assert_eq!(
1910 y.clone_as_vec(),
1911 vec![
1912 f::<M>(1.0),
1913 f::<M>(2.0),
1914 f::<M>(2.0),
1915 f::<M>(4.0),
1916 f::<M>(9.0),
1917 f::<M>(12.0),
1918 f::<M>(12.0),
1919 f::<M>(16.0),
1920 ]
1921 );
1922 }
1923
1924 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1925 pub fn test_grouped_copy_from_m<M: Matrix>(ctx2: M::C) {
1926 let wide = ctx4::<M>(&ctx2);
1927 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
1928 let values = (1..=8).map(|i| f::<M>(i as f64)).collect::<Vec<_>>();
1929 let a = M::try_from_triplets(2, 2, indices, values, ctx2).unwrap();
1930 let mut b = M::zeros(2, 2, wide);
1931 b.copy_from(&a);
1932 let group0 = (1..=4).map(|i| f::<M>(i as f64));
1933 let group1 = (5..=8).map(|i| f::<M>(i as f64));
1934 let expected = group0
1935 .clone()
1936 .chain(group0)
1937 .chain(group1.clone())
1938 .chain(group1)
1939 .collect::<Vec<_>>();
1940 assert_eq!(triplet_values(&b), expected);
1941 }
1942
1943 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1944 pub fn test_grouped_scale_add_and_assign_m<M: Matrix>(ctx2: M::C) {
1945 let wide = ctx4::<M>(&ctx2);
1946 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
1947 let x_vals = (1..=8).map(|i| f::<M>(i as f64)).collect::<Vec<_>>();
1948 let y_vals = (1..=8).map(|i| f::<M>(10.0 * i as f64)).collect::<Vec<_>>();
1949 let x = M::try_from_triplets(2, 2, indices.clone(), x_vals, ctx2.clone()).unwrap();
1950 let y = M::try_from_triplets(2, 2, indices.clone(), y_vals, ctx2).unwrap();
1951 let dst_vals = (0..16).map(|_| f::<M>(0.0)).collect::<Vec<_>>();
1953 let mut result = M::try_from_triplets(2, 2, indices, dst_vals, wide).unwrap();
1954 result.scale_add_and_assign(&x, f::<M>(2.0), &y);
1955 let group0 = (1..=4).map(|i| f::<M>(21.0 * i as f64));
1957 let group1 = (5..=8).map(|i| f::<M>(21.0 * i as f64));
1958 let expected = group0
1959 .clone()
1960 .chain(group0)
1961 .chain(group1.clone())
1962 .chain(group1)
1963 .collect::<Vec<_>>();
1964 assert_eq!(triplet_values(&result), expected);
1965 }
1966
1967 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1969 pub fn test_grouped_add_assign_m<M: DenseMatrix>(ctx2: M::C) {
1970 let wide = ctx4::<M>(&ctx2);
1971 let mut a = M::from_vec(2, 2, (0..16).map(|_| f::<M>(0.0)).collect(), wide);
1972 let b = M::from_vec(2, 2, (1..=8).map(|i| f::<M>(i as f64)).collect(), ctx2);
1973 a += &b;
1974 let group0 = (1..=4).map(|i| f::<M>(i as f64));
1975 let group1 = (5..=8).map(|i| f::<M>(i as f64));
1976 let expected = group0
1977 .clone()
1978 .chain(group0)
1979 .chain(group1.clone())
1980 .chain(group1)
1981 .collect::<Vec<_>>();
1982 assert_eq!(triplet_values(&a), expected);
1983 }
1984
1985 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
1987 pub fn test_grouped_owned_lhs_add_m<M>(ctx2: M::C)
1988 where
1989 M: Matrix + for<'a> Add<&'a M, Output = M>,
1990 {
1991 let wide_ctx = ctx4::<M>(&ctx2);
1992 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
1993 let narrow = M::try_from_triplets(
1994 2,
1995 2,
1996 indices.clone(),
1997 (1..=8).map(|i| f::<M>(i as f64)).collect(),
1998 ctx2,
1999 )
2000 .unwrap();
2001 let wide = M::try_from_triplets(
2002 2,
2003 2,
2004 indices,
2005 (0..16).map(|_| f::<M>(0.0)).collect(),
2006 wide_ctx,
2007 )
2008 .unwrap();
2009 let c = wide + &narrow;
2012 assert_eq!(c.context().nbatch(), 4);
2013 let group0 = (1..=4).map(|i| f::<M>(i as f64));
2014 let group1 = (5..=8).map(|i| f::<M>(i as f64));
2015 let expected = group0
2016 .clone()
2017 .chain(group0)
2018 .chain(group1.clone())
2019 .chain(group1)
2020 .collect::<Vec<_>>();
2021 assert_eq!(triplet_values(&c), expected);
2022 }
2023
2024 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
2026 pub fn test_grouped_owned_lhs_narrow_m<M>(ctx2: M::C)
2027 where
2028 M: Matrix + for<'a> Add<&'a M, Output = M>,
2029 {
2030 let wide_ctx = ctx4::<M>(&ctx2);
2031 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
2032 let narrow = M::try_from_triplets(
2033 2,
2034 2,
2035 indices.clone(),
2036 (1..=8).map(|i| f::<M>(i as f64)).collect(),
2037 ctx2,
2038 )
2039 .unwrap();
2040 let wide = M::try_from_triplets(
2041 2,
2042 2,
2043 indices,
2044 (0..16).map(|_| f::<M>(0.0)).collect(),
2045 wide_ctx,
2046 )
2047 .unwrap();
2048 let _ = narrow + &wide;
2049 }
2050
2051 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
2054 pub fn test_narrow_dest_gemv_m<M: Matrix>(ctx2: M::C) {
2055 let wide = ctx4::<M>(&ctx2);
2056 let indices = vec![(0, 0), (1, 1)];
2057 let values = (1..=8).map(|i| f::<M>(i as f64)).collect::<Vec<_>>();
2058 let a = M::try_from_triplets(2, 2, indices, values, wide.clone()).unwrap();
2059 let x = M::V::zeros(2, wide);
2060 let mut y = M::V::zeros(2, ctx2);
2061 a.gemv(f::<M>(1.0), &x, f::<M>(0.0), &mut y);
2062 }
2063
2064 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
2065 pub fn test_narrow_dest_copy_from_m<M: Matrix>(ctx2: M::C) {
2066 let wide = ctx4::<M>(&ctx2);
2067 let indices = vec![(0, 0), (1, 1)];
2068 let values = (1..=8).map(|i| f::<M>(i as f64)).collect::<Vec<_>>();
2069 let a = M::try_from_triplets(2, 2, indices, values, wide).unwrap();
2070 let mut b = M::zeros(2, 2, ctx2);
2071 b.copy_from(&a);
2072 }
2073
2074 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
2075 pub fn test_narrow_dest_scale_add_m<M: Matrix>(ctx2: M::C) {
2076 let wide = ctx4::<M>(&ctx2);
2077 let indices = vec![(0, 0), (1, 1)];
2078 let vals = (1..=8).map(|i| f::<M>(i as f64)).collect::<Vec<_>>();
2079 let x = M::try_from_triplets(2, 2, indices.clone(), vals.clone(), wide.clone()).unwrap();
2080 let y = M::try_from_triplets(2, 2, indices.clone(), vals, wide).unwrap();
2081 let dst = (1..=4).map(|i| f::<M>(i as f64)).collect::<Vec<_>>();
2082 let mut result = M::try_from_triplets(2, 2, indices, dst, ctx2).unwrap();
2083 result.scale_add_and_assign(&x, f::<M>(2.0), &y);
2084 }
2085
2086 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
2087 pub fn test_narrow_dest_gather_m<M: Matrix>(ctx2: M::C) {
2088 let wide = ctx4::<M>(&ctx2);
2089 let indices = vec![(0, 0), (1, 1)];
2090 let values = (1..=8).map(|i| f::<M>(i as f64)).collect::<Vec<_>>();
2091 let src = M::try_from_triplets(2, 2, indices.clone(), values, wide).unwrap();
2092 let zeros = (0..4).map(|_| f::<M>(0.0)).collect::<Vec<_>>();
2093 let mut dst = M::try_from_triplets(2, 2, indices, zeros, ctx2).unwrap();
2094 let gather_indices = <M::V as Vector>::Index::from_vec(vec![0, 1], Default::default());
2095 dst.gather(&src, &gather_indices);
2096 }
2097
2098 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
2099 pub fn test_narrow_dest_set_data_with_indices_m<M: Matrix>(ctx2: M::C) {
2100 let wide = ctx4::<M>(&ctx2);
2101 let indices = vec![(0, 0), (1, 1)];
2102 let zeros = (0..4).map(|_| f::<M>(0.0)).collect::<Vec<_>>();
2103 let mut mat = M::try_from_triplets(2, 2, indices, zeros, ctx2).unwrap();
2104 let dst_indices = <M::V as Vector>::Index::from_vec(vec![0, 1], Default::default());
2105 let src_indices = <M::V as Vector>::Index::from_vec(vec![0, 1], Default::default());
2106 let data = M::V::from_vec((1..=8).map(|i| f::<M>(i as f64)).collect(), wide);
2107 mat.set_data_with_indices(&dst_indices, &src_indices, &data);
2108 }
2109
2110 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
2111 pub fn test_narrow_dest_add_assign_m<M: DenseMatrix>(ctx2: M::C) {
2112 let wide = ctx4::<M>(&ctx2);
2113 let src = M::from_vec(2, 2, (0..16).map(|_| f::<M>(1.0)).collect(), wide);
2114 let mut dst = M::zeros(2, 2, ctx2);
2115 dst += &src;
2116 }
2117
2118 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
2119 pub fn test_narrow_dest_gemv_cols_m<M: DenseMatrix>(ctx2: M::C) {
2120 let wide = ctx4::<M>(&ctx2);
2121 let a = M::from_vec(2, 2, (0..16).map(|_| f::<M>(1.0)).collect(), wide);
2122 let mut y = M::V::zeros(2, ctx2);
2123 let ones = vec![f::<M>(1.0), f::<M>(1.0)];
2124 a.gemv_cols(0, 2, f::<M>(1.0), &ones, f::<M>(0.0), &mut y);
2125 }
2126
2127 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
2129 pub fn test_grouped_gemv_cols_m<M: DenseMatrix>(ctx2: M::C) {
2130 let wide = ctx4::<M>(&ctx2);
2131 let a = M::from_vec(
2133 2,
2134 2,
2135 vec![
2136 f::<M>(1.0),
2137 f::<M>(1.0),
2138 f::<M>(0.0),
2139 f::<M>(0.0),
2140 f::<M>(2.0),
2141 f::<M>(2.0),
2142 f::<M>(0.0),
2143 f::<M>(0.0),
2144 ],
2145 ctx2,
2146 );
2147 let mut y = M::V::zeros(2, wide);
2148 let ones = vec![f::<M>(1.0), f::<M>(1.0)];
2149 a.gemv_cols(0, 2, f::<M>(1.0), &ones, f::<M>(0.0), &mut y);
2150 assert_eq!(
2151 y.clone_as_vec(),
2152 vec![
2153 f::<M>(1.0),
2154 f::<M>(1.0),
2155 f::<M>(1.0),
2156 f::<M>(1.0),
2157 f::<M>(2.0),
2158 f::<M>(2.0),
2159 f::<M>(2.0),
2160 f::<M>(2.0),
2161 ]
2162 );
2163 }
2164
2165 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
2168 pub fn test_batched_set_index_batch<M: DenseMatrix>(ctx: M::C) {
2169 assert_eq!(ctx.nbatch(), 2);
2170 let mut a = M::zeros(2, 2, ctx);
2172 let val = |b: usize, i: usize, j: usize| f::<M>((100 * b + 10 * i + j) as f64);
2173 for b in 0..2 {
2174 for i in 0..2 {
2175 for j in 0..2 {
2176 a.set_index_batch(b, i, j, val(b, i, j));
2177 }
2178 }
2179 }
2180 for b in 0..2 {
2181 for i in 0..2 {
2182 for j in 0..2 {
2183 assert_eq!(mat_at(&a, b, i, j), val(b, i, j), "batch {b}, ({i}, {j})");
2184 }
2185 }
2186 }
2187 }
2188
2189 pub fn test_batched_from_vec<M: DenseMatrix>(ctx: M::C) {
2190 assert_eq!(ctx.nbatch(), 2);
2191 let a = M::from_vec(
2194 2,
2195 2,
2196 vec![
2197 f::<M>(1.0),
2198 f::<M>(3.0),
2199 f::<M>(2.0),
2200 f::<M>(4.0),
2201 f::<M>(5.0),
2202 f::<M>(7.0),
2203 f::<M>(6.0),
2204 f::<M>(8.0),
2205 ],
2206 ctx,
2207 );
2208 assert_eq!(a.nrows(), 2);
2209 assert_eq!(a.ncols(), 2);
2210 assert_eq!(at(&a, 0, 0, 0), f::<M>(1.0));
2211 assert_eq!(at(&a, 0, 1, 0), f::<M>(3.0));
2212 assert_eq!(at(&a, 0, 0, 1), f::<M>(2.0));
2213 assert_eq!(at(&a, 0, 1, 1), f::<M>(4.0));
2214 assert_eq!(at(&a, 1, 0, 0), f::<M>(5.0));
2215 assert_eq!(at(&a, 1, 1, 0), f::<M>(7.0));
2216 assert_eq!(at(&a, 1, 0, 1), f::<M>(6.0));
2217 assert_eq!(at(&a, 1, 1, 1), f::<M>(8.0));
2218 }
2219
2220 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
2223 pub fn test_batched_gemv_o_broadcast_x<M: DenseMatrix>(ctx: M::C) {
2224 assert_eq!(ctx.nbatch(), 2);
2225 let diff = M::from_vec(
2227 2,
2228 3,
2229 vec![
2230 f::<M>(1.0),
2231 f::<M>(4.0),
2232 f::<M>(2.0),
2233 f::<M>(5.0),
2234 f::<M>(3.0),
2235 f::<M>(6.0),
2236 f::<M>(7.0),
2237 f::<M>(10.0),
2238 f::<M>(8.0),
2239 f::<M>(11.0),
2240 f::<M>(9.0),
2241 f::<M>(12.0),
2242 ],
2243 ctx.clone(),
2244 );
2245 let x = vec![f::<M>(1.0), f::<M>(1.0)];
2247 let mut y = M::V::zeros(2, ctx);
2248 diff.gemv_cols(0, 2, f::<M>(1.0), &x, f::<M>(0.0), &mut y);
2249 assert_eq!(
2252 y.clone_as_vec(),
2253 vec![f::<M>(3.0), f::<M>(9.0), f::<M>(15.0), f::<M>(21.0)]
2254 );
2255 }
2256
2257 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
2260 pub fn test_batched_gemv_incompatible<M: DenseMatrix>(ctx2: M::C, ctx3: M::C) {
2261 assert_eq!(ctx2.nbatch(), 2);
2262 assert_eq!(ctx3.nbatch(), 3);
2263 let a = M::zeros(2, 2, ctx2.clone());
2264 let x = M::V::zeros(2, ctx3);
2265 let mut y = M::V::zeros(2, ctx2);
2266 a.gemv(f::<M>(1.0), &x, f::<M>(0.0), &mut y);
2267 }
2268
2269 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
2270 pub fn test_batched_resize_cols<M: DenseMatrix>(ctx: M::C) {
2271 assert_eq!(ctx.nbatch(), 2);
2272 let mut a = M::from_vec(
2274 2,
2275 2,
2276 vec![
2277 f::<M>(1.0),
2278 f::<M>(3.0),
2279 f::<M>(2.0),
2280 f::<M>(4.0),
2281 f::<M>(5.0),
2282 f::<M>(7.0),
2283 f::<M>(6.0),
2284 f::<M>(8.0),
2285 ],
2286 ctx.clone(),
2287 );
2288 a.resize_cols(3);
2290 assert_eq!(a.ncols(), 3);
2291 assert_eq!(a.nrows(), 2);
2292 assert_eq!(at(&a, 0, 0, 0), f::<M>(1.0));
2294 assert_eq!(at(&a, 0, 1, 0), f::<M>(3.0));
2295 assert_eq!(at(&a, 0, 0, 1), f::<M>(2.0));
2296 assert_eq!(at(&a, 0, 1, 1), f::<M>(4.0));
2297 assert_eq!(at(&a, 1, 0, 0), f::<M>(5.0));
2298 assert_eq!(at(&a, 1, 1, 0), f::<M>(7.0));
2299 assert_eq!(at(&a, 1, 0, 1), f::<M>(6.0));
2300 assert_eq!(at(&a, 1, 1, 1), f::<M>(8.0));
2301 assert_eq!(at(&a, 0, 0, 2), f::<M>(0.0));
2303 assert_eq!(at(&a, 0, 1, 2), f::<M>(0.0));
2304 assert_eq!(at(&a, 1, 0, 2), f::<M>(0.0));
2305 assert_eq!(at(&a, 1, 1, 2), f::<M>(0.0));
2306 let x = M::V::from_vec(
2308 vec![
2309 f::<M>(1.0),
2310 f::<M>(0.0),
2311 f::<M>(0.0),
2312 f::<M>(1.0),
2313 f::<M>(0.0),
2314 f::<M>(0.0),
2315 ],
2316 ctx.clone(),
2317 );
2318 let mut y = M::V::zeros(2, ctx.clone());
2319 a.gemv(f::<M>(1.0), &x, f::<M>(0.0), &mut y);
2320 assert_eq!(
2323 y.clone_as_vec(),
2324 vec![f::<M>(1.0), f::<M>(3.0), f::<M>(5.0), f::<M>(7.0)]
2325 );
2326
2327 a.resize_cols(1);
2329 assert_eq!(a.ncols(), 1);
2330 assert_eq!(at(&a, 0, 0, 0), f::<M>(1.0));
2331 assert_eq!(at(&a, 0, 1, 0), f::<M>(3.0));
2332 assert_eq!(at(&a, 1, 0, 0), f::<M>(5.0));
2333 assert_eq!(at(&a, 1, 1, 0), f::<M>(7.0));
2334 let x2 = M::V::from_vec(vec![f::<M>(1.0), f::<M>(1.0)], ctx.clone());
2336 let mut y2 = M::V::zeros(2, ctx);
2337 a.gemv(f::<M>(1.0), &x2, f::<M>(0.0), &mut y2);
2338 assert_eq!(
2340 y2.clone_as_vec(),
2341 vec![f::<M>(1.0), f::<M>(3.0), f::<M>(5.0), f::<M>(7.0)]
2342 );
2343 }
2344
2345 pub fn test_mul_scalar<M: Matrix>() {
2348 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
2349 let values = vec![f::<M>(1.0), f::<M>(3.0), f::<M>(2.0), f::<M>(4.0)];
2350 let a = M::try_from_triplets(2, 2, indices, values, Default::default()).unwrap();
2351 let result = a * Scale(f::<M>(2.0));
2352 let (_, vals) = result.triplet_iter();
2353 let vals: Vec<_> = vals.collect();
2354 assert_eq!(
2355 vals,
2356 vec![f::<M>(2.0), f::<M>(6.0), f::<M>(4.0), f::<M>(8.0)]
2357 );
2358 }
2359
2360 pub fn test_add_column_to_vector<M: Matrix>() {
2361 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
2362 let values = vec![f::<M>(1.0), f::<M>(2.0), f::<M>(3.0), f::<M>(4.0)];
2363 let mat = M::try_from_triplets(2, 2, indices, values, Default::default()).unwrap();
2364 let mut v = M::V::zeros(2, Default::default());
2365 mat.add_column_to_vector(1, &mut v);
2366 assert_eq!(v.clone_as_vec(), vec![f::<M>(3.0), f::<M>(4.0)]);
2367 }
2368
2369 pub fn test_add<M: DenseMatrix>() {
2372 let a = M::from_vec(
2373 2,
2374 2,
2375 vec![f::<M>(1.0), f::<M>(3.0), f::<M>(2.0), f::<M>(4.0)],
2376 Default::default(),
2377 );
2378 let b = M::from_vec(
2379 2,
2380 2,
2381 vec![f::<M>(5.0), f::<M>(7.0), f::<M>(6.0), f::<M>(8.0)],
2382 Default::default(),
2383 );
2384 let result = a + &b;
2385 assert_eq!(result.get_index(0, 0), f::<M>(6.0));
2386 assert_eq!(result.get_index(1, 1), f::<M>(12.0));
2387 }
2388
2389 pub fn test_sub<M: DenseMatrix>() {
2390 let a = M::from_vec(
2391 2,
2392 2,
2393 vec![f::<M>(5.0), f::<M>(7.0), f::<M>(6.0), f::<M>(8.0)],
2394 Default::default(),
2395 );
2396 let b = M::from_vec(
2397 2,
2398 2,
2399 vec![f::<M>(1.0), f::<M>(3.0), f::<M>(2.0), f::<M>(4.0)],
2400 Default::default(),
2401 );
2402 let result = a - &b;
2403 assert_eq!(result.get_index(0, 0), f::<M>(4.0));
2404 assert_eq!(result.get_index(1, 1), f::<M>(4.0));
2405 }
2406
2407 pub fn test_add_assign<M: DenseMatrix>() {
2408 let mut a = M::from_vec(
2409 2,
2410 2,
2411 vec![f::<M>(1.0), f::<M>(3.0), f::<M>(2.0), f::<M>(4.0)],
2412 Default::default(),
2413 );
2414 let b = M::from_vec(
2415 2,
2416 2,
2417 vec![f::<M>(5.0), f::<M>(7.0), f::<M>(6.0), f::<M>(8.0)],
2418 Default::default(),
2419 );
2420 a += &b;
2421 assert_eq!(a.get_index(0, 0), f::<M>(6.0));
2422 assert_eq!(a.get_index(1, 1), f::<M>(12.0));
2423 }
2424
2425 pub fn test_sub_assign<M: DenseMatrix>() {
2426 let mut a = M::from_vec(
2427 2,
2428 2,
2429 vec![f::<M>(5.0), f::<M>(7.0), f::<M>(6.0), f::<M>(8.0)],
2430 Default::default(),
2431 );
2432 let b = M::from_vec(
2433 2,
2434 2,
2435 vec![f::<M>(1.0), f::<M>(3.0), f::<M>(2.0), f::<M>(4.0)],
2436 Default::default(),
2437 );
2438 a -= &b;
2439 assert_eq!(a.get_index(0, 0), f::<M>(4.0));
2440 assert_eq!(a.get_index(1, 1), f::<M>(4.0));
2441 }
2442
2443 pub fn test_inner_mut<M: DenseMatrix>() {
2446 let mut a = M::zeros(2, 2, Default::default());
2447 let _ = a.inner_mut();
2448 }
2449
2450 pub fn test_column_mut<M: DenseMatrix>() {
2453 let mut a = M::from_vec(
2454 2,
2455 2,
2456 vec![f::<M>(1.0), f::<M>(3.0), f::<M>(2.0), f::<M>(4.0)],
2457 Default::default(),
2458 );
2459 a.column_mut(1).set_index(0, f::<M>(20.0));
2460 assert_eq!(a.get_index(0, 1), f::<M>(20.0));
2461 assert_eq!(a.get_index(1, 1), f::<M>(4.0));
2462 }
2463
2464 pub fn test_gather<M: DenseMatrix>() {
2465 let mat1 = M::from_vec(
2466 3,
2467 3,
2468 vec![
2469 f::<M>(1.0),
2470 f::<M>(2.0),
2471 f::<M>(3.0),
2472 f::<M>(4.0),
2473 f::<M>(5.0),
2474 f::<M>(6.0),
2475 f::<M>(7.0),
2476 f::<M>(8.0),
2477 f::<M>(9.0),
2478 ],
2479 Default::default(),
2480 );
2481 let mut mat2 = M::zeros(2, 2, Default::default());
2482 let indices = <M::V as Vector>::Index::from_vec(vec![0, 1, 3, 4], Default::default());
2483 mat2.gather(&mat1, &indices);
2484 assert_eq!(mat2.get_index(0, 0), f::<M>(1.0));
2485 assert_eq!(mat2.get_index(1, 0), f::<M>(2.0));
2486 assert_eq!(mat2.get_index(0, 1), f::<M>(4.0));
2487 assert_eq!(mat2.get_index(1, 1), f::<M>(5.0));
2488 }
2489
2490 pub fn test_set_data_with_indices<M: DenseMatrix>() {
2491 let mut mat = M::zeros(2, 2, Default::default());
2492 let dst_indices = <M::V as Vector>::Index::from_vec(vec![0, 3], Default::default());
2493 let src_indices = <M::V as Vector>::Index::from_vec(vec![0, 1], Default::default());
2494 let data = M::V::from_vec(vec![f::<M>(5.0), f::<M>(6.0)], Default::default());
2495 mat.set_data_with_indices(&dst_indices, &src_indices, &data);
2496 assert_eq!(mat.get_index(0, 0), f::<M>(5.0));
2497 assert_eq!(mat.get_index(1, 1), f::<M>(6.0));
2498 }
2499
2500 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
2501 pub fn test_batched_combine<M: DenseMatrix>(ctx: M::C) {
2502 assert_eq!(ctx.nbatch(), 2);
2503 #[rustfmt::skip]
2504 let data: Vec<M::T> = vec![
2505 f::<M>(1.0), f::<M>(2.0), f::<M>(3.0), f::<M>(4.0),
2507 f::<M>(5.0), f::<M>(6.0), f::<M>(7.0), f::<M>(8.0),
2508 f::<M>(9.0), f::<M>(10.0), f::<M>(11.0), f::<M>(12.0),
2509 f::<M>(13.0), f::<M>(14.0), f::<M>(15.0), f::<M>(16.0),
2510 f::<M>(101.0), f::<M>(102.0), f::<M>(103.0), f::<M>(104.0),
2512 f::<M>(105.0), f::<M>(106.0), f::<M>(107.0), f::<M>(108.0),
2513 f::<M>(109.0), f::<M>(110.0), f::<M>(111.0), f::<M>(112.0),
2514 f::<M>(113.0), f::<M>(114.0), f::<M>(115.0), f::<M>(116.0),
2515 ];
2516 let m = M::from_vec(4, 4, data, ctx.clone());
2517
2518 let alg_indices = <M::V as Vector>::Index::from_vec(vec![1, 3], Default::default());
2519 let [(ul, _), (ur, _), (ll, _), (lr, _)] = m.split(&alg_indices);
2520
2521 let recombined = M::combine(&ul, &ur, &ll, &lr, &alg_indices);
2522
2523 let (_orig_idx, orig_vals) = m.triplet_iter();
2524 let (_recom_idx, recom_vals) = recombined.triplet_iter();
2525 let orig_vals: Vec<_> = orig_vals.collect();
2526 let recom_vals: Vec<_> = recom_vals.collect();
2527 assert_eq!(orig_vals, recom_vals);
2528 }
2529
2530 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
2531 pub fn test_batched_add_column_to_vector_m<M: Matrix>(ctx: M::C) {
2532 assert_eq!(ctx.nbatch(), 2);
2533 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
2534 let values = vec![
2535 f::<M>(1.0),
2536 f::<M>(2.0),
2537 f::<M>(3.0),
2538 f::<M>(4.0),
2539 f::<M>(5.0),
2540 f::<M>(6.0),
2541 f::<M>(7.0),
2542 f::<M>(8.0),
2543 ];
2544 let mat = M::try_from_triplets(2, 2, indices, values, ctx.clone()).unwrap();
2545 let mut v = M::V::zeros(2, ctx);
2546 mat.add_column_to_vector(1, &mut v);
2547 assert_eq!(
2548 v.clone_as_vec(),
2549 vec![f::<M>(3.0), f::<M>(4.0), f::<M>(7.0), f::<M>(8.0)]
2550 );
2551 }
2552
2553 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
2554 pub fn test_batched_add_columns_to_batched_vector_m<M: Matrix>(ctx: M::C) {
2555 assert_eq!(ctx.nbatch(), 2);
2556 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
2557 let values = vec![
2558 f::<M>(1.0),
2559 f::<M>(2.0),
2560 f::<M>(3.0),
2561 f::<M>(4.0),
2562 f::<M>(5.0),
2563 f::<M>(6.0),
2564 f::<M>(7.0),
2565 f::<M>(8.0),
2566 ];
2567 let mat = M::try_from_triplets(2, 2, indices, values, ctx.clone()).unwrap();
2568 let ctx4 = ctx.clone_with_nbatch(4).unwrap();
2570 let mut v = M::V::zeros(2, ctx4);
2571 mat.add_columns_to_batched_vector(&mut v);
2572 assert_eq!(
2573 v.clone_as_vec(),
2574 vec![
2575 f::<M>(1.0),
2576 f::<M>(2.0),
2577 f::<M>(3.0),
2578 f::<M>(4.0),
2579 f::<M>(5.0),
2580 f::<M>(6.0),
2581 f::<M>(7.0),
2582 f::<M>(8.0)
2583 ]
2584 );
2585 mat.add_columns_to_batched_vector(&mut v);
2587 assert_eq!(v.clone_as_vec()[0], f::<M>(2.0));
2588 assert_eq!(v.clone_as_vec()[7], f::<M>(16.0));
2589 }
2590
2591 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
2592 pub fn test_batched_set_data_with_indices_m<M: Matrix>(ctx: M::C) {
2593 assert_eq!(ctx.nbatch(), 2);
2594 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
2595 let zero_values = vec![
2596 f::<M>(0.0),
2597 f::<M>(0.0),
2598 f::<M>(0.0),
2599 f::<M>(0.0),
2600 f::<M>(0.0),
2601 f::<M>(0.0),
2602 f::<M>(0.0),
2603 f::<M>(0.0),
2604 ];
2605 let mut mat = M::try_from_triplets(2, 2, indices, zero_values, ctx.clone()).unwrap();
2606 let dst_indices = <M::V as Vector>::Index::from_vec(vec![0, 3], Default::default());
2607 let src_indices = <M::V as Vector>::Index::from_vec(vec![0, 1], Default::default());
2608 let data = M::V::from_vec(
2609 vec![f::<M>(5.0), f::<M>(6.0), f::<M>(50.0), f::<M>(60.0)],
2610 ctx,
2611 );
2612 mat.set_data_with_indices(&dst_indices, &src_indices, &data);
2613 let (_, vals) = mat.triplet_iter();
2614 let vals: Vec<_> = vals.collect();
2615 assert_eq!(
2616 vals,
2617 vec![
2618 f::<M>(5.0),
2619 f::<M>(0.0),
2620 f::<M>(0.0),
2621 f::<M>(6.0),
2622 f::<M>(50.0),
2623 f::<M>(0.0),
2624 f::<M>(0.0),
2625 f::<M>(60.0),
2626 ]
2627 );
2628 }
2629
2630 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
2631 pub fn test_batched_gather_m<M: Matrix>(ctx: M::C) {
2632 assert_eq!(ctx.nbatch(), 2);
2633 let indices: Vec<(IndexType, IndexType)> =
2634 (0..3).flat_map(|j| (0..3).map(move |i| (i, j))).collect();
2635 let values = vec![
2636 f::<M>(1.0),
2637 f::<M>(2.0),
2638 f::<M>(3.0),
2639 f::<M>(4.0),
2640 f::<M>(5.0),
2641 f::<M>(6.0),
2642 f::<M>(7.0),
2643 f::<M>(8.0),
2644 f::<M>(9.0),
2645 f::<M>(10.0),
2646 f::<M>(20.0),
2647 f::<M>(30.0),
2648 f::<M>(40.0),
2649 f::<M>(50.0),
2650 f::<M>(60.0),
2651 f::<M>(70.0),
2652 f::<M>(80.0),
2653 f::<M>(90.0),
2654 ];
2655 let mat1 = M::try_from_triplets(3, 3, indices, values, ctx.clone()).unwrap();
2656 let dest_indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
2657 let zero_values = vec![
2658 f::<M>(0.0),
2659 f::<M>(0.0),
2660 f::<M>(0.0),
2661 f::<M>(0.0),
2662 f::<M>(0.0),
2663 f::<M>(0.0),
2664 f::<M>(0.0),
2665 f::<M>(0.0),
2666 ];
2667 let mut mat2 = M::try_from_triplets(2, 2, dest_indices, zero_values, ctx).unwrap();
2668 let gather_indices =
2669 <M::V as Vector>::Index::from_vec(vec![0, 1, 3, 4], Default::default());
2670 mat2.gather(&mat1, &gather_indices);
2671 let (_, vals) = mat2.triplet_iter();
2672 let vals: Vec<_> = vals.collect();
2673 assert_eq!(
2674 vals,
2675 vec![
2676 f::<M>(1.0),
2677 f::<M>(2.0),
2678 f::<M>(4.0),
2679 f::<M>(5.0),
2680 f::<M>(10.0),
2681 f::<M>(20.0),
2682 f::<M>(40.0),
2683 f::<M>(50.0),
2684 ]
2685 );
2686 }
2687
2688 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
2689 pub fn test_batched_mul_scalar_m<M: Matrix>(ctx: M::C) {
2690 assert_eq!(ctx.nbatch(), 2);
2691 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
2692 let values = vec![
2693 f::<M>(1.0),
2694 f::<M>(3.0),
2695 f::<M>(2.0),
2696 f::<M>(4.0),
2697 f::<M>(5.0),
2698 f::<M>(7.0),
2699 f::<M>(6.0),
2700 f::<M>(8.0),
2701 ];
2702 let a = M::try_from_triplets(2, 2, indices, values, ctx.clone()).unwrap();
2703 let result = a * Scale(f::<M>(2.0));
2704 let (_, vals) = result.triplet_iter();
2705 let vals: Vec<_> = vals.collect();
2706 assert_eq!(
2707 vals,
2708 vec![
2709 f::<M>(2.0),
2710 f::<M>(6.0),
2711 f::<M>(4.0),
2712 f::<M>(8.0),
2713 f::<M>(10.0),
2714 f::<M>(14.0),
2715 f::<M>(12.0),
2716 f::<M>(16.0),
2717 ]
2718 );
2719 }
2720
2721 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
2722 pub fn test_batched_partition_indices<M: Matrix>(ctx: M::C) {
2723 assert_eq!(ctx.nbatch(), 2);
2724 let zero_val = M::T::zero();
2725 let one_val = f::<M>(1.0);
2726 let two_val = f::<M>(2.0);
2727 let indices = vec![(0, 0), (1, 1), (2, 2)];
2728 let values = vec![one_val, zero_val, one_val, two_val, zero_val, two_val];
2729 let m = M::try_from_triplets(3, 3, indices, values, ctx).unwrap();
2730 let (zero_idx, nonzero_idx) = m.partition_indices_by_zero_diagonal();
2731 assert_eq!(zero_idx.clone_as_vec(), vec![1]);
2732 assert_eq!(nonzero_idx.clone_as_vec(), vec![0, 2]);
2733 }
2734
2735 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
2739 pub fn test_batched_update_backward_diff<M: DenseMatrix>(ctx: M::C) {
2740 assert_eq!(ctx.nbatch(), 2);
2741 let order = 1;
2742 let mut a = M::from_vec(
2743 2,
2744 4,
2745 vec![
2746 f::<M>(1.0),
2748 f::<M>(10.0),
2749 f::<M>(2.0),
2750 f::<M>(20.0),
2751 f::<M>(3.0),
2752 f::<M>(30.0),
2753 f::<M>(0.0),
2754 f::<M>(0.0),
2755 f::<M>(5.0),
2757 f::<M>(50.0),
2758 f::<M>(6.0),
2759 f::<M>(60.0),
2760 f::<M>(7.0),
2761 f::<M>(70.0),
2762 f::<M>(0.0),
2763 f::<M>(0.0),
2764 ],
2765 ctx.clone(),
2766 );
2767 let d = M::V::from_vec(
2768 vec![f::<M>(100.0), f::<M>(1000.0), f::<M>(200.0), f::<M>(2000.0)],
2769 ctx,
2770 );
2771
2772 a.update_backward_diff(order, &d);
2773
2774 assert_eq!(
2775 a.column(3).into_owned().clone_as_vec(),
2776 vec![f::<M>(97.0), f::<M>(970.0), f::<M>(193.0), f::<M>(1930.0)]
2777 );
2778 assert_eq!(
2779 a.column(2).into_owned().clone_as_vec(),
2780 vec![f::<M>(100.0), f::<M>(1000.0), f::<M>(200.0), f::<M>(2000.0)]
2781 );
2782 assert_eq!(
2783 a.column(1).into_owned().clone_as_vec(),
2784 vec![f::<M>(102.0), f::<M>(1020.0), f::<M>(206.0), f::<M>(2060.0)]
2785 );
2786 assert_eq!(
2787 a.column(0).into_owned().clone_as_vec(),
2788 vec![f::<M>(103.0), f::<M>(1030.0), f::<M>(211.0), f::<M>(2110.0)]
2789 );
2790 }
2791
2792 #[cfg_attr(not(feature = "cuda"), allow(dead_code))]
2793 pub fn test_batched_from_diagonal_dense<M: DenseMatrix>(ctx: M::C) {
2794 assert_eq!(ctx.nbatch(), 2);
2795 let v = M::V::from_vec(
2796 vec![f::<M>(2.0), f::<M>(3.0), f::<M>(4.0), f::<M>(5.0)],
2797 ctx,
2798 );
2799 let a = M::from_diagonal(&v);
2800 assert_eq!(a.nrows(), 2);
2801 assert_eq!(a.ncols(), 2);
2802 assert_eq!(at(&a, 0, 0, 0), f::<M>(2.0));
2803 assert_eq!(at(&a, 0, 1, 1), f::<M>(3.0));
2804 assert_eq!(at(&a, 0, 0, 1), f::<M>(0.0));
2805 assert_eq!(at(&a, 0, 1, 0), f::<M>(0.0));
2806 assert_eq!(at(&a, 1, 0, 0), f::<M>(4.0));
2807 assert_eq!(at(&a, 1, 1, 1), f::<M>(5.0));
2808 assert_eq!(at(&a, 1, 0, 1), f::<M>(0.0));
2809 assert_eq!(at(&a, 1, 1, 0), f::<M>(0.0));
2810 }
2811
2812 pub fn test_try_from_triplets_wrong_length<M: Matrix>() {
2813 let indices = vec![(0, 0), (1, 0), (0, 1), (1, 1)];
2814 let values = vec![f::<M>(1.0), f::<M>(2.0), f::<M>(3.0)];
2816 let _ = M::try_from_triplets(2, 2, indices, values, Default::default());
2817 }
2818
2819 }
2821
2822#[cfg(test)]
2823macro_rules! generate_matrix_tests_nonbatched {
2824 ($suffix:ident, $M:ty) => {
2825 paste::paste! {
2826 #[test]
2827 fn [<test_zeros_ $suffix>]() {
2828 $crate::matrix::tests::test_zeros::<$M>();
2829 }
2830 #[test]
2831 fn [<test_sparsity_ $suffix>]() {
2832 $crate::matrix::tests::test_sparsity::<$M>();
2833 }
2834 #[test]
2835 fn [<test_matrix_common_by_ref_ $suffix>]() {
2836 $crate::matrix::tests::test_matrix_common_by_ref::<$M>();
2837 }
2838 #[test]
2839 fn [<test_from_diagonal_ $suffix>]() {
2840 $crate::matrix::tests::test_from_diagonal::<$M>();
2841 }
2842 #[test]
2843 fn [<test_gemv_ $suffix>]() {
2844 $crate::matrix::tests::test_gemv::<$M>();
2845 }
2846 #[test]
2847 fn [<test_set_column_ $suffix>]() {
2848 $crate::matrix::tests::test_set_column::<$M>();
2849 }
2850 #[test]
2851 fn [<test_copy_from_ $suffix>]() {
2852 $crate::matrix::tests::test_copy_from::<$M>();
2853 }
2854 #[test]
2855 fn [<test_scale_add_and_assign_ $suffix>]() {
2856 $crate::matrix::tests::test_scale_add_and_assign::<$M>();
2857 }
2858 #[test]
2859 fn [<test_partition_indices_ $suffix>]() {
2860 $crate::matrix::tests::test_partition_indices_by_zero_diagonal::<$M>();
2861 }
2862 #[test]
2863 fn [<test_mul_scalar_ $suffix>]() {
2864 $crate::matrix::tests::test_mul_scalar::<$M>();
2865 }
2866 #[test]
2867 fn [<test_add_column_to_vector_ $suffix>]() {
2868 $crate::matrix::tests::test_add_column_to_vector::<$M>();
2869 }
2870 #[test]
2871 #[should_panic]
2872 fn [<test_try_from_triplets_wrong_length_ $suffix>]() {
2873 $crate::matrix::tests::test_try_from_triplets_wrong_length::<$M>();
2874 }
2875 }
2876 };
2877}
2878
2879#[cfg(test)]
2880#[cfg_attr(not(feature = "cuda"), allow(unused_macros))]
2881macro_rules! generate_matrix_tests_batched {
2882 ($suffix:ident, $M:ty, $ctx1:expr, $ctx2:expr) => {
2883 paste::paste! {
2884 #[test]
2885 fn [<test_batched_add_column_to_vector_ $suffix>]() {
2886 $crate::matrix::tests::test_batched_add_column_to_vector_m::<$M>($ctx2);
2887 }
2888 #[test]
2889 fn [<test_batched_add_columns_to_batched_vector_ $suffix>]() {
2890 $crate::matrix::tests::test_batched_add_columns_to_batched_vector_m::<$M>($ctx2);
2891 }
2892 #[test]
2893 fn [<test_batched_set_data_with_indices_ $suffix>]() {
2894 $crate::matrix::tests::test_batched_set_data_with_indices_m::<$M>($ctx2);
2895 }
2896 #[test]
2897 fn [<test_batched_gather_ $suffix>]() {
2898 $crate::matrix::tests::test_batched_gather_m::<$M>($ctx2);
2899 }
2900 #[test]
2901 fn [<test_batched_mul_scalar_ $suffix>]() {
2902 $crate::matrix::tests::test_batched_mul_scalar_m::<$M>($ctx2);
2903 }
2904 #[test]
2905 fn [<test_batched_partition_indices_ $suffix>]() {
2906 $crate::matrix::tests::test_batched_partition_indices::<$M>($ctx2);
2907 }
2908 #[test]
2909 fn [<test_batched_zeros_ $suffix>]() {
2910 $crate::matrix::tests::test_batched_zeros_m::<$M>($ctx2);
2911 }
2912 #[test]
2913 fn [<test_batched_gemv_ $suffix>]() {
2914 $crate::matrix::tests::test_batched_gemv_m::<$M>($ctx2);
2915 }
2916 #[test]
2917 fn [<test_batched_gemv_broadcast_x_ $suffix>]() {
2918 $crate::matrix::tests::test_batched_gemv_broadcast_x_m::<$M>($ctx2);
2919 }
2920 #[test]
2921 fn [<test_batched_gemv_broadcast_mat_ $suffix>]() {
2922 $crate::matrix::tests::test_batched_gemv_broadcast_mat_m::<$M>($ctx2);
2923 }
2924 #[test]
2925 fn [<test_batched_from_diagonal_ $suffix>]() {
2926 $crate::matrix::tests::test_batched_from_diagonal_m::<$M>($ctx2);
2927 }
2928 #[test]
2929 fn [<test_batched_copy_from_ $suffix>]() {
2930 $crate::matrix::tests::test_batched_copy_from_m::<$M>($ctx2);
2931 }
2932 #[test]
2933 fn [<test_batched_copy_from_broadcast_ $suffix>]() {
2934 $crate::matrix::tests::test_batched_copy_from_broadcast_m::<$M>($ctx2);
2935 }
2936 #[test]
2937 fn [<test_batched_set_column_ $suffix>]() {
2938 $crate::matrix::tests::test_batched_set_column_m::<$M>($ctx2);
2939 }
2940 #[test]
2941 fn [<test_batched_scale_add_ $suffix>]() {
2942 $crate::matrix::tests::test_batched_scale_add_and_assign_m::<$M>($ctx2);
2943 }
2944 #[test]
2945 fn [<test_batched_owned_lhs_broadcast_ $suffix>]() {
2946 $crate::matrix::tests::test_batched_owned_lhs_broadcast_m::<$M>($ctx2);
2947 }
2948 #[test]
2949 fn [<test_batched_scale_add_broadcast_ $suffix>]() {
2950 $crate::matrix::tests::test_batched_scale_add_and_assign_broadcast_m::<$M>($ctx2);
2951 }
2952
2953 #[test]
2954 fn [<test_batched_mul_scalar_ref_ $suffix>]() {
2955 $crate::matrix::tests::test_batched_mul_scalar_ref_m::<$M>($ctx2);
2956 }
2957 #[test]
2958 fn [<test_batched_owned_lhs_add_broadcast_ $suffix>]() {
2959 $crate::matrix::tests::test_batched_owned_lhs_add_broadcast_m::<$M>($ctx2);
2960 }
2961 #[test]
2962 fn [<test_batched_gemv_beta_ $suffix>]() {
2963 $crate::matrix::tests::test_batched_gemv_beta_m::<$M>($ctx2);
2964 }
2965
2966 #[test]
2968 #[should_panic(expected = "incompatible nbatch")]
2969 fn [<test_batched_owned_lhs_narrow_ $suffix>]() {
2970 $crate::matrix::tests::test_batched_owned_lhs_narrow_m::<$M>($ctx2);
2971 }
2972 #[test]
2973 #[should_panic(expected = "incompatible nbatch")]
2974 fn [<test_grouped_owned_lhs_narrow_ $suffix>]() {
2975 $crate::matrix::tests::test_grouped_owned_lhs_narrow_m::<$M>($ctx2);
2976 }
2977
2978 #[test]
2980 #[should_panic(expected = "incompatible nbatch")]
2981 fn [<test_narrow_dest_gemv_ $suffix>]() {
2982 $crate::matrix::tests::test_narrow_dest_gemv_m::<$M>($ctx2);
2983 }
2984 #[test]
2985 #[should_panic(expected = "incompatible nbatch")]
2986 fn [<test_narrow_dest_copy_from_ $suffix>]() {
2987 $crate::matrix::tests::test_narrow_dest_copy_from_m::<$M>($ctx2);
2988 }
2989 #[test]
2990 #[should_panic(expected = "incompatible nbatch")]
2991 fn [<test_narrow_dest_scale_add_ $suffix>]() {
2992 $crate::matrix::tests::test_narrow_dest_scale_add_m::<$M>($ctx2);
2993 }
2994 #[test]
2995 #[should_panic(expected = "incompatible nbatch")]
2996 fn [<test_narrow_dest_gather_ $suffix>]() {
2997 $crate::matrix::tests::test_narrow_dest_gather_m::<$M>($ctx2);
2998 }
2999 #[test]
3000 #[should_panic(expected = "incompatible nbatch")]
3001 fn [<test_narrow_dest_set_data_with_indices_ $suffix>]() {
3002 $crate::matrix::tests::test_narrow_dest_set_data_with_indices_m::<$M>($ctx2);
3003 }
3004
3005 #[test]
3007 fn [<test_grouped_gemv_ $suffix>]() {
3008 $crate::matrix::tests::test_grouped_gemv_m::<$M>($ctx2);
3009 }
3010 #[test]
3011 fn [<test_grouped_gemv_x_ $suffix>]() {
3012 $crate::matrix::tests::test_grouped_gemv_x_m::<$M>($ctx2);
3013 }
3014 #[test]
3015 fn [<test_grouped_copy_from_ $suffix>]() {
3016 $crate::matrix::tests::test_grouped_copy_from_m::<$M>($ctx2);
3017 }
3018 #[test]
3019 fn [<test_grouped_owned_lhs_add_ $suffix>]() {
3020 $crate::matrix::tests::test_grouped_owned_lhs_add_m::<$M>($ctx2);
3021 }
3022 #[test]
3023 fn [<test_grouped_scale_add_ $suffix>]() {
3024 $crate::matrix::tests::test_grouped_scale_add_and_assign_m::<$M>($ctx2);
3025 }
3026 }
3027 };
3028}
3029
3030#[cfg(test)]
3031macro_rules! generate_dense_matrix_tests_nonbatched {
3032 ($suffix:ident, $M:ty) => {
3033 paste::paste! {
3034 #[test]
3035 fn [<test_from_vec_ $suffix>]() {
3036 $crate::matrix::tests::test_from_vec::<$M>();
3037 }
3038 #[test]
3039 fn [<test_from_diagonal_dense_ $suffix>]() {
3040 $crate::matrix::tests::test_from_diagonal_dense::<$M>();
3041 }
3042 #[test]
3043 fn [<test_column_view_ $suffix>]() {
3044 $crate::matrix::tests::test_column_view::<$M>();
3045 }
3046 #[test]
3047 fn [<test_sparsity_dense_errors_ $suffix>]() {
3048 $crate::matrix::tests::test_sparsity_dense_errors::<$M>();
3049 }
3050 #[test]
3051 fn [<test_update_backward_diff_ $suffix>]() {
3052 $crate::matrix::tests::test_update_backward_diff::<$M>();
3053 }
3054 #[test]
3055 fn [<test_update_backward_diff_transpose_ $suffix>]() {
3056 $crate::matrix::tests::test_update_backward_diff_transpose::<$M>();
3057 }
3058 #[test]
3059 fn [<test_mul_cols_by_transpose_ $suffix>]() {
3060 $crate::matrix::tests::test_mul_cols_by_transpose::<$M>();
3061 }
3062 #[test]
3063 fn [<test_gemv_cols_ $suffix>]() {
3064 $crate::matrix::tests::test_gemv_cols::<$M>();
3065 }
3066 #[test]
3067 fn [<test_ger_cols_ $suffix>]() {
3068 $crate::matrix::tests::test_ger_cols::<$M>();
3069 }
3070 #[test]
3071 fn [<test_ger_cols_transpose_ $suffix>]() {
3072 $crate::matrix::tests::test_ger_cols_transpose::<$M>();
3073 }
3074
3075 #[test]
3076 fn [<test_gemv_cols_many_columns_ $suffix>]() {
3077 $crate::matrix::tests::test_gemv_cols_many_columns::<$M>();
3078 }
3079
3080 #[test]
3081 fn [<test_mul_cols_by_ $suffix>]() {
3082 $crate::matrix::tests::test_mul_cols_by::<$M>();
3083 }
3084 #[test]
3085 fn [<test_fill_ $suffix>]() {
3086 $crate::matrix::tests::test_fill::<$M>(Default::default());
3087 }
3088 #[test]
3089 fn [<test_resize_cols_ $suffix>]() {
3090 $crate::matrix::tests::test_resize_cols::<$M>();
3091 }
3092 #[test]
3093 fn [<test_add_ $suffix>]() {
3094 $crate::matrix::tests::test_add::<$M>();
3095 }
3096 #[test]
3097 fn [<test_sub_ $suffix>]() {
3098 $crate::matrix::tests::test_sub::<$M>();
3099 }
3100 #[test]
3101 fn [<test_inner_mut_ $suffix>]() {
3102 $crate::matrix::tests::test_inner_mut::<$M>();
3103 }
3104 #[test]
3105 fn [<test_column_mut_ $suffix>]() {
3106 $crate::matrix::tests::test_column_mut::<$M>();
3107 }
3108 #[test]
3109 fn [<test_add_assign_ $suffix>]() {
3110 $crate::matrix::tests::test_add_assign::<$M>();
3111 }
3112 #[test]
3113 fn [<test_sub_assign_ $suffix>]() {
3114 $crate::matrix::tests::test_sub_assign::<$M>();
3115 }
3116 #[test]
3117 fn [<test_gather_ $suffix>]() {
3118 $crate::matrix::tests::test_gather::<$M>();
3119 }
3120 #[test]
3121 fn [<test_set_data_with_indices_ $suffix>]() {
3122 $crate::matrix::tests::test_set_data_with_indices::<$M>();
3123 }
3124 }
3125 };
3126}
3127
3128#[cfg(test)]
3129#[cfg_attr(not(feature = "cuda"), allow(unused_macros))]
3130macro_rules! generate_dense_matrix_tests_batched {
3131 ($suffix:ident, $M:ty, $ctx1:expr, $ctx2:expr) => {
3132 paste::paste! {
3133 #[test]
3134 fn [<test_batched_update_backward_diff_ $suffix>]() {
3135 $crate::matrix::tests::test_batched_update_backward_diff::<$M>($ctx2);
3136 }
3137 #[test]
3138 fn [<test_batched_gemv_cols_ $suffix>]() {
3139 $crate::matrix::tests::test_batched_gemv_cols_m::<$M>($ctx2);
3140 }
3141 #[test]
3142 fn [<test_batched_ger_cols_ $suffix>]() {
3143 $crate::matrix::tests::test_batched_ger_cols::<$M>($ctx2);
3144 }
3145
3146 #[test]
3147 fn [<test_batched_mul_cols_by_ $suffix>]() {
3148 $crate::matrix::tests::test_batched_mul_cols_by::<$M>($ctx2);
3149 }
3150 #[test]
3151 fn [<test_batched_fill_ $suffix>]() {
3152 $crate::matrix::tests::test_fill::<$M>($ctx2);
3153 }
3154 #[test]
3155 fn [<test_batched_from_diagonal_dense_ $suffix>]() {
3156 $crate::matrix::tests::test_batched_from_diagonal_dense::<$M>($ctx2);
3157 }
3158 #[test]
3159 fn [<test_batched_from_vec_ $suffix>]() {
3160 $crate::matrix::tests::test_batched_from_vec::<$M>($ctx2);
3161 }
3162 #[test]
3163 fn [<test_batched_set_index_batch_ $suffix>]() {
3164 $crate::matrix::tests::test_batched_set_index_batch::<$M>($ctx2);
3165 }
3166 #[test]
3167 fn [<test_batched_gemv_o_broadcast_x_ $suffix>]() {
3168 $crate::matrix::tests::test_batched_gemv_o_broadcast_x::<$M>($ctx2);
3169 }
3170 #[test]
3171 fn [<test_batched_resize_cols_ $suffix>]() {
3172 $crate::matrix::tests::test_batched_resize_cols::<$M>($ctx2);
3173 }
3174 #[test]
3175 fn [<test_batched_combine_ $suffix>]() {
3176 $crate::matrix::tests::test_batched_combine::<$M>($ctx2);
3177 }
3178 #[test]
3179 fn [<test_batched_add_assign_broadcast_ $suffix>]() {
3180 $crate::matrix::tests::test_batched_add_assign_broadcast_m::<$M>($ctx2);
3181 }
3182 #[test]
3183 fn [<test_grouped_add_assign_ $suffix>]() {
3184 $crate::matrix::tests::test_grouped_add_assign_m::<$M>($ctx2);
3185 }
3186 #[test]
3187 #[should_panic(expected = "incompatible nbatch")]
3188 fn [<test_narrow_dest_gemv_cols_ $suffix>]() {
3189 $crate::matrix::tests::test_narrow_dest_gemv_cols_m::<$M>($ctx2);
3190 }
3191 #[test]
3192 #[should_panic(expected = "incompatible nbatch")]
3193 fn [<test_narrow_dest_add_assign_ $suffix>]() {
3194 $crate::matrix::tests::test_narrow_dest_add_assign_m::<$M>($ctx2);
3195 }
3196 #[test]
3197 fn [<test_grouped_gemv_cols_ $suffix>]() {
3198 $crate::matrix::tests::test_grouped_gemv_cols_m::<$M>($ctx2);
3199 }
3200 #[test]
3201 #[should_panic(expected = "incompatible nbatch")]
3202 fn [<test_batched_gemv_incompatible_ $suffix>]() {
3203 $crate::matrix::tests::test_batched_gemv_incompatible::<$M>($ctx2, $ctx1.clone_with_nbatch(3).unwrap());
3204 }
3205 }
3206 };
3207}
3208
3209#[cfg(test)]
3210#[cfg_attr(not(feature = "cuda"), allow(unused_imports))]
3211pub(crate) use generate_dense_matrix_tests_batched;
3212#[cfg(test)]
3213pub(crate) use generate_dense_matrix_tests_nonbatched;
3214#[cfg(test)]
3215#[cfg_attr(not(feature = "cuda"), allow(unused_imports))]
3216pub(crate) use generate_matrix_tests_batched;
3217#[cfg(test)]
3218pub(crate) use generate_matrix_tests_nonbatched;