Skip to main content

conspire/math/matrix/square/
mod.rs

1#[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/// Possible errors for square matrices.
27#[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/// A square matrix.
44#[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}