Skip to main content

sciforge_lib/maths/tensor/
linalg.rs

1use super::ops::transpose;
2use super::storage::Tensor;
3
4pub fn trace(t: &Tensor) -> f64 {
5    assert!(t.rank() == 2 && t.shape()[0] == t.shape()[1]);
6    (0..t.shape()[0]).map(|i| t.get(&[i, i])).sum()
7}
8
9pub fn matmul(a: &Tensor, b: &Tensor) -> Tensor {
10    assert!(a.rank() == 2 && b.rank() == 2);
11    assert_eq!(a.shape()[1], b.shape()[0]);
12    let (m, n, p) = (a.shape()[0], a.shape()[1], b.shape()[1]);
13    Tensor::from_fn(&[m, p], |idx| {
14        (0..n)
15            .map(|k| a.get(&[idx[0], k]) * b.get(&[k, idx[1]]))
16            .sum()
17    })
18}
19
20pub fn minor(t: &Tensor, row: usize, col: usize) -> Tensor {
21    let n = t.shape()[0];
22    let mut data = Vec::with_capacity((n - 1) * (n - 1));
23    for i in 0..n {
24        if i == row {
25            continue;
26        }
27        for j in 0..n {
28            if j == col {
29                continue;
30            }
31            data.push(t.get(&[i, j]));
32        }
33    }
34    Tensor::from_vec(&[n - 1, n - 1], data)
35}
36
37pub fn determinant(t: &Tensor) -> f64 {
38    assert!(t.rank() == 2 && t.shape()[0] == t.shape()[1]);
39    let n = t.shape()[0];
40    if n == 1 {
41        return t.get(&[0, 0]);
42    }
43    if n == 2 {
44        return t.get(&[0, 0]) * t.get(&[1, 1]) - t.get(&[0, 1]) * t.get(&[1, 0]);
45    }
46    let mut det = 0.0;
47    for j in 0..n {
48        let sign = if j % 2 == 0 { 1.0 } else { -1.0 };
49        det += sign * t.get(&[0, j]) * determinant(&minor(t, 0, j));
50    }
51    det
52}
53
54pub fn inverse(t: &Tensor) -> Option<Tensor> {
55    assert!(t.rank() == 2 && t.shape()[0] == t.shape()[1]);
56    let n = t.shape()[0];
57    let det = determinant(t);
58    if det.abs() < 1e-15 {
59        return None;
60    }
61    let cofactors = Tensor::from_fn(&[n, n], |idx| {
62        let sign = if (idx[0] + idx[1]) % 2 == 0 {
63            1.0
64        } else {
65            -1.0
66        };
67        sign * determinant(&minor(t, idx[0], idx[1]))
68    });
69    let adjugate = transpose(&cofactors, &[1, 0]);
70    Some(adjugate.scale(1.0 / det))
71}
72
73pub fn eigenvalues_2x2(t: &Tensor) -> (f64, f64) {
74    assert!(t.rank() == 2 && t.shape() == [2, 2]);
75    let a = t.get(&[0, 0]);
76    let b = t.get(&[0, 1]);
77    let c = t.get(&[1, 0]);
78    let d = t.get(&[1, 1]);
79    let tr = a + d;
80    let det = a * d - b * c;
81    let disc = (tr * tr - 4.0 * det).max(0.0).sqrt();
82    ((tr + disc) / 2.0, (tr - disc) / 2.0)
83}
84
85pub fn lu_decompose(t: &Tensor) -> (Tensor, Tensor) {
86    assert!(t.rank() == 2 && t.shape()[0] == t.shape()[1]);
87    let n = t.shape()[0];
88    let mut l = Tensor::identity(n);
89    let mut u = t.clone();
90    for j in 0..n {
91        for i in (j + 1)..n {
92            let pivot = u.get(&[j, j]);
93            if pivot.abs() < 1e-30 {
94                continue;
95            }
96            let factor = u.get(&[i, j]) / pivot;
97            l.set(&[i, j], factor);
98            for k in j..n {
99                let val = u.get(&[i, k]) - factor * u.get(&[j, k]);
100                u.set(&[i, k], val);
101            }
102        }
103    }
104    (l, u)
105}
106
107pub fn solve(a: &Tensor, b: &[f64]) -> Vec<f64> {
108    let (l, u) = lu_decompose(a);
109    let n = a.shape()[0];
110    let mut y = vec![0.0; n];
111    for i in 0..n {
112        y[i] = b[i];
113        for j in 0..i {
114            y[i] -= l.get(&[i, j]) * y[j];
115        }
116    }
117    let mut x = vec![0.0; n];
118    for i in (0..n).rev() {
119        x[i] = y[i];
120        for j in (i + 1)..n {
121            x[i] -= u.get(&[i, j]) * x[j];
122        }
123        let pivot = u.get(&[i, i]);
124        if pivot.abs() > 1e-30 {
125            x[i] /= pivot;
126        }
127    }
128    x
129}