loeres_backend_std/
dense.rs1use loeres::{
8 ContiguousMatrixAccess, ContiguousVectorAccess, ContiguousVectorAccessMut, Dim2, DimensionKind,
9 FiniteScalar, MatrixAccess, MatrixAccessMut, SolverError, VectorAccess, VectorAccessMut,
10};
11
12use crate::internal::dimension_mismatch;
13
14#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
19pub struct DenseIngestOptions {
20 pub max_elements: Option<usize>,
22}
23
24#[derive(Clone, Debug)]
26pub struct DenseVector<S> {
27 data: Vec<S>,
28}
29
30impl<S: loeres::BaseScalar> DenseVector<S> {
31 pub fn from_vec(data: Vec<S>) -> Result<Self, SolverError> {
33 Self::from_vec_with_options(data, DenseIngestOptions::default())
34 }
35
36 pub fn from_vec_with_options(
40 data: Vec<S>,
41 options: DenseIngestOptions,
42 ) -> Result<Self, SolverError> {
43 if data.is_empty() {
44 return Err(SolverError::InvalidDimension);
45 }
46 if let Some(max) = options.max_elements {
47 if data.len() > max {
48 return Err(SolverError::InvalidInput);
49 }
50 }
51 Ok(Self { data })
52 }
53
54 pub fn len(&self) -> usize {
56 self.data.len()
57 }
58
59 pub fn is_empty(&self) -> bool {
61 self.data.is_empty()
62 }
63}
64
65impl<S: FiniteScalar> DenseVector<S> {
66 pub fn validate_finite(&self) -> Result<(), SolverError> {
69 for value in &self.data {
70 if !value.is_finite() {
71 return Err(SolverError::NonFiniteInput);
72 }
73 }
74 Ok(())
75 }
76}
77
78impl<S: loeres::BaseScalar> VectorAccess for DenseVector<S> {
79 type Scalar = S;
80
81 fn len(&self) -> usize {
82 self.data.len()
83 }
84
85 fn dimension_kind(&self) -> DimensionKind {
86 DimensionKind::Dynamic
87 }
88
89 fn get(&self, index: usize) -> Result<S, SolverError> {
90 match self.data.get(index) {
91 Some(&value) => Ok(value),
92 None => Err(dimension_mismatch(index, self.data.len())),
93 }
94 }
95}
96
97impl<S: loeres::BaseScalar> VectorAccessMut for DenseVector<S> {
98 fn set(&mut self, index: usize, value: S) -> Result<(), SolverError> {
99 let len = self.data.len();
100 match self.data.get_mut(index) {
101 Some(slot) => {
102 *slot = value;
103 Ok(())
104 }
105 None => Err(dimension_mismatch(index, len)),
106 }
107 }
108}
109
110impl<S: loeres::BaseScalar> ContiguousVectorAccess for DenseVector<S> {
111 fn as_contiguous(&self) -> Option<&[S]> {
112 Some(&self.data)
113 }
114}
115
116impl<S: loeres::BaseScalar> ContiguousVectorAccessMut for DenseVector<S> {
117 fn as_contiguous_mut(&mut self) -> Option<&mut [S]> {
118 Some(&mut self.data)
119 }
120}
121
122#[derive(Clone, Debug)]
124pub struct DenseMatrix<S> {
125 rows: usize,
126 cols: usize,
127 data: Vec<S>,
128}
129
130impl<S: loeres::BaseScalar> DenseMatrix<S> {
131 pub fn from_row_major_vec(rows: usize, cols: usize, data: Vec<S>) -> Result<Self, SolverError> {
133 Self::from_row_major_vec_with_options(rows, cols, data, DenseIngestOptions::default())
134 }
135
136 pub fn from_row_major_vec_with_options(
139 rows: usize,
140 cols: usize,
141 data: Vec<S>,
142 options: DenseIngestOptions,
143 ) -> Result<Self, SolverError> {
144 if rows == 0 || cols == 0 {
145 return Err(SolverError::InvalidDimension);
146 }
147 let required = rows
148 .checked_mul(cols)
149 .ok_or(SolverError::InvalidDimension)?;
150 if let Some(max) = options.max_elements {
151 if required > max {
152 return Err(SolverError::InvalidInput);
153 }
154 }
155 if data.len() != required {
156 return Err(dimension_mismatch(data.len(), required));
157 }
158 Ok(Self { rows, cols, data })
159 }
160
161 pub fn dims(&self) -> Dim2 {
163 Dim2::new(self.rows, self.cols)
164 }
165}
166
167impl<S: FiniteScalar> DenseMatrix<S> {
168 pub fn validate_finite(&self) -> Result<(), SolverError> {
170 for value in &self.data {
171 if !value.is_finite() {
172 return Err(SolverError::NonFiniteInput);
173 }
174 }
175 Ok(())
176 }
177}
178
179impl<S: loeres::BaseScalar> MatrixAccess for DenseMatrix<S> {
180 type Scalar = S;
181
182 fn dims(&self) -> Dim2 {
183 Dim2::new(self.rows, self.cols)
184 }
185
186 fn dimension_kind(&self) -> DimensionKind {
187 DimensionKind::Dynamic
188 }
189
190 fn get(&self, row: usize, col: usize) -> Result<S, SolverError> {
191 if row >= self.rows {
192 return Err(dimension_mismatch(row, self.rows));
193 }
194 if col >= self.cols {
195 return Err(dimension_mismatch(col, self.cols));
196 }
197 let offset = row * self.cols + col;
199 match self.data.get(offset) {
200 Some(&value) => Ok(value),
201 None => Err(SolverError::InternalInvariantViolation),
202 }
203 }
204}
205
206impl<S: loeres::BaseScalar> MatrixAccessMut for DenseMatrix<S> {
207 fn set(&mut self, row: usize, col: usize, value: S) -> Result<(), SolverError> {
208 if row >= self.rows {
209 return Err(dimension_mismatch(row, self.rows));
210 }
211 if col >= self.cols {
212 return Err(dimension_mismatch(col, self.cols));
213 }
214 let offset = row * self.cols + col;
215 match self.data.get_mut(offset) {
216 Some(slot) => {
217 *slot = value;
218 Ok(())
219 }
220 None => Err(SolverError::InternalInvariantViolation),
221 }
222 }
223}
224
225impl<S: loeres::BaseScalar> ContiguousMatrixAccess for DenseMatrix<S> {
226 fn as_row_major(&self) -> Option<&[S]> {
227 Some(&self.data)
228 }
229}
230
231#[cfg(test)]
232mod tests;