1use std::ops::{Add, AddAssign, Neg, Sub, SubAssign, Mul, MulAssign, Range};
5use std::fmt::{Display, Debug};
6use delegate::delegate;
7use itertools::{Itertools, repeat_n};
8use nalgebra_sparse::na::{Scalar, ClosedAddAssign, ClosedSubAssign, ClosedMulAssign};
9use nalgebra_sparse::{CscMatrix, CooMatrix};
10use num_traits::{Zero, One, ToPrimitive};
11use auto_impl_ops::auto_ops;
12use yui_core::abst::{Ring, RingOps};
13use crate::Perm;
14use crate::dense::*;
15use super::sp_vec::SpVec;
16use super::triang::TriangularType;
17
18#[derive(Clone)]
28pub struct SpMat<R> {
29 inner: CscMatrix<R>
30}
31
32impl<R> SpMat<R> {
33 pub fn try_from_csc_data(
34 num_rows: usize,
35 num_cols: usize,
36 col_offsets: Vec<usize>,
37 row_indices: Vec<usize>,
38 values: Vec<R>,
39 ) -> Option<Self> {
40 let csc = CscMatrix::try_from_csc_data(num_rows, num_cols, col_offsets, row_indices, values);
41 csc.ok().map(SpMat::from)
42 }
43
44 pub(crate) fn inner(&self) -> &CscMatrix<R> {
45 &self.inner
46 }
47
48 pub(crate) fn into_inner(self) -> CscMatrix<R> {
49 self.inner
50 }
51
52 pub fn csc_data(&self) -> (&[usize], &[usize], &[R]) {
53 self.inner.csc_data()
54 }
55
56 pub fn disassemble(self) -> (Vec<usize>, Vec<usize>, Vec<R>) {
57 self.inner.disassemble()
58 }
59
60 pub fn zero(shape: (usize, usize)) -> Self {
61 let csc = CscMatrix::zeros(shape.0, shape.1);
62 Self::from(csc)
63 }
64
65 pub fn is_zero(&self) -> bool
66 where R: Zero {
67 self.inner.values().iter().all(|a| a.is_zero())
68 }
69
70 pub fn id(n: usize) -> Self
71 where R: Scalar + One {
72 let csc = CscMatrix::identity(n);
73 Self::from(csc)
74 }
75
76 pub fn is_id(&self) -> bool
77 where R: Scalar + One + Zero {
78 self.is_square() && self.iter().all(|(i, j, a)|
79 (i == j && a.is_one()) || (i != j && a.is_zero())
80 )
81 }
82
83 pub fn is_triang(&self, t: TriangularType) -> bool
84 where R: Zero {
85 if self.n_rows() != self.n_cols() {
86 return false
87 }
88
89 if t.is_upper() {
90 self.iter_nz().all(|(i, j, _)| i <= j )
91 } else {
92 self.iter_nz().all(|(i, j, _)| i >= j )
93 }
94 }
95
96 pub fn iter(&self) -> impl Iterator<Item = (usize, usize, &R)> {
98 self.inner.triplet_iter()
99 }
100
101 pub fn iter_nz(&self) -> impl Iterator<Item = (usize, usize, &R)>
103 where R: Zero {
104 self.iter().filter(|e| !e.2.is_zero())
105 }
106
107 pub fn into_dense(self) -> Mat<R>
108 where R: Scalar + Zero + ClosedAddAssign {
109 self.into()
110 }
111
112 pub fn nnz(&self) -> usize {
113 self.inner.nnz()
114 }
115
116 pub fn density(&self) -> f64 {
117 let (m, n) = self.shape();
118 if m == 0 || n == 0 {
119 return 0.0
120 }
121
122 let nnz = self.nnz().to_f64().unwrap();
123 let total = (m * n).to_f64().unwrap();
124
125 nnz / total
126 }
127
128 pub fn redundancy(&self) -> f64
129 where R: Zero {
130 let nnz = self.nnz().to_f64().unwrap();
131 let red = self.iter().filter(|(_, _, a)| a.is_zero()).count().to_f64().unwrap();
132 red / nnz
133 }
134
135 pub fn mean_weight(&self) -> f64
136 where R: Ring, for<'x> &'x R: RingOps<R> {
137 let nnz = self.nnz().to_f64().unwrap();
138 let w = self.iter().map(|(_, _, a)| a.c_weight()).sum::<f64>();
139 w / nnz
140 }
141
142 pub fn block_diag<I>(blocks: I) -> SpMat<R>
143 where I: IntoIterator<Item = SpMat<R>> {
144 let mut shape = (0, 0);
145 let mut col_offsets: Vec<usize> = vec![];
146 let mut row_indices: Vec<usize> = vec![];
147 let mut values: Vec<R> = vec![];
148
149 for a in blocks {
150 let a_shape = a.shape();
151 let (a_cols, a_rows, mut a_vals) = a.disassemble();
152
153 col_offsets.extend(a_cols.iter().map(|i| i + values.len()));
154 col_offsets.pop(); row_indices.extend(a_rows.iter().map(|i| i + shape.0));
157 values.append(&mut a_vals);
158
159 shape.0 += a_shape.0;
160 shape.1 += a_shape.1;
161 }
162 col_offsets.push(values.len());
163
164 SpMat::try_from_csc_data(shape.0, shape.1, col_offsets, row_indices, values).unwrap()
165 }
166
167 pub fn map<F, S>(self, f: F) -> SpMat<S>
168 where F: Fn(R) -> S {
169 let (m, n) = self.shape();
170 let (cols, rows, vals) = self.disassemble();
171 let vals = vals.into_iter().map(f).collect_vec();
172 SpMat::<S>::try_from_csc_data(m, n, cols, rows, vals).unwrap()
173 }
174
175 pub(crate) fn col_data(&self, j: usize) -> (&[usize], &[R]) {
178 let (col_offsets, row_indices, values) = self.inner.csc_data();
179 let range = col_offsets[j]..col_offsets[j + 1];
180 (&row_indices[range.clone()], &values[range])
181 }
182}
183
184impl<R> SpMat<R>
185where R: Scalar + Clone + Zero + ClosedAddAssign {
186 pub fn from_entries<T>(shape: (usize, usize), entries: T) -> Self
189 where T: IntoIterator<Item = (usize, usize, R)> {
190 let mut coo = CooMatrix::new(shape.0, shape.1);
191 for (i, j, a) in entries {
192 if a.is_zero() {
193 continue;
194 }
195 coo.push(i, j, a)
196 }
197 let csc = CscMatrix::from(&coo);
198 Self::from(csc)
199 }
200
201 pub fn from_col_vecs<I>(nrows: usize, vecs: I) -> Self
203 where I: IntoIterator<Item = SpVec<R>> {
204 let mut col_offsets = vec![0];
205 let mut row_indices = vec![];
206 let mut values = vec![];
207
208 for v in vecs.into_iter() {
209 assert_eq!(nrows, v.dim());
210 let (_, mut v_rows, mut v_values) = v.drop_zeros().into_inner().disassemble();
211
212 row_indices.append(&mut v_rows);
213 values.append(&mut v_values);
214 col_offsets.push(row_indices.len());
215 }
216
217 let ncols = col_offsets.len() - 1;
218 SpMat::try_from_csc_data(nrows, ncols, col_offsets, row_indices, values).unwrap()
219 }
220
221 pub fn from_row_major<I>(shape: (usize, usize), data: I) -> Self
222 where I: IntoIterator<Item = R> {
223 let n = shape.1;
224 Self::from_entries(
225 shape,
226 data.into_iter().enumerate().map(|(k, a)| {
227 let (i, j) = (k / n, k % n);
228 (i, j, a)
229 })
230 )
231 }
232
233 pub fn scalar(n: usize, a: &R) -> Self {
234 Self::from_entries((n, n), (0..n).map(|i| (i, i, a.clone())))
235 }
236
237 pub fn diag<I>(shape: (usize, usize), entries: I) -> Self
238 where I: IntoIterator<Item = R> {
239 Self::from_entries(shape, entries.into_iter().enumerate().map(|(i, a)| (i, i, a)))
240 }
241
242 pub fn is_diag(&self) -> bool {
243 self.iter_nz().all(|(i, j, _)| i == j)
244 }
245
246 pub fn col_vec(&self, j: usize) -> SpVec<R>
247 where R: Scalar + Zero + ClosedAddAssign {
248 let col = self.inner.col(j);
249 let row_indices = col.row_indices().to_vec();
250 let values = col.values().to_vec();
251 SpVec::try_from_csc_data(self.n_rows(), row_indices, values).unwrap()
252 }
253
254 pub fn transpose(&self) -> Self {
255 self.inner.transpose().into()
256 }
257
258 pub fn extract<F>(&self, shape: (usize, usize), f: F) -> SpMat<R>
261 where F: Fn(usize, usize) -> Option<(usize, usize)> {
262 SpMat::from_entries(shape, self.iter().filter_map(|(i, j, a)|
263 f(i, j).map(|(i, j)| (i, j, a.clone()))
264 ))
265 }
266
267 pub fn permute(&self, p: &Perm, q: &Perm) -> SpMat<R> {
268 self.extract(self.shape(), |i, j| Some((p.at(i), q.at(j))))
269 }
270
271 pub fn permute_rows(&self, p: &Perm) -> SpMat<R> {
272 let id = Perm::id(self.n_cols());
273 self.permute(p, &id)
274 }
275
276 pub fn permute_cols(&self, q: &Perm) -> SpMat<R> {
277 let id = Perm::id(self.n_rows());
278 self.permute(&id, q)
279 }
280
281 pub fn permute_and_split(&self, p: &Perm, q: &Perm, r: usize) -> [SpMat<R>; 4] {
289 use std::cmp::Ordering::Less;
290
291 let (m, n) = self.shape();
292 assert!(r <= m && r <= n);
293
294 let [mut a0, mut a1, mut a2, mut a3] = [vec![], vec![], vec![], vec![]];
295
296 for (i, j, v) in self.iter() {
297 let (pi, qj) = (p.at(i), q.at(j));
298 let v = v.clone();
299 match (pi.cmp(&r), qj.cmp(&r)) {
300 (Less, Less) => a0.push((pi, qj, v)),
301 (Less, _ ) => a1.push((pi, qj - r, v)),
302 (_ , Less) => a2.push((pi - r, qj, v)),
303 (_ , _ ) => a3.push((pi - r, qj - r, v)),
304 }
305 }
306 [
307 SpMat::from_entries((r, r ), a0),
308 SpMat::from_entries((r, n - r), a1),
309 SpMat::from_entries((m - r, r ), a2),
310 SpMat::from_entries((m - r, n - r), a3),
311 ]
312 }
313
314 pub fn submat(&self, rows: Range<usize>, cols: Range<usize>) -> SpMat<R> {
315 let (i0, i1) = (rows.start, rows.end);
316 let (j0, j1) = (cols.start, cols.end);
317
318 assert!(i0 <= i1 && i1 <= self.n_rows());
319 assert!(j0 <= j1 && j1 <= self.n_cols());
320
321 let shape = (i1 - i0, j1 - j0);
322 self.extract(shape, |i, j|
323 (rows.contains(&i) && cols.contains(&j)).then( ||
324 (i - i0, j - j0)
325 )
326 )
327 }
328
329 pub fn submat_rows(&self, rows: Range<usize>) -> SpMat<R> {
330 let n = self.n_cols();
331 self.submat(rows, 0 .. n)
332 }
333
334 pub fn submat_cols(&self, cols: Range<usize>) -> SpMat<R> {
335 let m = self.n_rows();
336 self.submat(0 .. m, cols)
337 }
338
339 pub fn block_split(self, point: (usize, usize)) -> [SpMat<R>; 4] {
340 let (m, n) = self.shape();
341 let (k, l) = point;
342 assert!(k <= m);
343 assert!(l <= n);
344
345 let (offsets, rows, vals) = self.disassemble();
346
347 let (mut a_rows, mut a_vals, mut a_offs) = (vec![], vec![], vec![0]);
348 let (mut b_rows, mut b_vals, mut b_offs) = (vec![], vec![], vec![0]);
349 let (mut c_rows, mut c_vals, mut c_offs) = (vec![], vec![], vec![0]);
350 let (mut d_rows, mut d_vals, mut d_offs) = (vec![], vec![], vec![0]);
351
352 let mut vals_iter = vals.into_iter();
353
354 for j in 0..n {
355 let range = offsets[j]..offsets[j + 1];
356 let col_rows = &rows[range];
357 let split = col_rows.partition_point(|&i| i < k);
358 let (top_rows_src, bot_rows_src) = col_rows.split_at(split);
359
360 let (top_rows, top_vals, top_offs, bot_rows, bot_vals, bot_offs) = if j < l {
361 (&mut a_rows, &mut a_vals, &mut a_offs, &mut c_rows, &mut c_vals, &mut c_offs)
362 } else {
363 (&mut b_rows, &mut b_vals, &mut b_offs, &mut d_rows, &mut d_vals, &mut d_offs)
364 };
365
366 top_rows.extend_from_slice(top_rows_src);
367 top_vals.extend(vals_iter.by_ref().take(top_rows_src.len()));
368 top_offs.push(top_rows.len());
369
370 bot_rows.extend(bot_rows_src.iter().map(|&i| i - k));
371 bot_vals.extend(vals_iter.by_ref().take(bot_rows_src.len()));
372 bot_offs.push(bot_rows.len());
373 }
374
375 [
376 SpMat::try_from_csc_data(k, l, a_offs, a_rows, a_vals).unwrap(),
377 SpMat::try_from_csc_data(k, n - l, b_offs, b_rows, b_vals).unwrap(),
378 SpMat::try_from_csc_data(m - k, l, c_offs, c_rows, c_vals).unwrap(),
379 SpMat::try_from_csc_data(m - k, n - l, d_offs, d_rows, d_vals).unwrap(),
380 ]
381 }
382
383 pub fn h_split(self, k: usize) -> [SpMat<R>; 2] {
384 let (m, n) = self.shape();
385 assert!(k <= n);
386
387 let [a, b, ..] = self.block_split((m, k));
388 [a, b]
389 }
390
391 pub fn v_split(self, k: usize) -> [SpMat<R>; 2] {
392 let (m, n) = self.shape();
393 assert!(k <= m);
394
395 let [a, _, b, _] = self.block_split((k, n));
396 [a, b]
397 }
398
399 pub fn block_combine(blocks: [SpMat<R>; 4]) -> SpMat<R> {
400 let [a, b, c, d] = blocks;
401
402 assert_eq!(a.n_rows(), b.n_rows());
403 assert_eq!(c.n_rows(), d.n_rows());
404 assert_eq!(a.n_cols(), c.n_cols());
405 assert_eq!(b.n_cols(), d.n_cols());
406
407 let (m0, m1) = (a.n_rows(), c.n_rows());
408 let m = m0 + m1;
409 let (n0, n1) = (a.n_cols(), b.n_cols());
410 let n = n0 + n1;
411 let nnz = a.nnz() + b.nnz() + c.nnz() + d.nnz();
412
413 let mut a = ColSource::from(a);
414 let mut b = ColSource::from(b);
415 let mut c = ColSource::from(c);
416 let mut d = ColSource::from(d);
417
418 let mut col_offsets = Vec::with_capacity(n + 1);
419 let mut row_indices = Vec::with_capacity(nnz);
420 let mut values = Vec::with_capacity(nnz);
421 col_offsets.push(0);
422
423 let mut push_col = |top: &mut ColSource<R>, bot: &mut ColSource<R>, j: usize| {
424 let (top_rows, top_vals) = top.take_col(j);
425 row_indices.extend_from_slice(top_rows);
426 values.extend(top_vals);
427
428 let (bot_rows, bot_vals) = bot.take_col(j);
429 row_indices.extend(bot_rows.iter().map(|i| i + m0));
430 values.extend(bot_vals);
431
432 col_offsets.push(row_indices.len());
433 };
434
435 for j in 0..n0 { push_col(&mut a, &mut c, j); }
436 for j in 0..n1 { push_col(&mut b, &mut d, j); }
437
438 SpMat::try_from_csc_data(m, n, col_offsets, row_indices, values).unwrap()
439 }
440
441 pub fn h_stack(left: Self, right: Self) -> Self {
442 assert_eq!(left.n_rows(), right.n_rows());
443 let (l_cols, r_cols) = (left.n_cols(), right.n_cols());
444 Self::block_combine([
445 left,
446 right,
447 SpMat::zero((0, l_cols)),
448 SpMat::zero((0, r_cols)),
449 ])
450 }
451
452 pub fn v_stack(top: Self, bot: Self) -> Self {
453 assert_eq!(top.n_cols(), bot.n_cols());
454 let (t_rows, b_rows) = (top.n_rows(), bot.n_rows());
455 Self::block_combine([
456 top,
457 SpMat::zero((t_rows, 0)),
458 bot,
459 SpMat::zero((b_rows, 0)),
460 ])
461 }
462
463 pub fn extend_by_zero(&mut self, add_rows: usize, add_cols: usize) {
464 let (m, n) = self.shape();
465 let l = std::mem::take(&mut self.inner);
466 let (mut col_offsets, row_indices, values) = l.disassemble();
467 let last = *col_offsets.last().unwrap();
468 col_offsets.extend(repeat_n(last, add_cols));
469
470 self.inner = CscMatrix::try_from_csc_data(
471 m + add_rows, n + add_cols,
472 col_offsets, row_indices, values
473 ).unwrap();
474 }
475
476 pub fn row_perm_mat(p: &Perm) -> Self
478 where R: One {
479 let n = p.len();
480 Self::from_entries((n, n), (0..n).map(|i|
481 (p.at(i), i, R::one())
482 ))
483 }
484
485 pub fn col_perm_mat(p: &Perm) -> Self
487 where R: One {
488 let n = p.len();
489 Self::from_entries((n, n), (0..n).map(|i|
490 (i, p.at(i), R::one())
491 ))
492 }
493}
494
495struct ColSource<R> {
498 offsets: Vec<usize>,
499 rows: Vec<usize>,
500 vals: std::vec::IntoIter<R>,
501 pos: usize,
502}
503
504impl<R> ColSource<R> {
505 fn from(m: SpMat<R>) -> Self {
506 let (offsets, rows, vals) = m.disassemble();
507 Self { offsets, rows, vals: vals.into_iter(), pos: 0 }
508 }
509
510 fn take_col(&mut self, j: usize) -> (&[usize], impl Iterator<Item = R> + '_) {
513 debug_assert_eq!(self.pos, self.offsets[j]);
514 let range = self.offsets[j]..self.offsets[j + 1];
515 let count = range.len();
516 self.pos += count;
517 (&self.rows[range], self.vals.by_ref().take(count))
518 }
519}
520
521impl<R> MatTrait for SpMat<R> {
522 fn shape(&self) -> (usize, usize) {
523 (self.inner.nrows(), self.inner.ncols())
524 }
525}
526
527impl<R> From<CscMatrix<R>> for SpMat<R> {
528 fn from(inner: CscMatrix<R>) -> Self {
529 Self { inner }
530 }
531}
532
533impl<R> From<Mat<R>> for SpMat<R>
534where R: Scalar + Zero {
535 fn from(value: Mat<R>) -> Self {
536 let csc = CscMatrix::from(value.inner());
537 Self::from(csc)
538 }
539}
540
541impl<R> Default for SpMat<R> {
542 fn default() -> Self {
543 Self::zero((0, 0))
544 }
545}
546
547impl<R: PartialEq + Zero> PartialEq for SpMat<R> {
548 fn eq(&self, other: &Self) -> bool {
549 self.shape() == other.shape() && self.iter_nz().eq(other.iter_nz())
550 }
551}
552
553impl<R: Eq + Zero> Eq for SpMat<R> {}
554
555impl<R> Neg for SpMat<R>
556where R: Scalar + Neg<Output = R> {
557 type Output = Self;
558 fn neg(self) -> Self::Output {
559 Self::from(-self.inner)
560 }
561}
562
563impl<R> Neg for &SpMat<R>
564where R: Scalar + Neg<Output = R> {
565 type Output = SpMat<R>;
566 fn neg(self) -> Self::Output {
567 SpMat::from(-&self.inner)
568 }
569}
570
571macro_rules! impl_binop {
573 ($trait:ident, $method:ident) => {
574 #[auto_ops]
575 impl<R> $trait<&SpMat<R>> for &SpMat<R>
576 where R: Scalar + ClosedAddAssign + ClosedSubAssign + ClosedMulAssign + Zero + One + Neg<Output = R> {
577 type Output = SpMat<R>;
578 fn $method(self, rhs: &SpMat<R>) -> Self::Output {
579 let res = (&self.inner).$method(&rhs.inner);
580 SpMat::from(res)
581 }
582 }
583 };
584}
585
586impl_binop!(Add, add);
587impl_binop!(Sub, sub);
588impl_binop!(Mul, mul);
589
590impl<R> Display for SpMat<R>
591where R: Display + Debug {
592 delegate! { to self.inner {
593 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
594 }}
595}
596
597impl<R> Debug for SpMat<R>
598where R: Display + Debug {
599 delegate! { to self.inner {
600 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
601 }}
602}
603
604#[cfg(feature = "serde")]
605impl<R> serde::Serialize for SpMat<R>
606where R: Clone + serde::Serialize {
607 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
608 where S: serde::Serializer {
609 self.inner.serialize(serializer)
610 }
611}
612
613#[cfg(feature = "serde")]
614impl<'de, R> serde::Deserialize<'de> for SpMat<R>
615where R: Clone + serde::Deserialize<'de> {
616 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
617 where D: serde::Deserializer<'de> {
618 let inner = CscMatrix::deserialize(deserializer)?;
619 let res = Self::from(inner);
620 Ok(res)
621 }
622}
623
624#[cfg(test)]
625impl<R> SpMat<R>
626where R: Scalar + Zero + One + ClosedAddAssign {
627 pub fn rand(shape: (usize, usize), density: f64) -> Self {
628 use itertools::iproduct;
629 use rand::RngExt;
630
631 let (m, n) = shape;
632 let range = iproduct!(0..m, 0..n);
633 let mut rng = rand::rng();
634
635 Self::from_entries(shape, range.filter_map(|(i, j)|
636 if rng.random::<f64>() < density {
637 Some((i, j, R::one()))
638 } else {
639 None
640 }
641 ))
642 }
643}
644
645#[cfg(test)]
646pub(super) mod tests {
647 use itertools::Itertools;
648 use yui_core::num::Ratio;
649 use crate::Perm;
650
651 use super::*;
652
653 #[test]
654 fn init() {
655 let a = SpMat::from_entries((2, 2), [
656 (0, 0, 1),
657 (0, 1, 2),
658 (1, 0, 3),
659 (1, 1, 4)
660 ]);
661 assert_eq!(a.disassemble(), (vec![0, 2, 4], vec![0, 1, 0, 1], vec![1, 3, 2, 4]));
662 }
663
664 #[test]
665 fn init_ratio() {
666 type R = Ratio<i64>;
667 let vals = (0..4).map(|i| R::new(i + 1, 5)).collect_vec();
668 let a = SpMat::from_entries((2, 2), [
669 (0, 0, vals[0]),
670 (0, 1, vals[2]),
671 (1, 0, vals[1]),
672 (1, 1, vals[3])
673 ]);
674 assert_eq!(a.disassemble(), (vec![0, 2, 4], vec![0, 1, 0, 1], vals));
675 }
676
677 #[test]
678 fn from_row_major() {
679 let a = SpMat::from_row_major((2, 2), [1,2,3,4]);
680 assert_eq!(a.disassemble(), (vec![0, 2, 4], vec![0, 1, 0, 1], vec![1, 3, 2, 4]));
681 }
682
683 #[test]
684 fn to_dense() {
685 let a = SpMat::from_entries((2, 2), [
686 (0, 0, 1),
687 (0, 1, 2),
688 (1, 0, 3),
689 (1, 1, 4)
690 ]);
691 assert_eq!(a.into_dense(), Mat::from_row_major((2, 2), [1,2,3,4]));
692 }
693
694 #[test]
695 fn permute() {
696 let p = Perm::new(vec![1,2,3,0]);
697 let q = Perm::new(vec![3,0,2,1]);
698 let a = SpMat::from_row_major((4,4), 0..16);
699 let b = a.permute(&p, &q);
700 assert_eq!(b, SpMat::from_row_major((4,4), vec![
701 13, 15, 14, 12,
702 1, 3, 2, 0,
703 5, 7, 6, 4,
704 9, 11, 10, 8,
705 ]));
706 }
707
708 #[test]
709 fn permute_and_split_identity() {
710 let a = SpMat::from_row_major((2, 2), [1, 2, 3, 4]);
713 let id = Perm::id(2);
714 let [a0, a1, a2, a3] = a.permute_and_split(&id, &id, 1);
715 assert_eq!(a0, SpMat::from_row_major((1, 1), [1]));
716 assert_eq!(a1, SpMat::from_row_major((1, 1), [2]));
717 assert_eq!(a2, SpMat::from_row_major((1, 1), [3]));
718 assert_eq!(a3, SpMat::from_row_major((1, 1), [4]));
719 }
720
721 #[test]
722 fn permute_and_split_with_perm() {
723 let a = SpMat::from_row_major((3, 3), [
728 1, 2, 3,
729 4, 5, 6,
730 7, 8, 9,
731 ]);
732 let p = Perm::new(vec![2, 0, 1]);
733 let q = Perm::new(vec![1, 2, 0]);
734 let [a0, a1, a2, a3] = a.permute_and_split(&p, &q, 2);
735 assert_eq!(a0, SpMat::from_row_major((2, 2), [6, 4, 9, 7]));
740 assert_eq!(a1, SpMat::from_row_major((2, 1), [5, 8]));
741 assert_eq!(a2, SpMat::from_row_major((1, 2), [3, 1]));
742 assert_eq!(a3, SpMat::from_row_major((1, 1), [2]));
743 }
744
745 #[test]
746 fn submat() {
747 let a = SpMat::from_row_major((5, 6), 0..30);
748 let b = a.submat(1..3, 2..5);
749 assert_eq!(b, SpMat::from_row_major((2,3), vec![
750 8, 9, 10,
751 14, 15, 16
752 ]));
753 }
754
755 #[test]
756 fn transpose() {
757 let a = SpMat::from_row_major((3,4), 0..12);
758 let b = a.transpose();
759
760 assert_eq!(b, SpMat::from_row_major((4,3), vec![
761 0, 4, 8,
762 1, 5, 9,
763 2, 6, 10,
764 3, 7, 11,
765 ]));
766 }
767
768 #[test]
769 fn h_stack() {
770 let a = SpMat::from_row_major((4, 3), 0..12);
771 let b = SpMat::from_row_major((4, 2), 12..20);
772 let c = SpMat::h_stack(a, b);
773
774 assert_eq!(c, SpMat::from_row_major((4,5), vec![
775 0, 1, 2, 12, 13,
776 3, 4, 5, 14, 15,
777 6, 7, 8, 16, 17,
778 9, 10, 11, 18, 19,
779 ]));
780 }
781
782 #[test]
783 fn v_stack() {
784 let a = SpMat::from_row_major((2, 3), 0..6);
785 let b = SpMat::from_row_major((3, 3), 6..15);
786 let c = SpMat::v_stack(a, b);
787
788 assert_eq!(c, SpMat::from_row_major((5, 3), vec![
789 0, 1, 2,
790 3, 4, 5,
791 6, 7, 8,
792 9, 10, 11,
793 12, 13, 14,
794 ]));
795 }
796
797 #[test]
798 fn extend_by_zero() {
799 let mut a = SpMat::from_row_major((2, 2), [1,2,3,4]);
801 a.extend_by_zero(1, 2);
802 assert_eq!(a.shape(), (3, 4));
803 assert_eq!(a, SpMat::from_row_major((3, 4), [1,2,0,0, 3,4,0,0, 0,0,0,0]));
804 }
805
806 #[test]
807 fn row_perm() {
808 let a = SpMat::from_row_major((3, 4), 0..12);
809 let p = Perm::new(vec![2,0,1]);
810 let q = SpMat::row_perm_mat(&p);
811 assert!(q * &a == a.permute_rows(&p))
812 }
813
814 #[test]
815 fn col_perm() {
816 let a = SpMat::from_row_major((3, 4), 0..12);
817 let p = Perm::new(vec![2,0,1,3]);
818 let q = SpMat::col_perm_mat(&p);
819 assert!(&a * q == a.permute_cols(&p))
820 }
821
822 #[test]
823 fn diag() {
824 let d = SpMat::diag((3, 4), [1, 2, 3]);
825 assert_eq!(d, SpMat::from_row_major((3, 4), [
826 1, 0, 0, 0,
827 0, 2, 0, 0,
828 0, 0, 3, 0,
829 ]));
830 assert!(d.is_diag());
831 }
832
833 #[test]
834 fn is_diag_false() {
835 let a = SpMat::from_row_major((2, 2), [1, 2, 0, 3]);
836 assert!(!a.is_diag());
837 }
838
839 #[test]
840 fn block_diag() {
841 let a = SpMat::from_row_major((2, 2), 1..=4);
842 let b = SpMat::from_row_major((1, 3), 5..=7);
843 let c = SpMat::from_row_major((2, 1), 8..=9);
844 let d = SpMat::block_diag([a, b, c]);
845 assert_eq!(d, SpMat::from_row_major((5, 6), [
846 1,2,0,0,0,0,
847 3,4,0,0,0,0,
848 0,0,5,6,7,0,
849 0,0,0,0,0,8,
850 0,0,0,0,0,9
851 ]))
852 }
853
854 #[test]
855 #[cfg(feature = "serde")]
856 fn serialize() {
857 let a = SpMat::from_row_major((3, 4), (0..12).map(|x| x % 5));
858 let ser = serde_json::to_string(&a).unwrap();
859 let des = serde_json::from_str(&ser).unwrap();
860 assert_eq!(a, des);
861 }
862}