1use std::ops::{Index, IndexMut};
11
12use crate::{geop_error::GeopResult, scalars::Scalar, vector::Vector};
13
14#[derive(Debug, Clone, Copy)]
16pub struct Matrix<S, const R: usize, const C: usize> {
17 data: [[S; C]; R],
18}
19
20impl<S: Scalar, const R: usize, const C: usize> Matrix<S, R, C> {
21 pub fn from_rows(data: [[S; C]; R]) -> Self {
22 Self { data }
23 }
24
25 pub fn zero() -> Self {
26 Self {
27 data: [[S::ZERO; C]; R],
28 }
29 }
30
31 pub fn from_columns(cols: [Vector<S, R>; C]) -> Self {
33 let mut out = Self::zero();
34 for (c, col) in cols.iter().enumerate() {
35 for r in 0..R {
36 out.data[r][c] = col[r];
37 }
38 }
39 out
40 }
41
42 pub fn row(&self, r: usize) -> Vector<S, C> {
43 Vector::from_array(self.data[r])
44 }
45
46 pub fn col(&self, c: usize) -> Vector<S, R> {
47 let mut out = Vector::<S, R>::zero();
48 for r in 0..R {
49 out[r] = self.data[r][c];
50 }
51 out
52 }
53
54 pub fn transpose(&self) -> Matrix<S, C, R> {
55 let mut out = Matrix::<S, C, R>::zero();
56 for r in 0..R {
57 for c in 0..C {
58 out[(c, r)] = self[(r, c)];
59 }
60 }
61 out
62 }
63
64 pub fn add(&self, other: &Self) -> Self {
65 let mut out = Self::zero();
66 for r in 0..R {
67 for c in 0..C {
68 out[(r, c)] = self[(r, c)].add(other[(r, c)]);
69 }
70 }
71 out
72 }
73
74 pub fn sub(&self, other: &Self) -> Self {
75 let mut out = Self::zero();
76 for r in 0..R {
77 for c in 0..C {
78 out[(r, c)] = self[(r, c)].sub(other[(r, c)]);
79 }
80 }
81 out
82 }
83
84 pub fn mul_vec(&self, v: &Vector<S, C>) -> Vector<S, R> {
86 let mut out = Vector::<S, R>::zero();
87 for r in 0..R {
88 out[r] = self.row(r).prod_dot(v);
89 }
90 out
91 }
92
93 pub fn mul_mat<const K: usize>(&self, other: &Matrix<S, C, K>) -> Matrix<S, R, K> {
95 let mut out = Matrix::<S, R, K>::zero();
96 for r in 0..R {
97 for k in 0..K {
98 out[(r, k)] = self.row(r).prod_dot(&other.col(k));
99 }
100 }
101 out
102 }
103
104 fn swap_rows(&mut self, i: usize, j: usize) {
105 self.data.swap(i, j);
106 }
107}
108
109impl<S: Scalar, const N: usize> Matrix<S, N, N> {
110 pub fn identity() -> Self {
111 let mut out = Self::zero();
112 for i in 0..N {
113 out[(i, i)] = S::ONE;
114 }
115 out
116 }
117}
118
119impl<S, const R: usize, const C: usize> Index<(usize, usize)> for Matrix<S, R, C> {
120 type Output = S;
121 fn index(&self, (r, c): (usize, usize)) -> &S {
122 &self.data[r][c]
123 }
124}
125impl<S, const R: usize, const C: usize> IndexMut<(usize, usize)> for Matrix<S, R, C> {
126 fn index_mut(&mut self, (r, c): (usize, usize)) -> &mut S {
127 &mut self.data[r][c]
128 }
129}
130
131pub fn solve_linear_system<S: Scalar, const N: usize>(
149 a: &Matrix<S, N, N>,
150 b: &Vector<S, N>,
151) -> GeopResult<Vector<S, N>> {
152 let mut a = *a;
153 let mut b = *b;
154
155 for col in 0..N {
156 let mut pivot = col;
157 for row in (col + 1)..N {
158 if a[(row, col)]
159 .abs()
160 .sharpen()
161 .definitely_greater(a[(pivot, col)].abs().sharpen())
162 {
163 pivot = row;
164 }
165 }
166 a.swap_rows(col, pivot);
167 let tmp = b[col];
168 b[col] = b[pivot];
169 b[pivot] = tmp;
170
171 for row in (col + 1)..N {
172 let factor = a[(row, col)].div(a[(col, col)]).map_err(|e| {
173 e.with_context(format!(
174 "solve_linear_system: singular at column {col}, pivot={:?}",
175 a[(col, col)]
176 ))
177 })?;
178 for k in col..N {
179 a[(row, k)] = a[(row, k)].sub(factor.mul(a[(col, k)]));
180 }
181 b[row] = b[row].sub(factor.mul(b[col]));
182 }
183 }
184
185 let mut x = Vector::<S, N>::zero();
186 for row in (0..N).rev() {
187 let mut sum = b[row];
188 for k in (row + 1)..N {
189 sum = sum.sub(a[(row, k)].mul(x[k]));
190 }
191 x[row] = sum.div(a[(row, row)]).map_err(|e| {
192 e.with_context(format!(
193 "solve_linear_system: singular at row {row}, pivot={:?}",
194 a[(row, row)]
195 ))
196 })?;
197 }
198 Ok(x)
199}
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204 use crate::for_all_scalars;
205
206 fn check_solves_identity<S: Scalar>() {
207 let a = Matrix::<S, 2, 2>::identity();
208 let b = Vector::<S, 2>::from_array([S::from_f64(3.0), S::from_f64(4.0)]);
209 let x = solve_linear_system(&a, &b).unwrap();
210 assert!(x[0].could_be_equal(S::from_f64(3.0)));
211 assert!(x[1].could_be_equal(S::from_f64(4.0)));
212 }
213 #[test]
214 fn solves_identity() {
215 for_all_scalars!(check_solves_identity);
216 }
217
218 fn check_solves_general_2x2<S: Scalar>() {
219 let a = Matrix::from_rows([
221 [S::from_f64(2.0), S::from_f64(1.0)],
222 [S::from_f64(1.0), S::from_f64(3.0)],
223 ]);
224 let b = Vector::from_array([S::from_f64(5.0), S::from_f64(10.0)]);
225 let x = solve_linear_system(&a, &b).unwrap();
226 assert!(x[0].could_be_equal(S::ONE));
227 assert!(x[1].could_be_equal(S::from_f64(3.0)));
228 }
229 #[test]
230 fn solves_general_2x2() {
231 for_all_scalars!(check_solves_general_2x2);
232 }
233
234 fn check_singular_errs<S: Scalar>() {
235 let a = Matrix::from_rows([[S::ONE, S::ONE], [S::ONE, S::ONE]]);
236 let b = Vector::from_array([S::ONE, S::TWO]);
237 assert!(solve_linear_system(&a, &b).is_err());
238 }
239 #[test]
240 fn singular_errs() {
241 for_all_scalars!(check_singular_errs);
242 }
243
244 fn check_transpose_and_mul<S: Scalar>() {
245 let m = Matrix::<S, 2, 3>::from_rows([
246 [S::from_f64(1.0), S::from_f64(2.0), S::from_f64(3.0)],
247 [S::from_f64(4.0), S::from_f64(5.0), S::from_f64(6.0)],
248 ]);
249 let mt = m.transpose();
250 assert!(mt[(0, 1)].could_be_equal(S::from_f64(4.0)));
251 assert!(mt[(2, 0)].could_be_equal(S::from_f64(3.0)));
252
253 let v = Vector::<S, 3>::from_array([S::ONE, S::ONE, S::ONE]);
254 let mv = m.mul_vec(&v);
255 assert!(mv[0].could_be_equal(S::from_f64(6.0)));
256 assert!(mv[1].could_be_equal(S::from_f64(15.0)));
257
258 let mtm = mt.mul_mat(&m); assert!(mtm[(0, 0)].could_be_equal(S::from_f64(1.0 + 16.0)));
260 }
261 #[test]
262 fn transpose_and_mul() {
263 for_all_scalars!(check_transpose_and_mul);
264 }
265}