conspire/math/matrix/square/
mod.rs1#[cfg(test)]
2mod test;
3
4#[cfg(test)]
5use crate::math::test::ErrorTensor;
6
7use crate::{
8    ABS_TOL,
9    math::{
10        Hessian, Rank2, Scalar, Tensor, TensorRank2Vec2D, TensorVec, Vector, write_tensor_rank_0,
11    },
12};
13use std::{
14    collections::VecDeque,
15    fmt::{self, Display, Formatter},
16    iter::Sum,
17    ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Sub, SubAssign},
18    vec::IntoIter,
19};
20
21pub struct Banded {
23    bandwidth: usize,
24    inverse: Vec<usize>,
25    mapping: Vec<usize>,
26}
27
28impl Banded {
29    pub fn map(&self, old: usize) -> usize {
30        self.inverse[old]
31    }
32    pub fn old(&self, new: usize) -> usize {
33        self.mapping[new]
34    }
35    pub fn width(&self) -> usize {
36        self.bandwidth
37    }
38}
39
40impl From<Vec<Vec<bool>>> for Banded {
41    fn from(structure: Vec<Vec<bool>>) -> Self {
42        let num = structure.len();
43        structure.iter().enumerate().for_each(|(i, row_i)| {
44            assert_eq!(row_i.len(), num);
45            row_i
46                .iter()
47                .zip(structure.iter())
48                .for_each(|(entry_ij, row_j)| assert_eq!(&row_j[i], entry_ij))
49        });
50        let mut adj_list = vec![Vec::new(); num];
51        (0..num).for_each(|i| {
52            (0..num)
53                .filter(|&j| structure[i][j] && i != j)
54                .for_each(|j| adj_list[i].push(j))
55        });
56        let start_vertex = (0..num)
57            .min_by_key(|&i| adj_list[i].len())
58            .expect("Matrix must have at least one entry.");
59        let mut visited = vec![false; num];
60        let mut mapping = Vec::new();
61        let mut queue = VecDeque::new();
62        queue.push_back(start_vertex);
63        visited[start_vertex] = true;
64        while let Some(vertex) = queue.pop_front() {
65            mapping.push(vertex);
66            let mut neighbors: Vec<usize> = adj_list[vertex]
67                .iter()
68                .filter(|&&neighbor| !visited[neighbor])
69                .copied()
70                .collect();
71            neighbors.sort_by_key(|&neighbor| adj_list[neighbor].len());
72            for neighbor in neighbors {
73                visited[neighbor] = true;
74                queue.push_back(neighbor);
75            }
76        }
77        mapping.reverse();
78        let mut inverse = vec![0; num];
79        mapping
80            .iter()
81            .enumerate()
82            .for_each(|(new, &old)| inverse[old] = new);
83        let mut bandwidth = 0;
84        (0..num).for_each(|i| {
85            (i + 1..num)
86                .filter(|&j| structure[mapping[i]][mapping[j]])
87                .for_each(|j| bandwidth = bandwidth.max(j - i))
88        });
89        Self {
90            bandwidth,
91            mapping,
92            inverse,
93        }
94    }
95}
96
97#[derive(Debug, PartialEq)]
99pub enum SquareMatrixError {
100    Singular,
101}
102
103#[derive(Clone, Debug, PartialEq)]
105pub struct SquareMatrix(Vec<Vector>);
106
107impl Default for SquareMatrix {
108    fn default() -> Self {
109        Self::new()
110    }
111}
112
113impl SquareMatrix {
114    pub fn solve_lu(&self, b: &Vector) -> Result<Vector, SquareMatrixError> {
191        let n = self.len();
192        let mut p: Vec<usize> = (0..n).collect();
193        let mut factor;
194        let mut lu = self.clone();
195        let mut max_row;
196        let mut max_val;
197        let mut pivot;
198        for i in 0..n {
199            max_row = i;
200            max_val = lu[max_row][i].abs();
201            for k in i + 1..n {
202                if lu[k][i].abs() > max_val {
203                    max_row = k;
204                    max_val = lu[max_row][i].abs();
205                }
206            }
207            if max_row != i {
208                lu.0.swap(i, max_row);
209                p.swap(i, max_row);
210            }
211            pivot = lu[i][i];
212            if pivot.abs() < ABS_TOL {
213                return Err(SquareMatrixError::Singular);
214            }
215            for j in i + 1..n {
216                if lu[j][i] != 0.0 {
217                    lu[j][i] /= pivot;
218                    factor = lu[j][i];
219                    for k in i + 1..n {
220                        lu[j][k] -= factor * lu[i][k];
221                    }
222                }
223            }
224        }
225        let mut x: Vector = p.into_iter().map(|p_i| b[p_i]).collect();
226        forward_substitution(&mut x, &lu);
227        backward_substitution(&mut x, &lu);
228        Ok(x)
229    }
230    pub fn solve_lu_banded(
232        &self,
233        b: &Vector,
234        banded: &Banded,
235    ) -> Result<Vector, SquareMatrixError> {
236        let bandwidth = banded.width();
237        let mut bandwidth_updated;
238        let n = self.len();
239        let mut p: Vec<usize> = (0..n).collect();
240        let mut end;
241        let mut factor;
242        let mut max_row;
243        let mut max_val;
244        let mut pivot;
245        let mut rearr: Self = (0..n)
246            .map(|i| (0..n).map(|j| self[banded.old(i)][banded.old(j)]).collect())
247            .collect();
248        for i in 0..n {
249            end = n.min(i + 1 + bandwidth);
250            pivot = rearr[i][i];
251            if pivot.abs() < ABS_TOL {
252                max_row = i;
253                max_val = rearr[max_row][i].abs();
254                for k in i + 1..end {
255                    if rearr[k][i].abs() > max_val {
256                        max_row = k;
257                        max_val = rearr[max_row][i].abs();
258                    }
259                }
260                if max_row != i {
261                    rearr.0.swap(i, max_row);
262                    p.swap(i, max_row);
263                    pivot = rearr[i][i];
264                    if pivot.abs() < ABS_TOL {
265                        return Err(SquareMatrixError::Singular);
266                    }
267                }
268            }
269            bandwidth_updated = bandwidth;
270            (i + 1 + bandwidth..n).for_each(|j| {
271                if rearr[i][j] != 0.0 {
272                    bandwidth_updated = bandwidth_updated.max(j - i)
273                }
274            });
275            end = n.min(i + 1 + bandwidth_updated);
276            for j in i + 1..end {
277                if rearr[j][i] != 0.0 {
278                    rearr[j][i] /= pivot;
279                    factor = rearr[j][i];
280                    for k in i + 1..end {
281                        rearr[j][k] -= factor * rearr[i][k];
282                    }
283                }
284            }
285        }
286        let mut x: Vector = p.into_iter().map(|p_i| b[banded.old(p_i)]).collect();
287        forward_substitution(&mut x, &rearr);
288        backward_substitution(&mut x, &rearr);
289        Ok((0..n).map(|i| x[banded.map(i)]).collect())
290    }
291    pub fn zero(len: usize) -> Self {
292        (0..len).map(|_| Vector::zero(len)).collect()
293    }
294}
295
296fn forward_substitution(x: &mut Vector, a: &SquareMatrix) {
297    a.iter().enumerate().for_each(|(i, a_i)| {
298        x[i] -= a_i
299            .iter()
300            .take(i)
301            .zip(x.iter().take(i))
302            .map(|(a_ij, x_j)| a_ij * x_j)
303            .sum::<Scalar>()
304    })
305}
306
307fn backward_substitution(x: &mut Vector, a: &SquareMatrix) {
308    a.0.iter().enumerate().rev().for_each(|(i, a_i)| {
309        x[i] -= a_i
310            .iter()
311            .skip(i + 1)
312            .zip(x.iter().skip(i + 1))
313            .map(|(a_ij, x_j)| a_ij * x_j)
314            .sum::<Scalar>();
315        x[i] /= a_i[i];
316    })
317}
318
319#[cfg(test)]
320impl ErrorTensor for SquareMatrix {
321    fn error_fd(&self, comparator: &Self, epsilon: &Scalar) -> Option<(bool, usize)> {
322        let error_count = self
323            .iter()
324            .zip(comparator.iter())
325            .map(|(self_i, comparator_i)| {
326                self_i
327                    .iter()
328                    .zip(comparator_i.iter())
329                    .filter(|&(&self_ij, &comparator_ij)| {
330                        &(self_ij / comparator_ij - 1.0).abs() >= epsilon
331                            && (&self_ij.abs() >= epsilon || &comparator_ij.abs() >= epsilon)
332                    })
333                    .count()
334            })
335            .sum();
336        if error_count > 0 {
337            Some((true, error_count))
338        } else {
339            None
340        }
341    }
342}
343
344impl Display for SquareMatrix {
345    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
346        write!(f, "\x1B[s")?;
347        write!(f, "[[")?;
348        self.iter().enumerate().try_for_each(|(i, row)| {
349            row.iter()
350                .try_for_each(|entry| write_tensor_rank_0(f, entry))?;
351            if i + 1 < self.len() {
352                writeln!(f, "\x1B[2D],")?;
353                write!(f, "\x1B[u")?;
354                write!(f, "\x1B[{}B [", i + 1)?;
355            }
356            Ok(())
357        })?;
358        write!(f, "\x1B[2D]]")
359    }
360}
361
362impl<const N: usize> From<[[Scalar; N]; N]> for SquareMatrix {
363    fn from(array: [[Scalar; N]; N]) -> Self {
364        array.into_iter().map(Vector::from).collect()
365    }
366}
367
368impl<const D: usize, const I: usize, const J: usize> From<TensorRank2Vec2D<D, I, J>>
369    for SquareMatrix
370{
371    fn from(tensor_rank_2_vec_2d: TensorRank2Vec2D<D, I, J>) -> Self {
372        let mut square_matrix = Self::zero(tensor_rank_2_vec_2d.len() * D);
373        tensor_rank_2_vec_2d
374            .iter()
375            .enumerate()
376            .for_each(|(a, entry_a)| {
377                entry_a.iter().enumerate().for_each(|(b, entry_ab)| {
378                    entry_ab.iter().enumerate().for_each(|(i, entry_ab_i)| {
379                        entry_ab_i.iter().enumerate().for_each(|(j, entry_ab_ij)| {
380                            square_matrix[D * a + i][D * b + j] = *entry_ab_ij
381                        })
382                    })
383                })
384            });
385        square_matrix
386    }
387}
388
389impl FromIterator<Vector> for SquareMatrix {
390    fn from_iter<Ii: IntoIterator<Item = Vector>>(into_iterator: Ii) -> Self {
391        Self(Vec::from_iter(into_iterator))
392    }
393}
394
395impl Index<usize> for SquareMatrix {
396    type Output = Vector;
397    fn index(&self, index: usize) -> &Self::Output {
398        &self.0[index]
399    }
400}
401
402impl IndexMut<usize> for SquareMatrix {
403    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
404        &mut self.0[index]
405    }
406}
407
408impl Hessian for SquareMatrix {
409    fn fill_into(self, square_matrix: &mut SquareMatrix) {
410        self.into_iter()
411            .zip(square_matrix.iter_mut())
412            .for_each(|(self_i, square_matrix_i)| {
413                self_i
414                    .into_iter()
415                    .zip(square_matrix_i.iter_mut())
416                    .for_each(|(self_ij, square_matrix_ij)| *square_matrix_ij = self_ij)
417            });
418    }
419}
420
421impl Rank2 for SquareMatrix {
422    type Transpose = Self;
423    fn deviatoric(&self) -> Self {
424        let len = self.len();
425        let scale = -self.trace() / len as Scalar;
426        (0..len)
427            .map(|i| {
428                (0..len)
429                    .map(|j| ((i == j) as u8) as Scalar * scale)
430                    .collect()
431            })
432            .collect::<Self>()
433            + self
434    }
435    fn deviatoric_and_trace(&self) -> (Self, Scalar) {
436        let len = self.len();
437        let trace = self.trace();
438        let scale = -trace / len as Scalar;
439        (
440            (0..len)
441                .map(|i| {
442                    (0..len)
443                        .map(|j| ((i == j) as u8) as Scalar * scale)
444                        .collect()
445                })
446                .collect::<Self>()
447                + self,
448            trace,
449        )
450    }
451    fn is_diagonal(&self) -> bool {
452        self.iter()
453            .enumerate()
454            .map(|(i, self_i)| {
455                self_i
456                    .iter()
457                    .enumerate()
458                    .map(|(j, self_ij)| (self_ij == &0.0) as u8 * (i != j) as u8)
459                    .sum::<u8>()
460            })
461            .sum::<u8>()
462            == (self.len().pow(2) - self.len()) as u8
463    }
464    fn is_identity(&self) -> bool {
465        self.iter().enumerate().all(|(i, self_i)| {
466            self_i
467                .iter()
468                .enumerate()
469                .all(|(j, self_ij)| self_ij == &((i == j) as u8 as Scalar))
470        })
471    }
472    fn is_symmetric(&self) -> bool {
473        self.iter().enumerate().all(|(i, self_i)| {
474            self_i
475                .iter()
476                .zip(self.iter())
477                .all(|(self_ij, self_j)| self_ij == &self_j[i])
478        })
479    }
480    fn squared_trace(&self) -> Scalar {
481        self.iter()
482            .enumerate()
483            .map(|(i, self_i)| {
484                self_i
485                    .iter()
486                    .zip(self.iter())
487                    .map(|(self_ij, self_j)| self_ij * self_j[i])
488                    .sum::<Scalar>()
489            })
490            .sum()
491    }
492    fn trace(&self) -> Scalar {
493        self.iter().enumerate().map(|(i, self_i)| self_i[i]).sum()
494    }
495    fn transpose(&self) -> Self::Transpose {
496        (0..self.len())
497            .map(|i| (0..self.len()).map(|j| self[j][i]).collect())
498            .collect()
499    }
500}
501
502impl Tensor for SquareMatrix {
503    type Item = Vector;
504    fn iter(&self) -> impl Iterator<Item = &Self::Item> {
505        self.0.iter()
506    }
507    fn iter_mut(&mut self) -> impl Iterator<Item = &mut Self::Item> {
508        self.0.iter_mut()
509    }
510    fn len(&self) -> usize {
511        self.0.len()
512    }
513    fn size(&self) -> usize {
514        unimplemented!("Do not like that inner Vecs could be different sizes")
515    }
516}
517
518impl IntoIterator for SquareMatrix {
519    type Item = Vector;
520    type IntoIter = IntoIter<Self::Item>;
521    fn into_iter(self) -> Self::IntoIter {
522        self.0.into_iter()
523    }
524}
525
526impl TensorVec for SquareMatrix {
527    type Item = Vector;
528    fn append(&mut self, other: &mut Self) {
529        self.0.append(&mut other.0)
530    }
531    fn capacity(&self) -> usize {
532        self.0.capacity()
533    }
534    fn is_empty(&self) -> bool {
535        self.0.is_empty()
536    }
537    fn new() -> Self {
538        Self(Vec::new())
539    }
540    fn push(&mut self, item: Self::Item) {
541        self.0.push(item)
542    }
543    fn remove(&mut self, index: usize) -> Self::Item {
544        self.0.remove(index)
545    }
546    fn retain<F>(&mut self, f: F)
547    where
548        F: FnMut(&Self::Item) -> bool,
549    {
550        self.0.retain(f)
551    }
552    fn swap_remove(&mut self, index: usize) -> Self::Item {
553        self.0.swap_remove(index)
554    }
555}
556
557impl Sum for SquareMatrix {
558    fn sum<Ii>(iter: Ii) -> Self
559    where
560        Ii: Iterator<Item = Self>,
561    {
562        iter.reduce(|mut acc, item| {
563            acc += item;
564            acc
565        })
566        .unwrap_or_else(Self::default)
567    }
568}
569
570impl Div<Scalar> for SquareMatrix {
571    type Output = Self;
572    fn div(mut self, tensor_rank_0: Scalar) -> Self::Output {
573        self /= &tensor_rank_0;
574        self
575    }
576}
577
578impl Div<&Scalar> for SquareMatrix {
579    type Output = Self;
580    fn div(mut self, tensor_rank_0: &Scalar) -> Self::Output {
581        self /= tensor_rank_0;
582        self
583    }
584}
585
586impl DivAssign<Scalar> for SquareMatrix {
587    fn div_assign(&mut self, tensor_rank_0: Scalar) {
588        self.iter_mut().for_each(|entry| *entry /= &tensor_rank_0);
589    }
590}
591
592impl DivAssign<&Scalar> for SquareMatrix {
593    fn div_assign(&mut self, tensor_rank_0: &Scalar) {
594        self.iter_mut().for_each(|entry| *entry /= tensor_rank_0);
595    }
596}
597
598impl Mul<Scalar> for SquareMatrix {
599    type Output = Self;
600    fn mul(mut self, tensor_rank_0: Scalar) -> Self::Output {
601        self *= &tensor_rank_0;
602        self
603    }
604}
605
606impl Mul<&Scalar> for SquareMatrix {
607    type Output = Self;
608    fn mul(mut self, tensor_rank_0: &Scalar) -> Self::Output {
609        self *= tensor_rank_0;
610        self
611    }
612}
613
614impl Mul<&Scalar> for &SquareMatrix {
615    type Output = SquareMatrix;
616    fn mul(self, tensor_rank_0: &Scalar) -> Self::Output {
617        self.iter().map(|self_i| self_i * tensor_rank_0).collect()
618    }
619}
620
621impl MulAssign<Scalar> for SquareMatrix {
622    fn mul_assign(&mut self, tensor_rank_0: Scalar) {
623        self.iter_mut().for_each(|entry| *entry *= &tensor_rank_0);
624    }
625}
626
627impl MulAssign<&Scalar> for SquareMatrix {
628    fn mul_assign(&mut self, tensor_rank_0: &Scalar) {
629        self.iter_mut().for_each(|entry| *entry *= tensor_rank_0);
630    }
631}
632
633impl Mul<Vector> for SquareMatrix {
634    type Output = Vector;
635    fn mul(self, vector: Vector) -> Self::Output {
636        self.iter().map(|self_i| self_i * &vector).collect()
637    }
638}
639
640impl Mul<&Vector> for SquareMatrix {
641    type Output = Vector;
642    fn mul(self, vector: &Vector) -> Self::Output {
643        self.iter().map(|self_i| self_i * vector).collect()
644    }
645}
646
647impl Add for SquareMatrix {
648    type Output = Self;
649    fn add(mut self, vector: Self) -> Self::Output {
650        self += vector;
651        self
652    }
653}
654
655impl Add<&Self> for SquareMatrix {
656    type Output = Self;
657    fn add(mut self, vector: &Self) -> Self::Output {
658        self += vector;
659        self
660    }
661}
662
663impl AddAssign for SquareMatrix {
664    fn add_assign(&mut self, vector: Self) {
665        self.iter_mut()
666            .zip(vector.iter())
667            .for_each(|(self_entry, tensor_rank_1)| *self_entry += tensor_rank_1);
668    }
669}
670
671impl AddAssign<&Self> for SquareMatrix {
672    fn add_assign(&mut self, vector: &Self) {
673        self.iter_mut()
674            .zip(vector.iter())
675            .for_each(|(self_entry, tensor_rank_1)| *self_entry += tensor_rank_1);
676    }
677}
678
679impl Mul for SquareMatrix {
680    type Output = Self;
681    fn mul(self, matrix: Self) -> Self::Output {
682        let mut output = Self::zero(matrix.len());
683        self.iter()
684            .zip(output.iter_mut())
685            .for_each(|(self_i, output_i)| {
686                self_i
687                    .iter()
688                    .zip(matrix.iter())
689                    .for_each(|(self_ij, matrix_j)| *output_i += matrix_j * self_ij)
690            });
691        output
692    }
693}
694
695impl Sub for SquareMatrix {
696    type Output = Self;
697    fn sub(mut self, square_matrix: Self) -> Self::Output {
698        self -= square_matrix;
699        self
700    }
701}
702
703impl Sub<&Self> for SquareMatrix {
704    type Output = Self;
705    fn sub(mut self, square_matrix: &Self) -> Self::Output {
706        self -= square_matrix;
707        self
708    }
709}
710
711impl Sub for &SquareMatrix {
712    type Output = SquareMatrix;
713    fn sub(self, square_matrix: Self) -> Self::Output {
714        square_matrix
715            .iter()
716            .zip(self.iter())
717            .map(|(square_matrix_i, self_i)| self_i - square_matrix_i)
718            .collect()
719    }
720}
721
722impl SubAssign for SquareMatrix {
723    fn sub_assign(&mut self, square_matrix: Self) {
724        self.iter_mut()
725            .zip(square_matrix.iter())
726            .for_each(|(self_entry, tensor_rank_1)| *self_entry -= tensor_rank_1);
727    }
728}
729
730impl SubAssign<&Self> for SquareMatrix {
731    fn sub_assign(&mut self, square_matrix: &Self) {
732        self.iter_mut()
733            .zip(square_matrix.iter())
734            .for_each(|(self_entry, tensor_rank_1)| *self_entry -= tensor_rank_1);
735    }
736}