conspire/math/matrix/square/
mod.rs1#[cfg(test)]
2mod test;
3
4mod ldl;
5mod lu;
6
7use crate::math::Quantity;
8use crate::math::assert::FiniteDifference;
9use crate::units::Dimensionless;
10
11use crate::math::{
12 Hessian, Rank2, Scalar, Style, StyledError, Tensor, TensorRank2Vec2D, TensorVec, Vector,
13 styled_error, write_tensor_rank_0,
14};
15
16use std::{
17 fmt::{self, Display, Formatter},
18 iter::Sum,
19 ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Sub, SubAssign},
20 vec::IntoIter,
21};
22
23pub use ldl::LdlDecomposition;
24pub use lu::LuDecomposition;
25
26#[derive(PartialEq)]
28pub enum SquareMatrixError {
29 Singular,
30}
31
32impl StyledError for SquareMatrixError {
33 fn message(&self, style: &Style) -> String {
34 let h = style.headline;
35 match self {
36 Self::Singular => format!("{h}Matrix is singular."),
37 }
38 }
39}
40
41styled_error!(SquareMatrixError);
42
43#[derive(Clone, Debug, PartialEq)]
45pub struct SquareMatrix(Vec<Vector>);
46
47impl Default for SquareMatrix {
48 fn default() -> Self {
49 Self::new()
50 }
51}
52
53impl SquareMatrix {
54 pub fn zero(len: usize) -> Self {
55 (0..len).map(|_| Vector::zero(len)).collect()
56 }
57}
58
59impl FiniteDifference for SquareMatrix {
60 fn error_fd(&self, comparator: &Self, epsilon: Scalar) -> Option<(bool, usize)> {
61 let error_count = self
62 .iter()
63 .zip(comparator.iter())
64 .map(|(self_i, comparator_i)| {
65 self_i
66 .iter()
67 .zip(comparator_i.iter())
68 .filter(|&(&self_ij, &comparator_ij)| {
69 (self_ij / comparator_ij - 1.0).abs() >= epsilon
70 && (self_ij.abs() >= epsilon || comparator_ij.abs() >= epsilon)
71 })
72 .count()
73 })
74 .sum();
75 if error_count > 0 {
76 Some((true, error_count))
77 } else {
78 None
79 }
80 }
81}
82
83impl Display for SquareMatrix {
84 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
85 write!(f, "\x1B[s")?;
86 write!(f, "[[")?;
87 self.iter().enumerate().try_for_each(|(i, row)| {
88 row.iter()
89 .try_for_each(|entry| write_tensor_rank_0(f, entry))?;
90 if i + 1 < self.len() {
91 writeln!(f, "\x1B[2D],")?;
92 write!(f, "\x1B[u")?;
93 write!(f, "\x1B[{}B [", i + 1)?;
94 }
95 Ok(())
96 })?;
97 write!(f, "\x1B[2D]]")
98 }
99}
100
101impl<const N: usize> From<[[Scalar; N]; N]> for SquareMatrix {
102 fn from(array: [[Scalar; N]; N]) -> Self {
103 array.into_iter().map(Vector::from).collect()
104 }
105}
106
107impl<const D: usize, I, J> From<TensorRank2Vec2D<D, I, J>> for SquareMatrix {
108 fn from(tensor_rank_2_vec_2d: TensorRank2Vec2D<D, I, J>) -> Self {
109 let mut square_matrix = Self::zero(tensor_rank_2_vec_2d.len() * D);
110 tensor_rank_2_vec_2d
111 .iter()
112 .enumerate()
113 .for_each(|(a, entry_a)| {
114 entry_a.iter().enumerate().for_each(|(b, entry_ab)| {
115 entry_ab.iter().enumerate().for_each(|(i, entry_ab_i)| {
116 entry_ab_i.iter().enumerate().for_each(|(j, entry_ab_ij)| {
117 square_matrix[D * a + i][D * b + j] = entry_ab_ij.value()
118 })
119 })
120 })
121 });
122 square_matrix
123 }
124}
125
126impl From<SquareMatrix> for Vec<Vec<Scalar>> {
127 fn from(square_matrix: SquareMatrix) -> Self {
128 square_matrix
129 .into_iter()
130 .map(|vector| vector.into())
131 .collect()
132 }
133}
134
135impl FromIterator<Vector> for SquareMatrix {
136 fn from_iter<Ii: IntoIterator<Item = Vector>>(into_iterator: Ii) -> Self {
137 Self(Vec::from_iter(into_iterator))
138 }
139}
140
141impl Index<usize> for SquareMatrix {
142 type Output = Vector;
143 fn index(&self, index: usize) -> &Self::Output {
144 &self.0[index]
145 }
146}
147
148impl IndexMut<usize> for SquareMatrix {
149 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
150 &mut self.0[index]
151 }
152}
153
154impl Hessian for SquareMatrix {
155 fn entry(&self, row: usize, column: usize) -> Scalar {
156 self[row][column]
157 }
158 fn quadratic_form(&self, vector: &Vector) -> Scalar {
159 self.iter()
160 .zip(vector.iter())
161 .map(|(self_i, vector_i)| vector_i * (self_i * vector))
162 .sum()
163 }
164 fn retain_from(self, retained: &[bool]) -> SquareMatrix {
165 self.into_iter()
166 .zip(retained.iter())
167 .filter(|(_, retained_i)| **retained_i)
168 .map(|(row, _)| {
169 row.into_iter()
170 .zip(retained.iter())
171 .filter(|(_, retained_j)| **retained_j)
172 .map(|(entry, _)| entry)
173 .collect()
174 })
175 .collect()
176 }
177 fn fill_into(self, square_matrix: &mut SquareMatrix) {
178 self.into_iter()
179 .zip(square_matrix.iter_mut())
180 .for_each(|(self_i, square_matrix_i)| {
181 self_i
182 .into_iter()
183 .zip(square_matrix_i.iter_mut())
184 .for_each(|(self_ij, square_matrix_ij)| *square_matrix_ij = self_ij)
185 });
186 }
187}
188
189impl Rank2 for SquareMatrix {
190 type Transpose = Self;
191 fn deviatoric(&self) -> Self {
192 let len = self.len();
193 let scale = -self.trace().value() / len as Scalar;
194 (0..len)
195 .map(|i| {
196 (0..len)
197 .map(|j| ((i == j) as u8) as Scalar * scale)
198 .collect()
199 })
200 .collect::<Self>()
201 + self
202 }
203 fn deviatoric_and_trace(&self) -> (Self, Quantity<Dimensionless>) {
204 let len = self.len();
205 let trace = self.trace();
206 let scale = -trace.value() / len as Scalar;
207 (
208 (0..len)
209 .map(|i| {
210 (0..len)
211 .map(|j| ((i == j) as u8) as Scalar * scale)
212 .collect()
213 })
214 .collect::<Self>()
215 + self,
216 trace,
217 )
218 }
219 fn is_diagonal(&self) -> bool {
220 self.iter()
221 .enumerate()
222 .map(|(i, self_i)| {
223 self_i
224 .iter()
225 .enumerate()
226 .map(|(j, self_ij)| (self_ij == &0.0) as u8 * (i != j) as u8)
227 .sum::<u8>()
228 })
229 .sum::<u8>()
230 == (self.len().pow(2) - self.len()) as u8
231 }
232 fn is_identity(&self) -> bool {
233 self.iter().enumerate().all(|(i, self_i)| {
234 self_i
235 .iter()
236 .enumerate()
237 .all(|(j, self_ij)| self_ij == &((i == j) as u8 as Scalar))
238 })
239 }
240 fn is_symmetric(&self) -> bool {
241 self.iter().enumerate().all(|(i, self_i)| {
242 self_i
243 .iter()
244 .zip(self.iter())
245 .all(|(self_ij, self_j)| self_ij == &self_j[i])
246 })
247 }
248 fn squared_trace(&self) -> Quantity {
249 Quantity::new(
250 self.iter()
251 .enumerate()
252 .map(|(i, self_i)| {
253 self_i
254 .iter()
255 .zip(self.iter())
256 .map(|(self_ij, self_j)| self_ij * self_j[i])
257 .sum::<Scalar>()
258 })
259 .sum::<Scalar>(),
260 )
261 }
262 fn trace(&self) -> Quantity<Dimensionless> {
263 Quantity::new(self.iter().enumerate().map(|(i, self_i)| self_i[i]).sum())
264 }
265 fn transpose(&self) -> Self::Transpose {
266 (0..self.len())
267 .map(|i| (0..self.len()).map(|j| self[j][i]).collect())
268 .collect()
269 }
270}
271
272impl Tensor for SquareMatrix {
273 type Item = Vector;
274 type Unit = Dimensionless;
275 fn iter(&self) -> impl Iterator<Item = &Self::Item> {
276 self.0.iter()
277 }
278 fn iter_mut(&mut self) -> impl Iterator<Item = &mut Self::Item> {
279 self.0.iter_mut()
280 }
281 fn len(&self) -> usize {
282 self.0.len()
283 }
284 fn size(&self) -> usize {
285 unimplemented!("Do not like that inner Vecs could be different sizes")
286 }
287}
288
289impl IntoIterator for SquareMatrix {
290 type Item = Vector;
291 type IntoIter = IntoIter<Self::Item>;
292 fn into_iter(self) -> Self::IntoIter {
293 self.0.into_iter()
294 }
295}
296
297impl TensorVec for SquareMatrix {
298 type Item = Vector;
299 fn append(&mut self, other: &mut Self) {
300 self.0.append(&mut other.0)
301 }
302 fn capacity(&self) -> usize {
303 self.0.capacity()
304 }
305 fn is_empty(&self) -> bool {
306 self.0.is_empty()
307 }
308 fn new() -> Self {
309 Self(Vec::new())
310 }
311 fn push(&mut self, item: Self::Item) {
312 self.0.push(item)
313 }
314 fn remove(&mut self, index: usize) -> Self::Item {
315 self.0.remove(index)
316 }
317 fn reserve(&mut self, additional: usize) {
318 self.0.reserve(additional)
319 }
320 fn retain<F>(&mut self, f: F)
321 where
322 F: FnMut(&Self::Item) -> bool,
323 {
324 self.0.retain(f)
325 }
326 fn swap_remove(&mut self, index: usize) -> Self::Item {
327 self.0.swap_remove(index)
328 }
329 fn with_capacity(capacity: usize) -> Self {
330 Self(Vec::with_capacity(capacity))
331 }
332}
333
334impl Sum for SquareMatrix {
335 fn sum<Ii>(iter: Ii) -> Self
336 where
337 Ii: Iterator<Item = Self>,
338 {
339 iter.reduce(|mut acc, item| {
340 acc += item;
341 acc
342 })
343 .unwrap_or_else(Self::default)
344 }
345}
346
347impl Div<Scalar> for SquareMatrix {
348 type Output = Self;
349 fn div(mut self, tensor_rank_0: Scalar) -> Self::Output {
350 self /= &tensor_rank_0;
351 self
352 }
353}
354
355impl Div<&Scalar> for SquareMatrix {
356 type Output = Self;
357 fn div(mut self, tensor_rank_0: &Scalar) -> Self::Output {
358 self /= tensor_rank_0;
359 self
360 }
361}
362
363impl DivAssign<Scalar> for SquareMatrix {
364 fn div_assign(&mut self, tensor_rank_0: Scalar) {
365 self.iter_mut().for_each(|entry| *entry /= &tensor_rank_0);
366 }
367}
368
369impl DivAssign<&Scalar> for SquareMatrix {
370 fn div_assign(&mut self, tensor_rank_0: &Scalar) {
371 self.iter_mut().for_each(|entry| *entry /= tensor_rank_0);
372 }
373}
374
375impl Mul<Scalar> for SquareMatrix {
376 type Output = Self;
377 fn mul(mut self, tensor_rank_0: Scalar) -> Self::Output {
378 self *= &tensor_rank_0;
379 self
380 }
381}
382
383impl Mul<&Scalar> for SquareMatrix {
384 type Output = Self;
385 fn mul(mut self, tensor_rank_0: &Scalar) -> Self::Output {
386 self *= tensor_rank_0;
387 self
388 }
389}
390
391impl Mul<&Scalar> for &SquareMatrix {
392 type Output = SquareMatrix;
393 fn mul(self, tensor_rank_0: &Scalar) -> Self::Output {
394 self.iter().map(|self_i| self_i * tensor_rank_0).collect()
395 }
396}
397
398impl MulAssign<Scalar> for SquareMatrix {
399 fn mul_assign(&mut self, tensor_rank_0: Scalar) {
400 self.iter_mut().for_each(|entry| *entry *= &tensor_rank_0);
401 }
402}
403
404impl MulAssign<&Scalar> for SquareMatrix {
405 fn mul_assign(&mut self, tensor_rank_0: &Scalar) {
406 self.iter_mut().for_each(|entry| *entry *= tensor_rank_0);
407 }
408}
409
410impl Mul<Vector> for SquareMatrix {
411 type Output = Vector;
412 fn mul(self, vector: Vector) -> Self::Output {
413 self.iter().map(|self_i| self_i * &vector).collect()
414 }
415}
416
417impl Mul<&Vector> for SquareMatrix {
418 type Output = Vector;
419 fn mul(self, vector: &Vector) -> Self::Output {
420 self.iter().map(|self_i| self_i * vector).collect()
421 }
422}
423
424impl Add for SquareMatrix {
425 type Output = Self;
426 fn add(mut self, vector: Self) -> Self::Output {
427 self += vector;
428 self
429 }
430}
431
432impl Add<&Self> for SquareMatrix {
433 type Output = Self;
434 fn add(mut self, vector: &Self) -> Self::Output {
435 self += vector;
436 self
437 }
438}
439
440impl AddAssign for SquareMatrix {
441 fn add_assign(&mut self, vector: Self) {
442 self.iter_mut()
443 .zip(vector.iter())
444 .for_each(|(self_entry, tensor_rank_1)| *self_entry += tensor_rank_1);
445 }
446}
447
448impl AddAssign<&Self> for SquareMatrix {
449 fn add_assign(&mut self, vector: &Self) {
450 self.iter_mut()
451 .zip(vector.iter())
452 .for_each(|(self_entry, tensor_rank_1)| *self_entry += tensor_rank_1);
453 }
454}
455
456impl Mul for SquareMatrix {
457 type Output = Self;
458 fn mul(self, matrix: Self) -> Self::Output {
459 let mut output = Self::zero(matrix.len());
460 self.iter()
461 .zip(output.iter_mut())
462 .for_each(|(self_i, output_i)| {
463 self_i
464 .iter()
465 .zip(matrix.iter())
466 .for_each(|(self_ij, matrix_j)| *output_i += matrix_j * self_ij)
467 });
468 output
469 }
470}
471
472impl Sub for SquareMatrix {
473 type Output = Self;
474 fn sub(mut self, square_matrix: Self) -> Self::Output {
475 self -= square_matrix;
476 self
477 }
478}
479
480impl Sub<&Self> for SquareMatrix {
481 type Output = Self;
482 fn sub(mut self, square_matrix: &Self) -> Self::Output {
483 self -= square_matrix;
484 self
485 }
486}
487
488impl Sub for &SquareMatrix {
489 type Output = SquareMatrix;
490 fn sub(self, square_matrix: Self) -> Self::Output {
491 square_matrix
492 .iter()
493 .zip(self.iter())
494 .map(|(square_matrix_i, self_i)| self_i - square_matrix_i)
495 .collect()
496 }
497}
498
499impl SubAssign for SquareMatrix {
500 fn sub_assign(&mut self, square_matrix: Self) {
501 self.iter_mut()
502 .zip(square_matrix.iter())
503 .for_each(|(self_entry, tensor_rank_1)| *self_entry -= tensor_rank_1);
504 }
505}
506
507impl SubAssign<&Self> for SquareMatrix {
508 fn sub_assign(&mut self, square_matrix: &Self) {
509 self.iter_mut()
510 .zip(square_matrix.iter())
511 .for_each(|(self_entry, tensor_rank_1)| *self_entry -= tensor_rank_1);
512 }
513}