mop_structs/matrix/csr_matrix/
mod.rs

1//! CSR (Compressed Sparse Row) matrix.
2//!
3//! See [Wikipedia](https://en.wikipedia.org/wiki/Sparse_matrix).
4
5#[cfg(feature = "rand")]
6mod csr_matrix_rnd;
7mod csr_matrix_row_constructor;
8mod csr_matrix_row_iter_impls;
9#[cfg(feature = "rayon")]
10mod csr_matrix_row_par_iter_impls;
11
12pub use self::{
13  csr_matrix_row_constructor::CsrMatrixRowConstructor,
14  csr_matrix_row_iter_impls::{CsrMatrixRowIter, CsrMatrixRowIterMut},
15};
16use crate::{
17  dim::Dim,
18  prelude::{Array, DynDenseStoMut, DynDenseStoRef, Matrix, StDenseStoMut, StDenseStoRef},
19  utils::{are_in_upper_bound, does_not_have_duplicates},
20  vec::{
21    css::{CssSlice, CssSliceMut},
22    VecArray,
23  },
24};
25use core::ops::Range;
26
27/// This structure can hold differents mixed types of indexed storages.
28#[cfg_attr(
29  feature = "serde1",
30  derive(mop_common_deps::serde::Deserialize, mop_common_deps::serde::Serialize)
31)]
32#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, PartialOrd)]
33pub struct CsrMatrix<DS, US> {
34  data: DS,
35  dim: Dim<[usize; 2]>,
36  indcs: US,
37  ptrs: US,
38}
39
40pub type CsrMatrixArray<DA, UA> = CsrMatrix<DA, UA>;
41#[cfg(feature = "std")]
42pub type CsrMatrixVec<T> = CsrMatrix<Vec<T>, Vec<usize>>;
43pub type CsrMatrixVecArray<DA, UA> = CsrMatrix<VecArray<DA>, VecArray<UA>>;
44pub type CsrMatrixRef<'a, T> = CsrMatrix<&'a [T], &'a [usize]>;
45
46#[cfg(feature = "std")]
47impl<T> CsrMatrixVec<T> {
48  #[cfg(feature = "rand")]
49  pub fn new_rnd<F, R>(shape: [usize; 2], nnz: usize, rng: &mut R, cb: F) -> Self
50  where
51    F: FnMut(&mut R, [usize; 2]) -> T,
52    R: mop_common_deps::rand::Rng,
53  {
54    let dim: Dim<[usize; 2]> = shape.into();
55    let capacity = dim.rows() * dim.cols();
56    assert!(nnz <= capacity);
57    let mut cmr = self::csr_matrix_rnd::CsrMatrixRnd {
58      data: Vec::with_capacity(nnz),
59      dim: &dim,
60      indcs: Vec::with_capacity(nnz),
61      nnz,
62      ptrs: Vec::with_capacity(dim.rows() + 1),
63      rng,
64    };
65    cmr.fill_ptrs();
66    cmr.fill_indcs();
67    cmr.fill_data(cb);
68    CsrMatrixVec::new([dim.rows(), dim.cols()], cmr.data, cmr.indcs, cmr.ptrs)
69  }
70
71  pub fn with_vec_capacity(shape: [usize; 2], nnz: usize) -> Self {
72    let mut ptrs = Vec::with_capacity(shape[0] + 1);
73    ptrs.push(0);
74    CsrMatrix {
75      data: Vec::with_capacity(nnz),
76      dim: [0, shape[1]].into(),
77      indcs: Vec::with_capacity(nnz),
78      ptrs,
79    }
80  }
81}
82
83impl<DA, UA> CsrMatrixVecArray<DA, UA>
84where
85  DA: Array,
86  UA: Array<Item = usize>,
87{
88  #[cfg(feature = "rand")]
89  pub fn new_rnd<F, R>(shape: [usize; 2], nnz: usize, rng: &mut R, cb: F) -> Self
90  where
91    F: FnMut(&mut R, [usize; 2]) -> DA::Item,
92    R: mop_common_deps::rand::Rng,
93  {
94    let dim: Dim<[usize; 2]> = shape.into();
95    let capacity = dim.rows() * dim.cols();
96    assert!(nnz <= capacity);
97    let mut cmr = self::csr_matrix_rnd::CsrMatrixRnd {
98      data: VecArray::<DA>::with_capacity(),
99      dim: &dim,
100      indcs: VecArray::<UA>::with_capacity(),
101      nnz,
102      ptrs: VecArray::<UA>::with_capacity(),
103      rng,
104    };
105    cmr.fill_ptrs();
106    cmr.fill_indcs();
107    cmr.fill_data(cb);
108    CsrMatrixVecArray::new([dim.rows(), dim.cols()], cmr.data, cmr.indcs, cmr.ptrs)
109  }
110
111  pub fn with_vec_array(cols: usize) -> Self {
112    let mut ptrs_vec_array = VecArray::with_capacity();
113    ptrs_vec_array.push(0);
114    CsrMatrixVecArray {
115      data: VecArray::with_capacity(),
116      dim: [0, cols].into(),
117      indcs: VecArray::with_capacity(),
118      ptrs: ptrs_vec_array,
119    }
120  }
121}
122
123impl<DS, US> CsrMatrix<DS, US>
124where
125  DS: StDenseStoRef,
126  US: StDenseStoRef<Item = usize>,
127{
128  /// Creates a new [`CsrMatrix`](CsrMatrix) from raw parameters.
129  ///
130  /// # Arguments
131  ///
132  /// * `shape` - An array containing the number of rows and columns.
133  /// * `data` - The matrix data.
134  /// * `indcs` - Each column index of its corresponding data.
135  /// * `ptrs` - The length of each row.
136  ///
137  /// # Examples
138  ///
139  /// ```rust
140  /// use mop_structs::matrix::csr_matrix::CsrMatrixArray;
141  /// let _ = CsrMatrixArray::new([2, 4], [1, 2, 3], [0, 1, 2], [0, 3, 3]);
142  /// ```
143  ///
144  /// # Assertions
145  ///
146  /// * The length of `data` must be equal the length of `indcs`.
147  ///
148  /// ```should_panic
149  /// use mop_structs::matrix::csr_matrix::CsrMatrixRef;
150  /// let _ = CsrMatrixRef::new([2, 4], &[1, 2, 3], &[], &[0, 3, 3]);
151  /// ```
152  ///
153  /// * The length of `data` is greater than the number of rows times the number of columns.
154  ///
155  /// ```should_panic
156  /// use mop_structs::matrix::csr_matrix::CsrMatrixRef;
157  /// let _ = CsrMatrixRef::new(
158  ///     [2, 4], &[1, 2, 3, 4, 5, 6, 7, 8, 9], &[0, 1, 2, 3, 0, 1, 2, 3, 0], &[0, 4, 8]
159  /// );
160  /// ```
161  ///
162  /// * The length of `ptrs` must be equal the number of rows plus 1.
163  ///
164  /// ```should_panic
165  /// use mop_structs::matrix::csr_matrix::CsrMatrixRef;
166  /// let _ = CsrMatrixRef::new([2, 4], &[1, 2, 3], &[0, 1, 2], &[0, 3, 3, 3, 3]);
167  /// ```
168  ///
169  /// * Column indices must be less than the number of columns.
170  ///
171  /// ```should_panic
172  /// use mop_structs::matrix::csr_matrix::CsrMatrixRef;
173  /// let _ = CsrMatrixRef::new([2, 4], &[1, 2, 3], &[0, 1, 9], &[0, 3, 3]);
174  /// ```
175  ///
176  /// * Column indices of a row must be unique.
177  ///
178  /// ```should_panic
179  /// use mop_structs::matrix::csr_matrix::CsrMatrixRef;
180  /// let _ = CsrMatrixRef::new([2, 4], &[1, 2, 3], &[0, 0, 0], &[0, 3, 3]);
181  /// ```
182  ///
183  /// * Rows length must end with the nnz.
184  ///
185  /// ```should_panic
186  /// use mop_structs::matrix::csr_matrix::CsrMatrixRef;
187  /// let _ = CsrMatrixRef::new([2, 4], &[1, 2, 3], &[0, 1, 2], &[0, 3, 9]);
188  /// ```
189  ///
190  /// * Rows length must be in ascending order.
191  ///
192  /// ```should_panic
193  ///  use mop_structs::matrix::csr_matrix::CsrMatrixRef;
194  ///  let _ = CsrMatrixRef::new([3, 4], &[1, 2, 3, 4], &[0, 0, 0, 1], &[0, 1, 0, 4]);
195  /// ```
196  pub fn new(shape: [usize; 2], data: DS, indcs: US, ptrs: US) -> Self {
197    let dim: Dim<[usize; 2]> = shape.into();
198    assert!(
199      data.as_slice().len() == indcs.as_slice().len(),
200      "The length of `data` must be equal the length of `indcs`."
201    );
202    assert!(
203      data.as_slice().len() <= dim.rows() * dim.cols(),
204      "The length of `data` must be less than the number of rows times the \
205       number of columns."
206    );
207    assert!(
208      ptrs.as_slice().len() == dim.rows() + 1,
209      "The length of `ptrs` must be equal the number of rows plus 1."
210    );
211    assert!(
212      are_in_upper_bound(indcs.as_slice(), &dim.cols()),
213      "Column indices must be less than the number of columns."
214    );
215    assert!(
216      ptrs
217        .as_slice()
218        .windows(2)
219        .all(|x| does_not_have_duplicates(&indcs.as_slice()[x[0]..x[1]])),
220      "Column indices of a row must be unique."
221    );
222    assert!(
223      *ptrs.as_slice().last().unwrap() == data.as_slice().len(),
224      "Rows length must end with the nnz."
225    );
226    assert!(
227        ptrs.as_slice().windows(2).all(|x| x[0] <= x[1]),
228        "Rows length must be in ascending order."
229    );
230    unsafe { Self::new_unchecked(shape, data, indcs, ptrs) }
231  }
232
233  /// A faster and unsafe version of [`new`](#method.new).
234  pub unsafe fn new_unchecked(shape: [usize; 2], data: DS, indcs: US, ptrs: US) -> Self {
235    CsrMatrix {
236      data,
237      dim: shape.into(),
238      indcs,
239      ptrs,
240    }
241  }
242
243  /// Converts the inner storage to a generic immutable slice storage.
244  ///
245  /// # Examples
246  ///
247  /// ```rust
248  /// use mop_structs::{
249  ///     doc_tests::csr_matrix_array,
250  ///     matrix::csr_matrix::CsrMatrixRef
251  /// };
252  /// assert_eq!(
253  ///     csr_matrix_array().as_ref(),
254  ///     CsrMatrixRef::new(
255  ///         [4, 5],
256  ///         &[1, 2, 3, 4, 5],
257  ///         &[0, 2, 1, 3, 4],
258  ///         &[0, 2, 4, 4, 5]
259  ///     )
260  /// );
261  /// ```
262  pub fn as_ref(&self) -> CsrMatrixRef<'_, DS::Item> {
263    CsrMatrix::new(
264      [self.dim.rows(), self.dim.cols()],
265      self.data.as_slice(),
266      self.indcs.as_slice(),
267      self.ptrs.as_slice(),
268    )
269  }
270
271  /// Returns an immutable reference to the data elements.
272  ///
273  /// # Examples
274  ///
275  /// ```rust
276  /// use mop_structs::doc_tests::csr_matrix_array;
277  /// let a = csr_matrix_array();
278  /// assert_eq!(a.data(), &[1, 2, 3, 4, 5]);
279  /// ```
280  pub fn data(&self) -> &[DS::Item] {
281    self.data.as_slice()
282  }
283
284  /// Returns an immutable reference to the column indices of the data elements.
285  ///
286  /// # Examples
287  ///
288  /// ```rust
289  /// use mop_structs::doc_tests::csr_matrix_array;
290  /// let a = csr_matrix_array();
291  /// assert_eq!(a.indcs(), &[0, 2, 1, 3, 4]);
292  /// ```
293  pub fn indcs(&self) -> &[usize] {
294    &self.indcs.as_slice()
295  }
296
297  /// Returns the Number of NonZero elements.
298  ///
299  /// # Examples
300  ///
301  /// ```rust
302  /// use mop_structs::doc_tests::csr_matrix_array;
303  /// assert_eq!(csr_matrix_array().nnz(), 5);
304  /// ```
305  #[inline]
306  pub fn nnz(&self) -> usize {
307    self.data().len()
308  }
309
310  /// Returns an immutable reference to the rows length.
311  ///
312  /// # Examples
313  ///
314  /// ```rust
315  /// use mop_structs::doc_tests::csr_matrix_array;
316  /// let a = csr_matrix_array();
317  /// assert_eq!(a.ptrs(), &[0, 2, 4, 4, 5]);
318  /// ```
319  pub fn ptrs(&self) -> &[usize] {
320    &self.ptrs.as_slice()
321  }
322
323  /// Returns an immutable reference to the row at the `row_idx` row.
324  ///
325  /// # Examples
326  ///
327  /// ```rust
328  /// use mop_structs::{
329  ///     doc_tests::csr_matrix_array,
330  ///     vec::css::CssSlice
331  /// };
332  /// assert_eq!(
333  ///     csr_matrix_array().row(0),
334  ///     CssSlice::new(5, &[1, 2], &[0, 2])
335  /// );
336  /// ```
337  ///
338  /// # Assertions
339  ///
340  /// * `row_idx` must be less than the number of rows.
341  ///
342  /// ```should_panic
343  /// use mop_structs::doc_tests::csr_matrix_array;
344  /// let _ = csr_matrix_array().row(10);
345  /// ```
346  pub fn row(&self, row_idx: usize) -> CssSlice<'_, DS::Item> {
347    let range = self.ptr_range_of_row(row_idx);
348    CssSlice::new(
349      self.dim.cols(),
350      &self.data.as_slice()[range.clone()],
351      &self.indcs.as_slice()[range],
352    )
353  }
354
355  /// An iterator that returns immutable references of all rows.
356  ///
357  /// # Examples
358  ///
359  /// ```rust
360  /// use mop_structs::{
361  ///     doc_tests::csr_matrix_array,
362  ///     vec::css::CssSlice
363  /// };
364  /// let mut a = csr_matrix_array();
365  /// let mut li = a.row_iter();
366  /// li.next();
367  /// assert_eq!(li.next(), Some(CssSlice::new(5, &[3, 4], &[1, 3])));
368  /// li.next();
369  /// li.next();
370  /// assert_eq!(li.next(), None);
371  /// ```
372  pub fn row_iter(&self) -> CsrMatrixRowIter<'_, DS::Item> {
373    CsrMatrixRowIter::new(
374      [self.rows(), self.cols()],
375      self.data().as_ptr(),
376      self.indcs(),
377      self.ptrs(),
378    )
379  }
380
381  /// An parallel iterator that returns immutable references of all rows.
382  ///
383  /// # Examples
384  ///
385  /// ```rust
386  /// use mop_structs::{
387  ///     doc_tests::csr_matrix_array,
388  ///     prelude::*
389  /// };
390  /// let a = csr_matrix_array();
391  /// a.row_par_iter().enumerate().for_each(|(idx, x)| assert_eq!(x, a.row(idx)));
392  /// ```
393  #[cfg(feature = "rayon")]
394  pub fn row_par_iter(
395    &self,
396  ) -> crate::utils::ParallelIteratorWrapper<CsrMatrixRowIter<'_, DS::Item>> {
397    crate::utils::ParallelIteratorWrapper(self.row_iter())
398  }
399
400  /// If any, returns an immutable reference to the element at the `row_idx` row and
401  /// `col_idx` column.
402  ///
403  /// # Examples
404  ///
405  /// ```rust
406  /// use mop_structs::doc_tests::csr_matrix_array;
407  /// let a = csr_matrix_array();
408  /// assert_eq!(a.value(0, 0), Some(&1));
409  /// assert_eq!(a.value(1, 0), None);
410  /// ```
411  ///
412  /// # Assertions
413  ///
414  /// * `row_idx` must be less than the number of rows and `col_idx` must be less
415  /// than the number of columns.
416  ///
417  /// ```should_panic
418  /// use mop_structs::doc_tests::csr_matrix_array;
419  /// let _ = csr_matrix_array().value(10, 10);
420  /// ```
421  pub fn value(&self, row_idx: usize, col_idx: usize) -> Option<&DS::Item> {
422    self
423      .data_idx_of_coords(row_idx, col_idx)
424      .map(|x| &self.data()[x])
425  }
426
427  #[inline]
428  fn data_idx_of_coords(&self, row_idx: usize, col_idx: usize) -> Option<usize> {
429    assert!(row_idx < self.rows() && col_idx < self.cols());
430    let row_start_ptr = self.ptrs()[row_idx];
431    let row_end_ptr = self.ptrs()[row_idx + 1];
432    if let Ok(x) = self.indcs()[row_start_ptr..row_end_ptr].binary_search(&col_idx) {
433      Some(row_start_ptr + x)
434    } else {
435      None
436    }
437  }
438
439  #[inline]
440  fn ptr_range_of_row(&self, row_idx: usize) -> Range<usize> {
441    assert!(
442      row_idx < self.dim.rows(),
443      "`row_idx` must be less than the number of rows."
444    );
445    let lower_bound = self.ptrs()[row_idx] - self.ptrs()[0];
446    let upper_bound = self.ptrs()[row_idx + 1] - self.ptrs()[0];
447    lower_bound..upper_bound
448  }
449}
450
451#[cfg(feature = "rand")]
452impl<DS, US> CsrMatrix<DS, US>
453where
454  DS: StDenseStoRef,
455  US: StDenseStoRef<Item = usize>,
456{
457}
458
459impl<DS, US> CsrMatrix<DS, US>
460where
461  DS: StDenseStoMut,
462  US: StDenseStoRef<Item = usize>,
463{
464  /// Returns an mutable reference to the data elements.
465  ///
466  /// # Examples
467  ///
468  /// ```rust
469  /// use mop_structs::doc_tests::csr_matrix_array;
470  /// let mut a = csr_matrix_array();
471  /// assert_eq!(a.data_mut(), &mut [1, 2, 3, 4, 5]);
472  /// ```
473  pub fn data_mut(&mut self) -> &mut [DS::Item] {
474    self.data.as_mut_slice()
475  }
476
477  /// In a single borrow of `Self`, returns borrows for the most imporant inner
478  /// parts (&mut data, &indices and &pointers).
479  pub fn parts_with_data_mut(&mut self) -> (&mut [DS::Item], &[usize], &[usize]) {
480    (
481      self.data.as_mut_slice(),
482      self.indcs.as_slice(),
483      self.ptrs.as_slice(),
484    )
485  }
486
487  /// Returns an mutable reference to the row at the `row_idx` position.
488  ///
489  /// # Examples
490  ///
491  /// ```rust
492  /// use mop_structs::{
493  ///     doc_tests::csr_matrix_array,
494  ///     vec::css::CssSliceMut
495  /// };
496  /// assert_eq!(
497  ///     csr_matrix_array().row_mut(1),
498  ///     CssSliceMut::new(5, &mut [3, 4], &[1, 3])
499  /// );
500  /// ```
501  ///
502  /// # Assertions
503  ///
504  /// * `row_idx` must be less than the number of rows.
505  ///
506  /// ```should_panic
507  /// use mop_structs::doc_tests::csr_matrix_array;
508  /// let _ = csr_matrix_array().row_mut(10);
509  /// ```
510  pub fn row_mut(&mut self, row_idx: usize) -> CssSliceMut<'_, DS::Item> {
511    let range = self.ptr_range_of_row(row_idx);
512    CssSliceMut::new(
513      self.dim.cols(),
514      &mut self.data.as_mut_slice()[range.clone()],
515      &self.indcs.as_slice()[range],
516    )
517  }
518
519  /// An iterator that returns mutable references of all rows.
520  ///
521  /// # Examples
522  ///
523  /// ```rust
524  /// use mop_structs::{
525  ///     doc_tests::csr_matrix_array,
526  ///     vec::css::CssSliceMut
527  /// };
528  /// let mut a = csr_matrix_array();
529  /// let mut li = a.row_iter_mut();
530  /// li.next();
531  /// assert_eq!(li.next(), Some(CssSliceMut::new(5, &mut [3, 4], &[1, 3])));
532  /// li.next();
533  /// li.next();
534  /// assert_eq!(li.next(), None);
535  /// ```
536  pub fn row_iter_mut(&mut self) -> CsrMatrixRowIterMut<'_, DS::Item> {
537    CsrMatrixRowIterMut::new(
538      [self.rows(), self.cols()],
539      self.data_mut().as_mut_ptr(),
540      self.indcs(),
541      self.ptrs(),
542    )
543  }
544
545  /// An parallel iterator that returns mutable references of all rows.
546  ///
547  /// # Examples
548  ///
549  /// ```rust
550  /// use mop_structs::{
551  ///     doc_tests::csr_matrix_array,
552  ///     prelude::*
553  /// };
554  /// let mut a = csr_matrix_array();
555  /// a.row_par_iter_mut().for_each(|mut a| a.data_mut().iter_mut().for_each(|b| *b += 2));
556  /// assert_eq!(a.data(), &[3, 4, 5, 6, 7]);
557  /// ```
558  #[cfg(feature = "rayon")]
559  pub fn row_par_iter_mut(
560    &mut self,
561  ) -> crate::utils::ParallelIteratorWrapper<CsrMatrixRowIterMut<'_, DS::Item>> {
562    crate::utils::ParallelIteratorWrapper(self.row_iter_mut())
563  }
564
565  pub fn split_at_mut(
566    &mut self,
567    row_idx: usize,
568  ) -> (CssSliceMut<'_, DS::Item>, CssSliceMut<'_, DS::Item>) {
569    assert!(row_idx <= self.rows());
570    let split_at = self.ptrs()[row_idx];
571    let (first_data, second_data) = self.data.as_mut_slice().split_at_mut(split_at);
572    let first = CssSliceMut::new(
573      self.dim.cols(),
574      first_data,
575      &self.indcs.as_slice()[0..split_at],
576    );
577    let second = CssSliceMut::new(
578      self.dim.cols(),
579      second_data,
580      &self.indcs.as_slice()[split_at..],
581    );
582    (first, second)
583  }
584
585  /// If any, returns an mutable reference to the element at the `row_idx` row and
586  /// `col_idx` column.
587  ///
588  /// # Examples
589  ///
590  /// ```rust
591  /// use mop_structs::doc_tests::csr_matrix_array;
592  /// let mut a = csr_matrix_array();
593  /// assert_eq!(a.value_mut(0, 0), Some(&mut 1));
594  /// assert_eq!(a.value_mut(1, 0), None);
595  /// ```
596  ///
597  /// # Assertions
598  ///
599  /// * `row_idx` must be less than the number of rows and `col_idx` must be less
600  /// than the number of columns.
601  ///
602  /// ```should_panic
603  /// use mop_structs::doc_tests::csr_matrix_array;
604  /// let _ = csr_matrix_array().value_mut(10, 10);
605  /// ```
606  pub fn value_mut(&mut self, row_idx: usize, col_idx: usize) -> Option<&mut DS::Item> {
607    if let Some(x) = self.data_idx_of_coords(row_idx, col_idx) {
608      Some(&mut self.data_mut()[x])
609    } else {
610      None
611    }
612  }
613
614  /// Swaps two elements of two distinct coordinates.
615  ///
616  /// # Examples
617  ///
618  /// ```rust
619  /// use mop_structs::doc_tests::csr_matrix_array;
620  /// let mut a = csr_matrix_array();
621  /// a.swap([0, 0], [3, 4]);
622  /// assert_eq!(a.data(), &[5, 2, 3, 4, 1]);
623  /// ```
624  ///
625  /// # Assertions
626  ///
627  /// * `a` row must be less than the number of rows and `a` column must be
628  /// less than the number of columns.
629  ///
630  /// ```should_panic
631  /// use mop_structs::doc_tests::csr_matrix_array;
632  /// let _ = csr_matrix_array().swap([10, 10], [0, 0]);
633  /// ```
634  ///
635  /// * `b` row must be less than the number of rows and `b` column must be
636  /// less than the number of columns.
637  ///
638  /// ```should_panic
639  /// use mop_structs::doc_tests::csr_matrix_array;
640  /// let _ = csr_matrix_array().swap([0, 0], [10, 10]);
641  /// ```
642  ///
643  /// * `a` or `b` coordinates must point to existing elements.
644  ///
645  /// ```should_panic
646  /// use mop_structs::doc_tests::csr_matrix_array;
647  /// let _ = csr_matrix_array().swap([1, 1], [2, 2]);
648  /// ```
649  pub fn swap(&mut self, a: [usize; 2], b: [usize; 2]) {
650    let a_data_idx = self.data_idx_of_coords(a[0], a[1]).unwrap();
651    let b_data_idx = self.data_idx_of_coords(b[0], b[1]).unwrap();
652    self.data_mut().swap(a_data_idx, b_data_idx);
653  }
654}
655
656impl<DS, US> CsrMatrix<DS, US>
657where
658  DS: DynDenseStoRef,
659  US: DynDenseStoRef<Item = usize>,
660{
661  /// Returns the current rows capacity.
662  ///
663  /// # Examples
664  ///
665  /// ```rust
666  /// use mop_structs::doc_tests::csr_matrix_vec_array;
667  /// assert_eq!(csr_matrix_vec_array().rows_capacity(), 4);
668  /// ```
669  #[inline]
670  pub fn rows_capacity(&self) -> usize {
671    self.ptrs.capacity() - 1
672  }
673}
674
675impl<DS, US> CsrMatrix<DS, US>
676where
677  DS: DynDenseStoMut,
678  US: DynDenseStoMut<Item = usize>,
679{
680  /// Removes all values and sets the number of rows to zero but doesn't modify the
681  /// number of columns.
682  ///
683  /// Note that this method has no effect on the allocated capacity.
684  ///
685  /// # Examples
686  ///
687  /// ```rust
688  /// use mop_structs::{
689  ///     doc_tests::csr_matrix_vec_array,
690  ///     matrix::csr_matrix::CsrMatrixRef,
691  ///     prelude::*
692  /// };
693  /// let mut a = csr_matrix_vec_array();
694  /// a.clear();
695  /// assert_eq!(a.as_ref(), CsrMatrixRef::new(
696  ///     [0, a.cols()],
697  ///     &[],
698  ///     &[],
699  ///     &[0]
700  /// ));
701  /// ```
702  pub fn clear(&mut self) {
703    self.data.clear();
704    self.indcs.clear();
705    self.ptrs.clear();
706    self.ptrs.push(0);
707    *self.dim.rows_mut() = 0;
708  }
709
710  pub fn extend(&mut self, other: &Self)
711  where
712    DS::Item: Copy,
713    US::Item: Copy,
714  {
715    assert!(
716      self.cols() == other.cols(),
717      "The number of columns of `Self` must be equal the number of columns of `other`."
718    );
719    let mut current_ptr = *self.ptrs.as_slice().last().unwrap();
720    let mut last_other_ptr = *other.ptrs().first().unwrap();
721    other.ptrs().iter().skip(1).for_each(|&x| {
722      current_ptr += x - last_other_ptr;
723      last_other_ptr = x;
724      self.ptrs.push(current_ptr);
725    });
726    self.data.extend(other.data());
727    self.indcs.extend(other.indcs());
728    *self.dim.rows_mut() += other.rows();
729  }
730
731  /// See [`CsrMatrixRowConstructor`](CsrMatrixRowConstructor) for more information.
732  pub fn row_constructor(&mut self) -> CsrMatrixRowConstructor<'_, DS, US> {
733    CsrMatrixRowConstructor::new(
734      &mut self.dim,
735      &mut self.data,
736      &mut self.indcs,
737      &mut self.ptrs,
738    )
739  }
740
741  pub fn truncate(&mut self, until_row_idx: usize) {
742    self.data.truncate(until_row_idx);
743    self.indcs.truncate(until_row_idx);
744    self.ptrs.truncate(until_row_idx + 1);
745    *self.dim.rows_mut() = until_row_idx;
746  }
747}
748
749impl<DS, US> Matrix for CsrMatrix<DS, US> {
750  /// The number of columns.
751  ///
752  /// # Examples
753  ///
754  /// ```rust
755  /// use mop_structs::{doc_tests::csr_matrix_array, prelude::*};
756  /// assert_eq!(csr_matrix_array().cols(), 5);
757  /// ```
758  #[inline]
759  fn cols(&self) -> usize {
760    self.dim.cols()
761  }
762
763  /// The number of rows.
764  ///
765  /// # Examples
766  ///
767  /// ```rust
768  /// use mop_structs::{doc_tests::csr_matrix_array, prelude::*};
769  /// assert_eq!(csr_matrix_array().rows(), 4);
770  /// ```
771  #[inline]
772  fn rows(&self) -> usize {
773    self.dim.rows()
774  }
775}
776
777#[cfg(all(feature = "quickcheck", feature = "rand"))]
778use mop_common_deps::{
779  quickcheck::{Arbitrary, Gen},
780  rand::{
781    distributions::{Distribution, Standard},
782    Rng,
783  },
784};
785#[cfg(all(feature = "quickcheck", feature = "rand"))]
786impl<T> Arbitrary for CsrMatrixVec<T>
787where
788  Standard: Distribution<T>,
789  T: Arbitrary,
790{
791  #[inline]
792  fn arbitrary<G>(g: &mut G) -> Self
793  where
794    G: Gen,
795  {
796    let rows = g.gen_range(0, g.size());
797    let cols = g.gen_range(0, g.size());
798    let nnz = g.gen_range(0, rows * cols + 1);
799    CsrMatrixVec::new_rnd([rows, cols], nnz, g, |g, _| g.gen())
800  }
801}