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