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}