mop_structs/matrix/csr_matrix/
csr_matrix_row_constructor.rs

1use crate::{
2  dim::Dim,
3  prelude::DynDenseStoMut,
4  utils::{are_in_upper_bound, does_not_have_duplicates},
5  vec::css::CssSlice,
6};
7
8/// Constructs a new valid row in a easy and interactive manner, abstracting away the complexity
9/// of the CSR format.
10///
11/// This struct may panic when out of scope. Please see the `Drop` documentation in
12/// the [`Trait Implementations`](#implementations) section for more information.
13#[derive(Debug, PartialEq)]
14pub struct CsrMatrixRowConstructor<'a, DS, US> {
15  row_nnz: usize,
16  data: &'a mut DS,
17  dim: &'a mut Dim<[usize; 2]>,
18  indcs: &'a mut US,
19  ptrs: &'a mut US,
20}
21
22impl<'a, DS, US> CsrMatrixRowConstructor<'a, DS, US>
23where
24  DS: DynDenseStoMut,
25  US: DynDenseStoMut<Item = usize>,
26{
27  pub(crate) fn new(
28    dim: &'a mut Dim<[usize; 2]>,
29    data: &'a mut DS,
30    indcs: &'a mut US,
31    ptrs: &'a mut US,
32  ) -> Self {
33    CsrMatrixRowConstructor {
34      row_nnz: 0,
35      data,
36      dim,
37      indcs,
38      ptrs,
39    }
40  }
41
42  /// Commits the row construction, modifying the internal structure.
43  ///
44  /// # Examples
45  ///
46  /// ```rust
47  /// use mop_structs::{
48  ///     doc_tests::csr_matrix_empty_vec_array,
49  ///     matrix::csr_matrix::CsrMatrixRef
50  /// };
51  /// let mut a = csr_matrix_empty_vec_array();
52  /// a.row_constructor().commit();
53  /// assert_eq!(a.as_ref(), CsrMatrixRef::new([1, 5], &[], &[], &[0, 0]));
54  /// ```
55  ///
56  /// # Assertions
57  ///
58  /// * Inserted indices must be less than the number of columns of `Self`.
59  ///
60  /// ```should_panic
61  /// use mop_structs::doc_tests::csr_matrix_empty_vec_array;
62  /// let mut a = csr_matrix_empty_vec_array();
63  /// a.row_constructor().set_value(10, 1).commit();
64  /// ```
65  ///
66  /// * Inserted indices must be unique.
67  ///
68  /// ```should_panic
69  /// use mop_structs::doc_tests::csr_matrix_empty_vec_array;
70  /// let mut a = csr_matrix_empty_vec_array();
71  /// a.row_constructor().set_value(1, 1).set_value(1, 10).commit();
72  /// ```
73  pub fn commit(self) {
74    let last_ptr = *self.ptrs.as_slice().last().unwrap();
75    let inserted_indcs = &self.indcs.as_slice()[last_ptr..];
76    assert!(
77      are_in_upper_bound(inserted_indcs, &self.dim.cols()),
78      "Inserted indices must be less than the number of columns of `Self`"
79    );
80    assert!(
81      does_not_have_duplicates(inserted_indcs),
82      "Inserted indices must be unique."
83    );
84    unsafe { self.commit_unchecked() };
85  }
86
87  /// A faster and unsafe version of [`commit`](#method.commit).
88  pub unsafe fn commit_unchecked(mut self) {
89    let last_ptr = *self.ptrs.as_slice().last().unwrap();
90    self.ptrs.push(last_ptr + self.row_nnz);
91    *self.dim.rows_mut() += 1;
92    self.row_nnz = 0;
93  }
94
95  /// Copies all values of `row` into the current row.
96  ///
97  /// # Examples
98  ///
99  /// ```rust
100  /// use mop_structs::{
101  ///     doc_tests::csr_matrix_empty_vec_array,
102  ///     matrix::csr_matrix::CsrMatrixRef,
103  ///     vec::css::CssSlice
104  /// };
105  /// let mut a = csr_matrix_empty_vec_array();
106  /// let b = CssSlice::new(5, &[1, 2], &[0, 1]);
107  /// a.row_constructor().copy_values_from_row(&b).commit();
108  /// assert_eq!(a.as_ref(), CsrMatrixRef::new(
109  ///     [1, 5],
110  ///     &[1, 2],
111  ///     &[0, 1],
112  ///     &[0, 2]
113  /// ));
114  /// ```
115  pub fn copy_values_from_row(mut self, row: &CssSlice<'_, DS::Item>) -> Self
116  where
117    DS::Item: Copy,
118  {
119    self.row_nnz += row.nnz();
120    self.data.extend(row.data());
121    self.indcs.extend(row.indcs());
122    self
123  }
124
125  /// Sets a new value in the current row and column index `column_idx`.
126  ///
127  /// # Examples
128  ///
129  /// ```rust
130  /// use mop_structs::{
131  ///     doc_tests::csr_matrix_empty_vec_array,
132  ///     matrix::csr_matrix::CsrMatrixRef
133  /// };
134  /// let mut a = csr_matrix_empty_vec_array();
135  /// a.row_constructor().set_value(1, 1).commit();
136  /// assert_eq!(a.as_ref(), CsrMatrixRef::new([1, 5], &[1], &[1], &[0, 1]));
137  /// ```
138  pub fn set_value(mut self, column_idx: usize, value: DS::Item) -> Self {
139    self.row_nnz += 1;
140    self.data.push(value);
141    self.indcs.push(column_idx);
142    self
143  }
144}
145
146impl<'a, DS, US> Drop for CsrMatrixRowConstructor<'a, DS, US> {
147  /// Some measures are taken to ensure the CSR format and avoid unexpected runtime behavior.
148  ///
149  /// # Assertions
150  ///
151  /// * Every single nonempty instance of `CsrRowLayerConstructor` must end with a call to
152  /// the `commit` method.
153  ///
154  /// ```should_panic
155  /// use mop_structs::doc_tests::csr_matrix_empty_vec_array;
156  /// let mut a = csr_matrix_empty_vec_array();
157  /// a.row_constructor().set_value(1, 1);
158  /// ```
159  fn drop(&mut self) {
160    if self.row_nnz > 0 {
161      panic!(
162        "Every single nonempty instance of `CsrMatrixRowConstructor` must
163                end with a call to the `commit` method."
164      );
165    }
166  }
167}