1use std::ops::{Add, AddAssign, Index, IndexMut, Mul, Sub, SubAssign};
2
3use nalgebra::{
4 Const, DMatrix, DVectorView, MatrixView as NaMatrixView, MatrixViewMut as NaMatrixViewMut,
5};
6
7use super::default_solver::DefaultSolver;
8use super::sparsity::{Dense, DenseRef};
9use std::mem::MaybeUninit;
10
11use crate::context::broadcast_batch;
12use crate::error::LaError;
13use crate::{scalar::Scale, Context, NalgebraScalar, Vector};
14use crate::{
15 DenseMatrix, Matrix, MatrixCommon, NalgebraContext, NalgebraLU, NalgebraVec, NalgebraVecMut,
16 NalgebraVecRef, VectorIndex,
17};
18
19#[derive(Clone, Debug, PartialEq)]
24pub struct NalgebraMat<T: NalgebraScalar> {
25 pub(crate) data: DMatrix<T>,
26 pub(crate) context: NalgebraContext,
27}
28impl<T: NalgebraScalar> NalgebraMat<T> {
29 fn logical_ncols(&self) -> usize {
30 self.data.ncols() / self.context.nbatch()
31 }
32 fn col(&self, b: usize, j: usize) -> usize {
34 debug_assert!(b < self.context.nbatch(), "batch out of bounds");
35 b * self.logical_ncols() + j
36 }
37 fn col_bcast(&self, b: usize, j: usize, nbatch: usize) -> usize {
40 self.col(broadcast_batch(b, self.context.nbatch(), nbatch), j)
41 }
42}
43const MUL_COLS_TILE: usize = 1024;
53
54impl<T: NalgebraScalar> DefaultSolver for NalgebraMat<T> {
55 type LS = NalgebraLU<T>;
56}
57
58impl<T: NalgebraScalar> MatrixCommon for NalgebraMat<T> {
59 type T = T;
60 type V = NalgebraVec<T>;
61 type C = NalgebraContext;
62 type Inner = DMatrix<T>;
63 fn nrows(&self) -> usize {
64 self.data.nrows()
65 }
66 fn ncols(&self) -> usize {
67 self.logical_ncols()
68 }
69 fn inner(&self) -> &Self::Inner {
70 &self.data
71 }
72}
73macro_rules! binary_owned_lhs {
76 ($tr:ident, $fn:ident, $assign_tr:ident, $assign:ident, $rhs:ty) => {
77 impl<T: NalgebraScalar> $tr<$rhs> for NalgebraMat<T> {
78 type Output = NalgebraMat<T>;
79
80 fn $fn(mut self, rhs: $rhs) -> Self::Output {
81 $assign_tr::$assign(&mut self, rhs);
82 self
83 }
84 }
85 };
86}
87binary_owned_lhs!(Add, add, AddAssign, add_assign, &NalgebraMat<T>);
88binary_owned_lhs!(Sub, sub, SubAssign, sub_assign, &NalgebraMat<T>);
89
90macro_rules! binary_owned_rhs {
96 (commutes, $tr:ident, $fn:ident, $assign_tr:ident, $assign:ident, $lhs:ty, $op:tt,
97 $combine:expr) => {
98 impl<T: NalgebraScalar> $tr<NalgebraMat<T>> for $lhs {
99 type Output = NalgebraMat<T>;
100
101 fn $fn(self, mut rhs: NalgebraMat<T>) -> Self::Output {
102 $assign_tr::$assign(&mut rhs, self);
103 rhs
104 }
105 }
106 };
107 (noncommutes, $tr:ident, $fn:ident, $assign_tr:ident, $assign:ident, $lhs:ty, $op:tt, $combine:expr) => {
108 impl<T: NalgebraScalar> $tr<NalgebraMat<T>> for $lhs {
109 type Output = NalgebraMat<T>;
110
111 fn $fn(self, mut rhs: NalgebraMat<T>) -> Self::Output {
112 rhs.context
113 .assert_broadcastable_into(self.context.nbatch(), stringify!($fn));
114 let nc = self.ncols();
115 let nb = rhs.context.nbatch();
116 for b in 0..nb {
117 let mut columns = rhs.data.columns_mut(rhs.col(b, 0), nc);
118 columns.zip_apply(&self.data.columns(self.col_bcast(b, 0, nb), nc), $combine);
119 }
120 rhs
121 }
122 }
123 };
124}
125binary_owned_rhs!(
126 commutes, Add, add, AddAssign, add_assign, &NalgebraMat<T>, +=, |rhs: &mut T, lhs: T| *rhs += lhs
127);
128binary_owned_rhs!(
129 noncommutes, Sub, sub, SubAssign, sub_assign, &NalgebraMat<T>, -=,
130 |rhs: &mut T, lhs: T| *rhs = lhs - *rhs
131);
132macro_rules! assign {
133 ($tr:ident, $fn:ident, $l:ty, $r:ty, $op:tt) => {
134 impl<T: NalgebraScalar> $tr<$r> for $l {
135 fn $fn(&mut self, rhs: $r) {
136 self.context
137 .assert_broadcastable_into(rhs.context.nbatch(), stringify!($fn));
138 let nb = self.context.nbatch();
139 let nc = self.ncols();
140 if nb == rhs.context.nbatch()
141 && self.data.ncols() == nc * nb
142 && rhs.data.ncols() == nc * nb
143 {
144 self.data $op &rhs.data;
145 return;
146 }
147 for b in 0..nb {
148 let mut columns = self.data.columns_mut(self.col(b, 0), nc);
149 columns $op &rhs.data.columns(rhs.col_bcast(b, 0, nb), nc);
150 }
151 }
152 }
153 };
154}
155assign!(AddAssign, add_assign, NalgebraMat<T>, &NalgebraMat<T>, +=);
156assign!(SubAssign, sub_assign, NalgebraMat<T>, &NalgebraMat<T>, -=);
157impl<T: NalgebraScalar> Mul<Scale<T>> for NalgebraMat<T> {
158 type Output = Self;
159 fn mul(mut self, r: Scale<T>) -> Self {
160 self.data *= r.value();
161 self
162 }
163}
164macro_rules! scale_ref {
165 ($t:ty) => {
166 impl<T: NalgebraScalar> Mul<Scale<T>> for $t {
167 type Output = NalgebraMat<T>;
168 fn mul(self, r: Scale<T>) -> Self::Output {
169 NalgebraMat {
172 data: &self.data * r.value(),
173 context: self.context,
174 }
175 }
176 }
177 };
178}
179scale_ref!(&NalgebraMat<T>);
180macro_rules! ind {
181 ($t:ty) => {
182 impl<T: NalgebraScalar> Index<(usize, usize)> for $t {
183 type Output = T;
184 fn index(&self, x: (usize, usize)) -> &T {
185 assert_eq!(
186 self.context.nbatch(),
187 1,
188 "indexing not supported for batched matrices"
189 );
190 &self.data[(x.0, self.col(0, x.1))]
191 }
192 }
193 };
194}
195ind!(NalgebraMat<T>);
196impl<T: NalgebraScalar> IndexMut<(usize, usize)> for NalgebraMat<T> {
197 fn index_mut(&mut self, x: (usize, usize)) -> &mut T {
198 assert_eq!(
199 self.context.nbatch(),
200 1,
201 "indexing not supported for batched matrices"
202 );
203 let c = self.col(0, x.1);
204 &mut self.data[(x.0, c)]
205 }
206}
207
208macro_rules! gemv_data {
217 ($self:ident, $a:ident, $x:ident, $beta:ident, $y:ident, $op:literal) => {{
218 $y.context
219 .assert_broadcastable_into($self.context.nbatch(), $op);
220 $y.context
221 .assert_broadcastable_into($x.context.nbatch(), $op);
222 let nc = $self.ncols();
223 if $y.data.ncols() == 1 {
226 $y.data.column_mut(0).gemv(
227 $a,
228 &$self.data.columns($self.col(0, 0), nc),
229 &$x.data.column(0),
230 $beta,
231 );
232 return;
233 }
234 let nb = $y.data.ncols();
235 for b in 0..nb {
236 $y.data.column_mut(b).gemv(
237 $a,
238 &$self.data.columns($self.col_bcast(b, 0, nb), nc),
239 &$x.data.column($x.batch(b, nb)),
240 $beta,
241 );
242 }
243 }};
244}
245
246macro_rules! gemv_cols_data {
250 ($self:ident, $start:expr, $nc:expr, $a:ident, $x:ident, $beta:ident, $y:ident, $op:literal) => {{
251 $y.context
252 .assert_broadcastable_into($self.context.nbatch(), $op);
253 let (start, nc) = ($start, $nc);
254 debug_assert!(
258 start + nc <= $self.ncols(),
259 concat!($op, ": column range out of bounds")
260 );
261 let x = DVectorView::from_slice(&$x[..nc], nc);
262 if $y.data.ncols() == 1 {
263 $y.data
264 .column_mut(0)
265 .gemv($a, &$self.data.columns($self.col(0, start), nc), &x, $beta);
266 return;
267 }
268 let nb = $y.data.ncols();
269 for b in 0..nb {
270 $y.data.column_mut(b).gemv(
271 $a,
272 &$self.data.columns($self.col_bcast(b, start, nb), nc),
273 &x,
274 $beta,
275 );
276 }
277 }};
278}
279
280impl<T: NalgebraScalar> Matrix for NalgebraMat<T> {
281 type Sparsity = Dense<Self>;
282 type SparsityRef<'a> = DenseRef<'a, Self>;
283 fn sparsity(&self) -> Option<Self::SparsityRef<'_>> {
284 None
285 }
286 fn context(&self) -> &Self::C {
287 &self.context
288 }
289 fn inner_mut(&mut self) -> &mut Self::Inner {
290 &mut self.data
291 }
292 fn set_data_with_indices(
293 &mut self,
294 dst: &crate::vector::nalgebra_serial::NalgebraIndex,
295 src: &crate::vector::nalgebra_serial::NalgebraIndex,
296 data: &NalgebraVec<T>,
297 ) {
298 self.context
299 .assert_broadcastable_into(data.context.nbatch(), "set_data_with_indices");
300 let nb = self.context.nbatch();
301 for (d, s) in dst.data.iter().zip(src.data.iter()) {
302 let i = d % self.nrows();
303 let j = d / self.nrows();
304 for b in 0..nb {
305 let c = self.col(b, j);
306 self.data[(i, c)] = data.data[(*s, data.batch(b, nb))]
307 }
308 }
309 }
310 fn gather(&mut self, o: &Self, idx: &crate::vector::nalgebra_serial::NalgebraIndex) {
311 self.context
312 .assert_broadcastable_into(o.context.nbatch(), "gather");
313 let nb = self.context.nbatch();
314 for b in 0..nb {
315 for (d, s) in idx.data.iter().enumerate() {
316 let i = d % self.nrows();
317 let j = d / self.nrows();
318 let oi = s % o.nrows();
319 let oj = s / o.nrows();
320 let c = self.col(b, j);
321 self.data[(i, c)] = o.data[(oi, o.col_bcast(b, oj, nb))]
322 }
323 }
324 }
325 fn partition_indices_by_zero_diagonal(
326 &self,
327 ) -> (
328 crate::vector::nalgebra_serial::NalgebraIndex,
329 crate::vector::nalgebra_serial::NalgebraIndex,
330 ) {
331 let (mut z, mut nz) = (Vec::new(), Vec::new());
332 for i in 0..self.nrows() {
333 if self.data[(i, self.col(0, i))].is_zero() {
334 z.push(i)
335 } else {
336 nz.push(i)
337 }
338 }
339 (
340 crate::vector::nalgebra_serial::NalgebraIndex::from_vec(z, self.context),
341 crate::vector::nalgebra_serial::NalgebraIndex::from_vec(nz, self.context),
342 )
343 }
344 fn add_column_to_vector(&self, j: usize, v: &mut NalgebraVec<T>) {
345 v.context
346 .assert_broadcastable_into(self.context.nbatch(), "add_column_to_vector");
347 if self.context.nbatch() == 1 && v.context.nbatch() == 1 {
348 v.data
349 .column_mut(0)
350 .axpy(T::one(), &self.data.column(j), T::one());
351 return;
352 }
353 let nb = v.context.nbatch();
354 for b in 0..nb {
355 v.data.column_mut(b).axpy(
356 T::one(),
357 &self.data.column(self.col_bcast(b, j, nb)),
358 T::one(),
359 );
360 }
361 }
362 fn add_columns_to_batched_vector(&self, v: &mut NalgebraVec<T>) {
363 assert_eq!(v.len(), self.nrows(), "row count mismatch");
364 assert_eq!(
365 v.context.nbatch(),
366 self.context.nbatch() * self.ncols(),
367 "batch count mismatch: the destination holds one lane per (batch, column)"
368 );
369 v.data += &self.data;
372 }
373 fn triplet_iter(
374 &self,
375 ) -> (
376 impl Iterator<Item = (usize, usize)> + '_,
377 impl Iterator<Item = T> + '_,
378 ) {
379 let pos: Vec<_> = (0..self.ncols())
380 .flat_map(|j| (0..self.nrows()).map(move |i| (i, j)))
381 .collect();
382 let val: Vec<_> = (0..self.context.nbatch())
383 .flat_map(|b| {
384 pos.iter()
385 .map(move |&(i, j)| self.data[(i, self.col(b, j))])
386 })
387 .collect();
388 (pos.into_iter(), val.into_iter())
389 }
390 fn try_from_triplets(
391 nr: usize,
392 nc: usize,
393 idx: Vec<(usize, usize)>,
394 v: Vec<T>,
395 ctx: Self::C,
396 ) -> Result<Self, LaError> {
397 assert_eq!(v.len(), idx.len() * ctx.nbatch());
398 let mut out = Self::zeros(nr, nc, ctx);
399 for b in 0..ctx.nbatch() {
400 for (k, &(i, j)) in idx.iter().enumerate() {
401 let c = out.col(b, j);
402 out.data[(i, c)] = v[b * idx.len() + k]
403 }
404 }
405 Ok(out)
406 }
407 fn zeros(nr: usize, nc: usize, ctx: Self::C) -> Self {
408 Self {
409 data: DMatrix::zeros(nr, nc * ctx.nbatch()),
410 context: ctx,
411 }
412 }
413 fn from_diagonal(v: &NalgebraVec<T>) -> Self {
414 if v.context.nbatch() == 1 {
415 return Self {
416 data: DMatrix::from_diagonal(&v.data.column(0)),
417 context: v.context,
418 };
419 }
420 let mut out = Self::zeros(v.len(), v.len(), v.context);
421 for b in 0..v.context.nbatch() {
422 out.data
423 .columns_mut(out.col(b, 0), out.ncols())
424 .set_diagonal(&v.data.column(b));
425 }
426 out
427 }
428 fn gemv(&self, a: T, x: &NalgebraVec<T>, beta: T, y: &mut NalgebraVec<T>) {
429 gemv_data!(self, a, x, beta, y, "gemv")
430 }
431 fn copy_from(&mut self, o: &Self) {
432 self.context
433 .assert_broadcastable_into(o.context.nbatch(), "copy_from");
434 if self.context.nbatch() == o.context.nbatch() {
435 self.data.copy_from(&o.data);
436 return;
437 }
438 let nb = self.context.nbatch();
439 for b in 0..nb {
440 let nc = self.ncols();
441 self.data
442 .columns_mut(self.col(b, 0), nc)
443 .copy_from(&o.data.columns(o.col_bcast(b, 0, nb), nc));
444 }
445 }
446 fn set_column(&mut self, j: usize, v: &NalgebraVec<T>) {
447 self.context
448 .assert_broadcastable_into(v.context.nbatch(), "set_column");
449 if self.context.nbatch() == 1 && v.context.nbatch() == 1 {
451 self.data.column_mut(j).copy_from(&v.data.column(0));
452 return;
453 }
454 let nb = self.context.nbatch();
455 for b in 0..nb {
456 self.data
457 .column_mut(self.col(b, j))
458 .copy_from(&v.data.column(v.batch(b, nb)));
459 }
460 }
461 fn scale_add_and_assign(&mut self, x: &Self, b: T, y: &Self) {
462 self.context
463 .assert_broadcastable_into(x.context.nbatch(), "scale_add_and_assign");
464 self.context
465 .assert_broadcastable_into(y.context.nbatch(), "scale_add_and_assign");
466 let nc = self.ncols();
467 let nb = self.context.nbatch();
468 if nb == 1 {
471 let mut columns = self.data.columns_mut(0, nc);
472 columns.copy_from(&x.data.columns(0, nc));
473 columns.zip_apply(&y.data.columns(0, nc), |s, y| {
474 *s += b * y;
475 });
476 return;
477 }
478 for batch in 0..nb {
479 let mut columns = self.data.columns_mut(self.col(batch, 0), nc);
480 columns.copy_from(&x.data.columns(x.col_bcast(batch, 0, nb), nc));
481 columns.zip_apply(&y.data.columns(y.col_bcast(batch, 0, nb), nc), |s, y| {
482 *s += b * y;
483 });
484 }
485 }
486 fn new_from_sparsity(nr: usize, nc: usize, _: Option<Self::Sparsity>, ctx: Self::C) -> Self {
487 Self::zeros(nr, nc, ctx)
488 }
489}
490impl<T: NalgebraScalar> DenseMatrix for NalgebraMat<T> {
491 fn fill(&mut self, value: T) {
492 self.data.fill(value);
493 }
494 fn resize_cols(&mut self, nc: usize) {
495 let old = self.ncols();
496 if old == nc {
497 return;
498 }
499 let mut d = DMatrix::zeros(self.nrows(), nc * self.context.nbatch());
500 for b in 0..self.context.nbatch() {
501 d.columns_mut(b * nc, old.min(nc))
502 .copy_from(&self.data.columns(self.col(b, 0), old.min(nc)));
503 }
504 self.data = d
505 }
506 fn get_index(&self, i: usize, j: usize) -> T {
507 assert_eq!(
508 self.context.nbatch(),
509 1,
510 "get_index not supported for batched matrices"
511 );
512 self.data[(i, self.col(0, j))]
513 }
514 fn gemv_cols(
515 &self,
516 start: usize,
517 end: usize,
518 alpha: T,
519 x: &[T],
520 beta: T,
521 y: &mut NalgebraVec<T>,
522 ) {
523 assert!(start <= end, "gemv_cols: column range start > end");
524 assert!(
525 end - start <= crate::matrix::MAX_SMALL_COLS,
526 "gemv_cols: column range exceeds MAX_SMALL_COLS"
527 );
528 assert!(
529 x.len() >= end - start,
530 "gemv_cols: x must hold at least end - start values"
531 );
532 gemv_cols_data!(self, start, end - start, alpha, x, beta, y, "gemv_cols")
533 }
534 fn from_vec(nr: usize, nc: usize, d: Vec<T>, ctx: Self::C) -> Self {
535 assert_eq!(d.len(), nr * nc * ctx.nbatch());
536 Self {
537 data: DMatrix::from_vec(nr, nc * ctx.nbatch(), d),
538 context: ctx,
539 }
540 }
541 fn column_mut(&mut self, i: usize) -> NalgebraVecMut<'_, T> {
542 if self.context.nbatch() == 1 {
543 return NalgebraVecMut {
544 data: self.data.columns_mut(i, 1),
545 context: self.context,
546 };
547 }
548 let nr = self.nrows();
549 let nc = self.ncols();
550 let nb = self.context.nbatch();
551 assert!(i < nc, "column index out of bounds");
552 let data = NaMatrixViewMut::from_slice_with_strides_generic(
554 &mut self.data.as_mut_slice()[i * nr..],
555 nalgebra::Dyn(nr),
556 nalgebra::Dyn(nb),
557 Const,
558 nalgebra::Dyn(nr * nc),
559 );
560 NalgebraVecMut {
561 data,
562 context: self.context,
563 }
564 }
565 fn set_index(&mut self, i: usize, j: usize, v: T) {
566 assert_eq!(
567 self.context.nbatch(),
568 1,
569 "set_index not supported for batched matrices"
570 );
571 let c = self.col(0, j);
572 self.data[(i, c)] = v;
573 }
574 fn set_index_batch(&mut self, batch: usize, i: usize, j: usize, value: T) {
575 let c = self.col(batch, j);
576 self.data[(i, c)] = value;
577 }
578 fn column(&self, i: usize) -> NalgebraVecRef<'_, T> {
579 if self.context.nbatch() == 1 {
580 return NalgebraVecRef {
581 data: self.data.columns(i, 1),
582 context: self.context,
583 };
584 }
585 let nr = self.nrows();
586 let nc = self.ncols();
587 let nb = self.context.nbatch();
588 assert!(i < nc, "column index out of bounds");
589 let data = NaMatrixView::from_slice_with_strides_generic(
591 &self.data.as_slice()[i * nr..],
592 nalgebra::Dyn(nr),
593 nalgebra::Dyn(nb),
594 Const,
595 nalgebra::Dyn(nr * nc),
596 );
597 NalgebraVecRef {
598 data,
599 context: self.context,
600 }
601 }
602 fn mul_cols_by(&mut self, ncols: usize, rhs: &[T]) {
603 assert!(
604 ncols <= self.logical_ncols(),
605 "mul_cols_by: column range out of bounds"
606 );
607 assert_eq!(
608 rhs.len(),
609 ncols * ncols,
610 "mul_cols_by: rhs must hold ncols * ncols values"
611 );
612 if ncols == 0 {
613 return;
614 }
615 assert!(
616 ncols <= crate::matrix::MAX_SMALL_COLS,
617 "mul_cols_by: ncols exceeds MAX_SMALL_COLS"
618 );
619 let nrows = self.nrows();
620 let nbatch = self.context.nbatch();
621 let logical_ncols = self.logical_ncols();
622 let tile = (MUL_COLS_TILE / ncols).max(1);
626 let mut buf: [MaybeUninit<T>; MUL_COLS_TILE] =
630 [const { MaybeUninit::uninit() }; MUL_COLS_TILE];
631 let data = self.data.as_mut_slice();
632 for b in 0..nbatch {
633 let base = b * logical_ncols * nrows;
634 let mut row = 0;
635 while row < nrows {
636 let rows = tile.min(nrows - row);
637 for j in 0..ncols {
638 let src = &data[base + j * nrows + row..][..rows];
639 unsafe {
643 std::ptr::copy_nonoverlapping(
644 src.as_ptr(),
645 buf.as_mut_ptr().add(j * rows) as *mut T,
646 rows,
647 );
648 }
649 }
650 let buf =
654 unsafe { &*(&buf[..rows * ncols] as *const [MaybeUninit<T>] as *const [T]) };
655 for j in 0..ncols {
659 let w = &rhs[j * ncols..][..ncols];
660 let dst = base + j * nrows + row;
661 for i in 0..rows {
662 let mut acc = T::zero();
663 for l in 0..ncols {
664 acc += buf[l * rows + i] * w[l];
665 }
666 data[dst + i] = acc;
667 }
668 }
669 row += rows;
670 }
671 }
672 }
673
674 fn update_backward_diff(&mut self, order: usize, d: &NalgebraVec<T>) {
675 assert!(order + 2 < self.logical_ncols(), "order out of bounds");
676 self.context
677 .assert_broadcastable_into(d.context.nbatch(), "update_backward_diff");
678 let nb = self.context.nbatch();
679 for b in 0..nb {
680 let base = self.col(b, 0);
681 let d_col = d.batch(b, nb);
682 {
684 let (src, mut dst) = self.data.columns_range_pair_mut(
685 base + order + 1..base + order + 2,
686 base + order + 2..base + order + 3,
687 );
688 dst.column_mut(0).copy_from(&d.data.column(d_col));
689 dst.column_mut(0).axpy(-T::one(), &src.column(0), T::one());
690 }
691 for i in (0..=order + 1).rev() {
693 let (mut dst, src) = self
694 .data
695 .columns_range_pair_mut(base + i..base + i + 1, base + i + 1..base + i + 2);
696 dst.column_mut(0).axpy(T::one(), &src.column(0), T::one());
697 }
698 }
699 }
700}
701
702#[cfg(test)]
703mod tests {
704 use super::*;
705
706 #[test]
707 fn test_update_backward_diff() {
708 super::super::tests::test_update_backward_diff::<NalgebraMat<f64>>();
709 }
710
711 #[test]
712 fn test_index_operator() {
713 let mut mat =
714 NalgebraMat::from_vec(2, 2, vec![1.0, 3.0, 2.0, 4.0], NalgebraContext::default());
715 assert_eq!(mat[(1, 0)], 3.0);
716 mat[(1, 0)] = 30.0;
717 assert_eq!(mat.get_index(1, 0), 30.0);
718 }
719
720 #[test]
721 fn test_partition_indices_by_zero_diagonal() {
722 super::super::tests::test_partition_indices_by_zero_diagonal::<NalgebraMat<f64>>();
723 }
724
725 #[test]
726 fn test_resize_cols() {
727 super::super::tests::test_resize_cols::<NalgebraMat<f64>>();
728 }
729
730 #[test]
731 fn test_owned_rhs() {
732 super::super::tests::test_owned_rhs_m::<NalgebraMat<f64>>();
733 }
734
735 #[test]
736 fn test_batched_owned_rhs_broadcast() {
737 super::super::tests::test_batched_owned_rhs_broadcast_m::<NalgebraMat<f64>>(
738 NalgebraContext::with_nbatch(2),
739 );
740 }
741
742 #[test]
743 #[should_panic(expected = "incompatible nbatch")]
744 fn test_batched_owned_rhs_narrow() {
745 super::super::tests::test_batched_owned_rhs_narrow_m::<NalgebraMat<f64>>(
746 NalgebraContext::with_nbatch(2),
747 );
748 }
749
750 super::super::generate_matrix_tests_nonbatched!(nalgebra, NalgebraMat<f64>);
751 super::super::generate_matrix_tests_nonbatched!(nalgebra_f32, NalgebraMat<f32>);
752 super::super::generate_matrix_tests_batched!(
753 nalgebra,
754 NalgebraMat<f64>,
755 NalgebraContext::default(),
756 NalgebraContext::with_nbatch(2)
757 );
758 super::super::generate_matrix_tests_batched!(
759 nalgebra_f32,
760 NalgebraMat<f32>,
761 NalgebraContext::default(),
762 NalgebraContext::with_nbatch(2)
763 );
764 super::super::generate_dense_matrix_tests_nonbatched!(nalgebra, NalgebraMat<f64>);
765 super::super::generate_dense_matrix_tests_nonbatched!(nalgebra_f32, NalgebraMat<f32>);
766 super::super::generate_dense_matrix_tests_batched!(
767 nalgebra,
768 NalgebraMat<f64>,
769 NalgebraContext::default(),
770 NalgebraContext::with_nbatch(2)
771 );
772 super::super::generate_dense_matrix_tests_batched!(
773 nalgebra_f32,
774 NalgebraMat<f32>,
775 NalgebraContext::default(),
776 NalgebraContext::with_nbatch(2)
777 );
778}