Skip to main content

conspire/math/matrix/square/
mod.rs

1#[cfg(test)]
2mod test;
3
4use crate::math::assert::FiniteDifference;
5
6use crate::{
7    ABS_TOL,
8    math::{
9        Hessian, Rank2, Scalar, Tensor, TensorRank2Vec2D, TensorVec, Vector, write_tensor_rank_0,
10    },
11};
12use std::{
13    fmt::{self, Display, Formatter},
14    iter::Sum,
15    ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Sub, SubAssign},
16    vec::IntoIter,
17};
18
19/// Possible errors for square matrices.
20#[derive(Debug, PartialEq)]
21pub enum SquareMatrixError {
22    Singular,
23}
24
25/// A square matrix.
26#[derive(Clone, Debug, PartialEq)]
27pub struct SquareMatrix(Vec<Vector>);
28
29impl Default for SquareMatrix {
30    fn default() -> Self {
31        Self::new()
32    }
33}
34
35impl SquareMatrix {
36    // /// Solve a system of linear equations using the LDL decomposition.
37    // pub fn solve_ldl(&mut self, b: &Vector) -> Result<Vector, SquareMatrixError> {
38    //     let n = self.len();
39    //     let mut p: Vec<usize> = (0..n).collect();
40    //     let mut d: Vec<Scalar> = vec![0.0; n];
41    //     let mut l: Vec<Vec<Scalar>> = vec![vec![0.0; n]; n];
42    //     // for i in 0..n {
43    //     //     for j in 0..n {
44    //     //         assert!((self[i][j] - self[j][i]).abs() < ABS_TOL || (self[i][j] / self[j][i] - 1.0).abs() < ABS_TOL)
45    //     //     }
46    //     // }
47    //     for i in 0..n {
48    //         let mut max_row = i;
49    //         let mut max_val = self[max_row][i].abs();
50    //         for k in i + 1..n {
51    //             if self[k][i].abs() > max_val {
52    //                 max_row = k;
53    //                 max_val = self[max_row][i].abs();
54    //             }
55    //         }
56    //         if max_row != i {
57    //             self.0.swap(i, max_row);
58    //             p.swap(i, max_row);
59    //         }
60    //         let mut sum = 0.0;
61    //         for k in 0..i {
62    //             sum += l[i][k] * d[k] * l[i][k];
63    //         }
64    //         let pivot = self[i][i] - sum;
65    //         if pivot.abs() < ABS_TOL {
66    //             return Err(SquareMatrixError::Singular);
67    //         }
68    //         d[i] = pivot;
69    //         l[i][i] = 1.0;
70    //         for j in i + 1..n {
71    //             sum = 0.0;
72    //             for k in 0..i {
73    //                 sum += l[j][k] * d[k] * l[i][k];
74    //             }
75    //             l[j][i] = (self[j][i] - sum) / d[i];
76    //         }
77    //     }
78    //     let mut y = Vector::zero(n);
79    //     for i in 0..n {
80    //         y[i] = b[p[i]];
81    //         for j in 0..i {
82    //             y[i] -= l[i][j] * y[j];
83    //         }
84    //     }
85    //     let mut x = Vector::zero(n);
86    //     for i in 0..n {
87    //         x[i] = y[i] / d[i];
88    //     }
89    //     for i in (0..n).rev() {
90    //         for j in i + 1..n {
91    //             x[i] -= l[j][i] * x[j];
92    //         }
93    //     }
94    //     // Ok(x)
95    //     let mut xs = Vector::zero(n);
96    //     for i in 0..n {
97    //         xs[p[i]] = x[i]
98    //     }
99    //     Ok(xs)
100    //     // let mut p_reverse = vec![0; n];
101    //     // for (i, &pi) in p.iter().enumerate() {
102    //     //     p_reverse[pi] = i;
103    //     // }
104    //     // let mut xs = Vector::zero(n);
105    //     // for i in 0..n {
106    //     //     // xs[i] = x[p_reverse[i]]
107    //     //     xs[p_reverse[i]] = x[i]
108    //     // }
109    //     // Ok(xs)
110    // }
111    /// Solve a system of linear equations using the LU decomposition.
112    pub fn solve_lu(&self, b: &Vector) -> Result<Vector, SquareMatrixError> {
113        let n = self.len();
114        let mut p: Vec<usize> = (0..n).collect();
115        let mut factor;
116        let mut lu = self.clone();
117        let mut max_row;
118        let mut max_val;
119        let mut pivot;
120        for i in 0..n {
121            max_row = i;
122            max_val = lu[max_row][i].abs();
123            for k in i + 1..n {
124                if lu[k][i].abs() > max_val {
125                    max_row = k;
126                    max_val = lu[max_row][i].abs();
127                }
128            }
129            if max_row != i {
130                lu.0.swap(i, max_row);
131                p.swap(i, max_row);
132            }
133            pivot = lu[i][i];
134            if pivot.abs() < ABS_TOL {
135                return Err(SquareMatrixError::Singular);
136            }
137            for j in i + 1..n {
138                if lu[j][i] != 0.0 {
139                    lu[j][i] /= pivot;
140                    factor = lu[j][i];
141                    let (front, back) = lu.0.split_at_mut(j);
142                    back[0].as_mut_slice()[i + 1..n]
143                        .iter_mut()
144                        .zip(front[i].as_slice()[i + 1..n].iter())
145                        .for_each(|(lu_jk, lu_ik)| *lu_jk -= factor * lu_ik);
146                }
147            }
148        }
149        let mut x: Vector = p.into_iter().map(|p_i| b[p_i]).collect();
150        forward_substitution(&mut x, &lu);
151        backward_substitution(&mut x, &lu);
152        Ok(x)
153    }
154    pub fn zero(len: usize) -> Self {
155        (0..len).map(|_| Vector::zero(len)).collect()
156    }
157}
158
159fn forward_substitution(x: &mut Vector, a: &SquareMatrix) {
160    a.iter().enumerate().for_each(|(i, a_i)| {
161        x[i] -= a_i
162            .iter()
163            .take(i)
164            .zip(x.iter().take(i))
165            .map(|(a_ij, x_j)| a_ij * x_j)
166            .sum::<Scalar>()
167    })
168}
169
170fn backward_substitution(x: &mut Vector, a: &SquareMatrix) {
171    a.0.iter().enumerate().rev().for_each(|(i, a_i)| {
172        x[i] -= a_i
173            .iter()
174            .skip(i + 1)
175            .zip(x.iter().skip(i + 1))
176            .map(|(a_ij, x_j)| a_ij * x_j)
177            .sum::<Scalar>();
178        x[i] /= a_i[i];
179    })
180}
181
182impl FiniteDifference for SquareMatrix {
183    fn error_fd(&self, comparator: &Self, epsilon: Scalar) -> Option<(bool, usize)> {
184        let error_count = self
185            .iter()
186            .zip(comparator.iter())
187            .map(|(self_i, comparator_i)| {
188                self_i
189                    .iter()
190                    .zip(comparator_i.iter())
191                    .filter(|&(&self_ij, &comparator_ij)| {
192                        (self_ij / comparator_ij - 1.0).abs() >= epsilon
193                            && (self_ij.abs() >= epsilon || comparator_ij.abs() >= epsilon)
194                    })
195                    .count()
196            })
197            .sum();
198        if error_count > 0 {
199            Some((true, error_count))
200        } else {
201            None
202        }
203    }
204}
205
206impl Display for SquareMatrix {
207    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
208        write!(f, "\x1B[s")?;
209        write!(f, "[[")?;
210        self.iter().enumerate().try_for_each(|(i, row)| {
211            row.iter()
212                .try_for_each(|entry| write_tensor_rank_0(f, entry))?;
213            if i + 1 < self.len() {
214                writeln!(f, "\x1B[2D],")?;
215                write!(f, "\x1B[u")?;
216                write!(f, "\x1B[{}B [", i + 1)?;
217            }
218            Ok(())
219        })?;
220        write!(f, "\x1B[2D]]")
221    }
222}
223
224impl<const N: usize> From<[[Scalar; N]; N]> for SquareMatrix {
225    fn from(array: [[Scalar; N]; N]) -> Self {
226        array.into_iter().map(Vector::from).collect()
227    }
228}
229
230impl<const D: usize, const I: usize, const J: usize> From<TensorRank2Vec2D<D, I, J>>
231    for SquareMatrix
232{
233    fn from(tensor_rank_2_vec_2d: TensorRank2Vec2D<D, I, J>) -> Self {
234        let mut square_matrix = Self::zero(tensor_rank_2_vec_2d.len() * D);
235        tensor_rank_2_vec_2d
236            .iter()
237            .enumerate()
238            .for_each(|(a, entry_a)| {
239                entry_a.iter().enumerate().for_each(|(b, entry_ab)| {
240                    entry_ab.iter().enumerate().for_each(|(i, entry_ab_i)| {
241                        entry_ab_i.iter().enumerate().for_each(|(j, entry_ab_ij)| {
242                            square_matrix[D * a + i][D * b + j] = *entry_ab_ij
243                        })
244                    })
245                })
246            });
247        square_matrix
248    }
249}
250
251impl From<SquareMatrix> for Vec<Vec<Scalar>> {
252    fn from(square_matrix: SquareMatrix) -> Self {
253        square_matrix
254            .into_iter()
255            .map(|vector| vector.into())
256            .collect()
257    }
258}
259
260impl FromIterator<Vector> for SquareMatrix {
261    fn from_iter<Ii: IntoIterator<Item = Vector>>(into_iterator: Ii) -> Self {
262        Self(Vec::from_iter(into_iterator))
263    }
264}
265
266impl Index<usize> for SquareMatrix {
267    type Output = Vector;
268    fn index(&self, index: usize) -> &Self::Output {
269        &self.0[index]
270    }
271}
272
273impl IndexMut<usize> for SquareMatrix {
274    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
275        &mut self.0[index]
276    }
277}
278
279impl Hessian for SquareMatrix {
280    fn entry(&self, row: usize, column: usize) -> Scalar {
281        self[row][column]
282    }
283    fn fill_into(self, square_matrix: &mut SquareMatrix) {
284        self.into_iter()
285            .zip(square_matrix.iter_mut())
286            .for_each(|(self_i, square_matrix_i)| {
287                self_i
288                    .into_iter()
289                    .zip(square_matrix_i.iter_mut())
290                    .for_each(|(self_ij, square_matrix_ij)| *square_matrix_ij = self_ij)
291            });
292    }
293}
294
295impl Rank2 for SquareMatrix {
296    type Transpose = Self;
297    fn deviatoric(&self) -> Self {
298        let len = self.len();
299        let scale = -self.trace() / len as Scalar;
300        (0..len)
301            .map(|i| {
302                (0..len)
303                    .map(|j| ((i == j) as u8) as Scalar * scale)
304                    .collect()
305            })
306            .collect::<Self>()
307            + self
308    }
309    fn deviatoric_and_trace(&self) -> (Self, Scalar) {
310        let len = self.len();
311        let trace = self.trace();
312        let scale = -trace / len as Scalar;
313        (
314            (0..len)
315                .map(|i| {
316                    (0..len)
317                        .map(|j| ((i == j) as u8) as Scalar * scale)
318                        .collect()
319                })
320                .collect::<Self>()
321                + self,
322            trace,
323        )
324    }
325    fn is_diagonal(&self) -> bool {
326        self.iter()
327            .enumerate()
328            .map(|(i, self_i)| {
329                self_i
330                    .iter()
331                    .enumerate()
332                    .map(|(j, self_ij)| (self_ij == &0.0) as u8 * (i != j) as u8)
333                    .sum::<u8>()
334            })
335            .sum::<u8>()
336            == (self.len().pow(2) - self.len()) as u8
337    }
338    fn is_identity(&self) -> bool {
339        self.iter().enumerate().all(|(i, self_i)| {
340            self_i
341                .iter()
342                .enumerate()
343                .all(|(j, self_ij)| self_ij == &((i == j) as u8 as Scalar))
344        })
345    }
346    fn is_symmetric(&self) -> bool {
347        self.iter().enumerate().all(|(i, self_i)| {
348            self_i
349                .iter()
350                .zip(self.iter())
351                .all(|(self_ij, self_j)| self_ij == &self_j[i])
352        })
353    }
354    fn squared_trace(&self) -> Scalar {
355        self.iter()
356            .enumerate()
357            .map(|(i, self_i)| {
358                self_i
359                    .iter()
360                    .zip(self.iter())
361                    .map(|(self_ij, self_j)| self_ij * self_j[i])
362                    .sum::<Scalar>()
363            })
364            .sum()
365    }
366    fn trace(&self) -> Scalar {
367        self.iter().enumerate().map(|(i, self_i)| self_i[i]).sum()
368    }
369    fn transpose(&self) -> Self::Transpose {
370        (0..self.len())
371            .map(|i| (0..self.len()).map(|j| self[j][i]).collect())
372            .collect()
373    }
374}
375
376impl Tensor for SquareMatrix {
377    type Item = Vector;
378    fn iter(&self) -> impl Iterator<Item = &Self::Item> {
379        self.0.iter()
380    }
381    fn iter_mut(&mut self) -> impl Iterator<Item = &mut Self::Item> {
382        self.0.iter_mut()
383    }
384    fn len(&self) -> usize {
385        self.0.len()
386    }
387    fn size(&self) -> usize {
388        unimplemented!("Do not like that inner Vecs could be different sizes")
389    }
390}
391
392impl IntoIterator for SquareMatrix {
393    type Item = Vector;
394    type IntoIter = IntoIter<Self::Item>;
395    fn into_iter(self) -> Self::IntoIter {
396        self.0.into_iter()
397    }
398}
399
400impl TensorVec for SquareMatrix {
401    type Item = Vector;
402    fn append(&mut self, other: &mut Self) {
403        self.0.append(&mut other.0)
404    }
405    fn capacity(&self) -> usize {
406        self.0.capacity()
407    }
408    fn is_empty(&self) -> bool {
409        self.0.is_empty()
410    }
411    fn new() -> Self {
412        Self(Vec::new())
413    }
414    fn push(&mut self, item: Self::Item) {
415        self.0.push(item)
416    }
417    fn remove(&mut self, index: usize) -> Self::Item {
418        self.0.remove(index)
419    }
420    fn reserve(&mut self, additional: usize) {
421        self.0.reserve(additional)
422    }
423    fn retain<F>(&mut self, f: F)
424    where
425        F: FnMut(&Self::Item) -> bool,
426    {
427        self.0.retain(f)
428    }
429    fn swap_remove(&mut self, index: usize) -> Self::Item {
430        self.0.swap_remove(index)
431    }
432    fn with_capacity(capacity: usize) -> Self {
433        Self(Vec::with_capacity(capacity))
434    }
435}
436
437impl Sum for SquareMatrix {
438    fn sum<Ii>(iter: Ii) -> Self
439    where
440        Ii: Iterator<Item = Self>,
441    {
442        iter.reduce(|mut acc, item| {
443            acc += item;
444            acc
445        })
446        .unwrap_or_else(Self::default)
447    }
448}
449
450impl Div<Scalar> for SquareMatrix {
451    type Output = Self;
452    fn div(mut self, tensor_rank_0: Scalar) -> Self::Output {
453        self /= &tensor_rank_0;
454        self
455    }
456}
457
458impl Div<&Scalar> for SquareMatrix {
459    type Output = Self;
460    fn div(mut self, tensor_rank_0: &Scalar) -> Self::Output {
461        self /= tensor_rank_0;
462        self
463    }
464}
465
466impl DivAssign<Scalar> for SquareMatrix {
467    fn div_assign(&mut self, tensor_rank_0: Scalar) {
468        self.iter_mut().for_each(|entry| *entry /= &tensor_rank_0);
469    }
470}
471
472impl DivAssign<&Scalar> for SquareMatrix {
473    fn div_assign(&mut self, tensor_rank_0: &Scalar) {
474        self.iter_mut().for_each(|entry| *entry /= tensor_rank_0);
475    }
476}
477
478impl Mul<Scalar> for SquareMatrix {
479    type Output = Self;
480    fn mul(mut self, tensor_rank_0: Scalar) -> Self::Output {
481        self *= &tensor_rank_0;
482        self
483    }
484}
485
486impl Mul<&Scalar> for SquareMatrix {
487    type Output = Self;
488    fn mul(mut self, tensor_rank_0: &Scalar) -> Self::Output {
489        self *= tensor_rank_0;
490        self
491    }
492}
493
494impl Mul<&Scalar> for &SquareMatrix {
495    type Output = SquareMatrix;
496    fn mul(self, tensor_rank_0: &Scalar) -> Self::Output {
497        self.iter().map(|self_i| self_i * tensor_rank_0).collect()
498    }
499}
500
501impl MulAssign<Scalar> for SquareMatrix {
502    fn mul_assign(&mut self, tensor_rank_0: Scalar) {
503        self.iter_mut().for_each(|entry| *entry *= &tensor_rank_0);
504    }
505}
506
507impl MulAssign<&Scalar> for SquareMatrix {
508    fn mul_assign(&mut self, tensor_rank_0: &Scalar) {
509        self.iter_mut().for_each(|entry| *entry *= tensor_rank_0);
510    }
511}
512
513impl Mul<Vector> for SquareMatrix {
514    type Output = Vector;
515    fn mul(self, vector: Vector) -> Self::Output {
516        self.iter().map(|self_i| self_i * &vector).collect()
517    }
518}
519
520impl Mul<&Vector> for SquareMatrix {
521    type Output = Vector;
522    fn mul(self, vector: &Vector) -> Self::Output {
523        self.iter().map(|self_i| self_i * vector).collect()
524    }
525}
526
527impl Add for SquareMatrix {
528    type Output = Self;
529    fn add(mut self, vector: Self) -> Self::Output {
530        self += vector;
531        self
532    }
533}
534
535impl Add<&Self> for SquareMatrix {
536    type Output = Self;
537    fn add(mut self, vector: &Self) -> Self::Output {
538        self += vector;
539        self
540    }
541}
542
543impl AddAssign for SquareMatrix {
544    fn add_assign(&mut self, vector: Self) {
545        self.iter_mut()
546            .zip(vector.iter())
547            .for_each(|(self_entry, tensor_rank_1)| *self_entry += tensor_rank_1);
548    }
549}
550
551impl AddAssign<&Self> for SquareMatrix {
552    fn add_assign(&mut self, vector: &Self) {
553        self.iter_mut()
554            .zip(vector.iter())
555            .for_each(|(self_entry, tensor_rank_1)| *self_entry += tensor_rank_1);
556    }
557}
558
559impl Mul for SquareMatrix {
560    type Output = Self;
561    fn mul(self, matrix: Self) -> Self::Output {
562        let mut output = Self::zero(matrix.len());
563        self.iter()
564            .zip(output.iter_mut())
565            .for_each(|(self_i, output_i)| {
566                self_i
567                    .iter()
568                    .zip(matrix.iter())
569                    .for_each(|(self_ij, matrix_j)| *output_i += matrix_j * self_ij)
570            });
571        output
572    }
573}
574
575impl Sub for SquareMatrix {
576    type Output = Self;
577    fn sub(mut self, square_matrix: Self) -> Self::Output {
578        self -= square_matrix;
579        self
580    }
581}
582
583impl Sub<&Self> for SquareMatrix {
584    type Output = Self;
585    fn sub(mut self, square_matrix: &Self) -> Self::Output {
586        self -= square_matrix;
587        self
588    }
589}
590
591impl Sub for &SquareMatrix {
592    type Output = SquareMatrix;
593    fn sub(self, square_matrix: Self) -> Self::Output {
594        square_matrix
595            .iter()
596            .zip(self.iter())
597            .map(|(square_matrix_i, self_i)| self_i - square_matrix_i)
598            .collect()
599    }
600}
601
602impl SubAssign for SquareMatrix {
603    fn sub_assign(&mut self, square_matrix: Self) {
604        self.iter_mut()
605            .zip(square_matrix.iter())
606            .for_each(|(self_entry, tensor_rank_1)| *self_entry -= tensor_rank_1);
607    }
608}
609
610impl SubAssign<&Self> for SquareMatrix {
611    fn sub_assign(&mut self, square_matrix: &Self) {
612        self.iter_mut()
613            .zip(square_matrix.iter())
614            .for_each(|(self_entry, tensor_rank_1)| *self_entry -= tensor_rank_1);
615    }
616}