mymatrix/
matrix.rs

1use std::{
2    fmt::Display,
3    ops::{Index, IndexMut},
4};
5
6use crate::{detail, Vector};
7
8use pyinrs::Fraction;
9
10/// Matrix with fractions as elements.
11#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
12pub struct Matrix {
13    rows: Vec<Vector>,
14}
15
16impl Matrix {
17    /// Create a new matrix object.
18    pub fn new() -> Self {
19        Self { rows: Vec::new() }
20    }
21
22    /// Create a row x col matrix with all identical elements.
23    pub fn create(row: usize, col: usize, value: Fraction) -> Self {
24        let mut rows = Vec::with_capacity(row);
25        for _ in 0..row {
26            rows.push(Vector::create(col, value));
27        }
28        Self { rows }
29    }
30
31    /// Create a row x col matrix with all 0 elements.
32    pub fn zeros(row: usize, col: usize) -> Self {
33        Self::create(row, col, 0.into())
34    }
35
36    /// Create a row x col matrix with all 1 elements.
37    pub fn ones(row: usize, col: usize) -> Self {
38        Self::create(row, col, 1.into())
39    }
40
41    /// Generate an n-order identity matrix.
42    pub fn identity(n: usize) -> Self {
43        let mut m = Self::zeros(n, n);
44        for i in 0..n {
45            m[i][i] = 1.into();
46        }
47        m
48    }
49
50    /// Return the number of rows in the matrix.
51    pub fn row_size(&self) -> usize {
52        self.rows.len()
53    }
54
55    /// Return the number of columns in the matrix.
56    pub fn col_size(&self) -> usize {
57        if self.row_size() == 0 {
58            0
59        } else {
60            self.rows[0].size()
61        }
62    }
63
64    /// Returns `true` if the matrix contains no elements.
65    pub fn is_empty(&self) -> bool {
66        self.rows.is_empty()
67    }
68
69    /// Returns `true` if the matrix is symmetric.
70    pub fn is_symmetric(&self) -> bool {
71        if self.row_size() != self.col_size() {
72            return false;
73        }
74
75        for r in 0..self.row_size() {
76            for c in 0..r {
77                if self.rows[r][c] != self.rows[c][r] {
78                    return false;
79                }
80            }
81        }
82
83        true
84    }
85
86    /// Check if the matrix is upper triangular matrix.
87    pub fn is_upper(&self) -> bool {
88        if self.row_size() != self.col_size() {
89            return false;
90        }
91
92        for r in 1..self.row_size() {
93            for c in 0..r {
94                if self[r][c] != 0.into() {
95                    return false;
96                }
97            }
98        }
99
100        true
101    }
102
103    /// Check if the matrix is lower triangular matrix.
104    pub fn is_lower(&self) -> bool {
105        if self.row_size() != self.col_size() {
106            return false;
107        }
108
109        for c in 1..self.col_size() {
110            for r in 0..c {
111                if self[r][c] != 0.into() {
112                    return false;
113                }
114            }
115        }
116
117        true
118    }
119
120    /// Check if the matrix is diagonal matrix.
121    pub fn is_diagonal(&self) -> bool {
122        self.is_lower() && self.is_upper()
123    }
124
125    /// Calculate the trace of the matrix.
126    pub fn trace(&self) -> Fraction {
127        detail::check_square(self);
128
129        let mut tr = Fraction::new();
130        for i in 0..self.row_size() {
131            tr += self[i][i];
132        }
133
134        tr
135    }
136
137    /// Returns the transpose of the matrix.
138    pub fn transpose(&self) -> Self {
139        let mut result = Self::zeros(self.col_size(), self.row_size());
140
141        for i in 0..self.row_size() {
142            for j in 0..self.col_size() {
143                result[j][i] = self[i][j];
144            }
145        }
146        result
147    }
148
149    /// Transform this matrix to general row echelon form.
150    pub fn row_echelon_form(&self) -> Self {
151        let mut m = self.clone();
152
153        // Gaussian elimination
154        for i in 0..m.row_size() {
155            let mut j: usize = 0;
156            while j < m.col_size() && m.rows[i][j] == 0.into() {
157                j += 1;
158            }
159            for k in i + 1..m.row_size() {
160                if j < m.col_size() && m.rows[i][j] != 0.into() {
161                    m.e_row_sum(k, i, -m.rows[k][j] / m.rows[i][j]);
162                }
163            }
164        }
165
166        // transform to the row echelon form. It's so elegant, I'm a genius haha.
167        m.rows.sort_by_key(|r| r.count_leading_zeros());
168
169        m
170    }
171
172    /// Transform this matrix to reduced row echelon form.
173    pub fn row_canonical_form(&self) -> Self {
174        let mut m = self.row_echelon_form();
175
176        let n = usize::min(m.row_size(), m.col_size());
177
178        // eliminate elements above the pivot
179        for c in 0..n {
180            for r in 0..c {
181                if m[c][c] != 0.into() {
182                    m.e_row_sum(r, c, -(m[r][c] / m[c][c]));
183                }
184            }
185        }
186
187        // make pivot equals 1
188        let mut i = 0;
189        while i < n && m[i][i] != 0.into() {
190            m.e_scalar_multiplication(i, Fraction::from(1) / m[i][i]);
191            i += 1;
192        }
193
194        m
195    }
196
197    /// Calculate the determinant of this matrix.
198    pub fn det(&self) -> Fraction {
199        detail::check_square(self);
200
201        let n = self.row_size();
202        let mut a = self.clone();
203
204        let mut det = Fraction::from(1);
205        for i in 0..n {
206            let mut pivot = i;
207            for j in i + 1..n {
208                if a[j][i].abs() > a[pivot][i].abs() {
209                    pivot = j;
210                }
211            }
212            if pivot != i {
213                a.e_row_swap(i, pivot);
214                det = -det;
215            }
216            if a[i][i] == 0.into() {
217                return Fraction::new();
218            }
219            det *= a[i][i];
220            for j in i + 1..n {
221                a.e_row_sum(j, i, -a[j][i] / a[i][i]);
222            }
223        }
224        det
225    }
226
227    /// Return the matrix that removed the i-th row and j-th column, 0 <= i, j < n.
228    pub fn submatrix(&self, i: usize, j: usize) -> Self {
229        let mut submatrix = Vec::with_capacity(self.row_size() - 1);
230        for r in 0..self.row_size() {
231            if r != i {
232                let mut row = Vec::with_capacity(self.col_size() - 1);
233                row.extend_from_slice(&self[r].elements[..j]);
234                row.extend_from_slice(&self[r].elements[j + 1..]);
235                submatrix.push(row);
236            }
237        }
238        Self::from(submatrix)
239    }
240
241    /// Return the minor matrix.
242    pub fn minor(&self) -> Self {
243        let mut m = Self::zeros(self.row_size(), self.col_size());
244        for r in 0..m.row_size() {
245            for c in 0..m.col_size() {
246                m[r][c] = self.submatrix(r, c).det();
247            }
248        }
249        m
250    }
251
252    /// Return the cofactor matrix.
253    pub fn cofactor(&self) -> Self {
254        let mut m = self.minor();
255        for r in 0..m.row_size() {
256            for c in 0..self.col_size() {
257                // a11 -> a00, r+c parity unchanged
258                if (r + c) & 1 == 1 {
259                    m[r][c] = -m[r][c];
260                }
261            }
262        }
263        m
264    }
265
266    /// Return the adjugate matrix.
267    pub fn adj(&self) -> Self {
268        self.cofactor().transpose()
269    }
270
271    /// Calculate the inverse of this matrix.
272    pub fn inv(&self) -> Option<Self> {
273        detail::check_square(self);
274
275        // inverse of empty matrix is empty matrix
276        if self.is_empty() {
277            return Some(Matrix::new());
278        }
279
280        // generate augmented matrix [A:E] and transform [A:E] to reduced row echelon form and split
281        let n = self.row_size();
282        let rref = self.clone().expand_col(Self::identity(n)).row_canonical_form().split_col(n);
283
284        // now, the original E is the inverse of A if rank = n
285        if !rref.0[n - 1].is_zero() {
286            Some(rref.1)
287        } else {
288            None
289        }
290    }
291
292    /// Calculate the rank of this matrix.
293    pub fn rank(&self) -> usize {
294        let zeros = self.row_echelon_form().rows.iter().filter(|row| row.is_zero()).count();
295        self.row_size() - zeros
296    }
297
298    /// LU decomposition, use Doolittle algorithm.
299    pub fn lu_decomposition(&self) -> (Self, Self) {
300        detail::check_square(self);
301
302        let n = self.row_size();
303
304        if self.is_upper() {
305            return (Matrix::zeros(n, n), self.clone());
306        } else if self.is_lower() {
307            return (self.clone(), Matrix::zeros(n, n));
308        }
309
310        let mut l = Self::identity(n);
311        let mut u = Self::zeros(n, n);
312
313        for i in 0..n {
314            for j in 0..(i + 1) {
315                let mut sum = Fraction::new();
316                for k in 0..j {
317                    sum += l[j][k] * u[k][i];
318                }
319                u[j][i] = self[j][i] - sum;
320            }
321
322            for j in (i + 1)..n {
323                let mut sum = Fraction::new();
324                for k in 0..i {
325                    sum += l[j][k] * u[k][i];
326                }
327                l[j][i] = (self[j][i] - sum) / u[i][i];
328            }
329        }
330
331        (l, u)
332    }
333
334    /// Split this matrix by rows.
335    pub fn split_row(&self, n: usize) -> (Self, Self) {
336        detail::check_bounds(n, 0, self.row_size());
337
338        let (mut first, mut second) = (Self::new(), Self::new());
339        first.rows = self.rows[0..n].to_vec();
340        second.rows = self.rows[n..].to_vec();
341
342        (first, second)
343    }
344
345    /// Split this matrix by columns.
346    pub fn split_col(&self, n: usize) -> (Self, Self) {
347        detail::check_bounds(n, 0, self.col_size());
348
349        let (mut first, mut second) = (Self::new(), Self::new());
350        first.rows.resize(self.row_size(), Default::default());
351        second.rows.resize(self.row_size(), Default::default());
352        for r in 0..self.row_size() {
353            first.rows[r].elements = self.rows[r].elements[..n].to_vec();
354            second.rows[r].elements = self.rows[r].elements[n..].to_vec();
355        }
356
357        (first, second)
358    }
359
360    /// Expand this matrix by rows.
361    pub fn expand_row(&mut self, mut matrix: Self) -> &Self {
362        detail::check_size(self.col_size(), matrix.col_size());
363
364        self.rows.append(&mut matrix.rows);
365        self
366    }
367
368    /// Expand this matrix by columns.
369    pub fn expand_col(&mut self, mut matrix: Self) -> &Self {
370        detail::check_size(self.row_size(), matrix.row_size());
371
372        for i in 0..self.row_size() {
373            self.rows[i].elements.append(&mut matrix[i].elements);
374        }
375        self
376    }
377
378    /// Elementary Row Operations: Row Swap. (A[i] <=> A[j])
379    pub fn e_row_swap(&mut self, i: usize, j: usize) -> &Self {
380        self.rows.swap(i, j);
381        self
382    }
383
384    /// Elementary Row Operations: Scalar Multiplication. (A[i] *= k)
385    pub fn e_scalar_multiplication(&mut self, i: usize, k: Fraction) -> &Self {
386        self.rows[i] *= k;
387        self
388    }
389
390    /// Elementary Row Operations: Row Sum. (A[i] += A[j] * k)
391    pub fn e_row_sum(&mut self, i: usize, j: usize, k: Fraction) -> &Self {
392        let row = self[j].clone();
393        self.rows[i] += row * k;
394        self
395    }
396}
397
398impl<const R: usize, const C: usize> From<[[Fraction; C]; R]> for Matrix {
399    fn from(value: [[Fraction; C]; R]) -> Self {
400        let rows = Vec::from(value.map(Vector::from));
401        Self { rows }
402    }
403}
404
405impl<const R: usize, const C: usize> From<[[i32; C]; R]> for Matrix {
406    fn from(value: [[i32; C]; R]) -> Self {
407        let rows = Vec::from(value.map(Vector::from));
408        Self { rows }
409    }
410}
411
412impl From<Vec<Vec<Fraction>>> for Matrix {
413    fn from(value: Vec<Vec<Fraction>>) -> Self {
414        let rows = value.into_iter().map(Vector::from).collect();
415        Self { rows }
416    }
417}
418
419impl From<Vec<Vec<i32>>> for Matrix {
420    fn from(value: Vec<Vec<i32>>) -> Self {
421        let rows = value.into_iter().map(Vector::from).collect();
422        Self { rows }
423    }
424}
425
426impl Index<usize> for Matrix {
427    type Output = Vector;
428
429    fn index(&self, index: usize) -> &Self::Output {
430        &self.rows[index]
431    }
432}
433
434impl IndexMut<usize> for Matrix {
435    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
436        &mut self.rows[index]
437    }
438}
439
440impl Display for Matrix {
441    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
442        writeln!(f, "[")?;
443
444        // calc the max width of element
445        let mut width = 0;
446        for i in 0..self.row_size() {
447            for j in 0..self.col_size() {
448                width = width.max(format!("{}", self[i][j]).len());
449            }
450        }
451
452        // align right, fill with space
453        for i in 0..self.row_size() {
454            for j in 0..self.col_size() {
455                if j != 0 {
456                    write!(f, " ")?;
457                }
458                write!(f, "{:>width$}", format!("{}", self[i][j]))?;
459            }
460            writeln!(f)?;
461        }
462
463        write!(f, "]")
464    }
465}
466
467auto_ops::impl_op_ex!(+=|a: &mut Matrix, b: &Matrix| {
468    detail::check_size(a.row_size(), b.row_size());
469    detail::check_size(a.col_size(), b.col_size());
470
471    for r in 0..a.row_size() {
472        a[r] += &b[r];
473    }
474});
475
476auto_ops::impl_op_ex!(+|a: &Matrix, b: &Matrix| -> Matrix {
477    let mut a = a.clone();
478    a += b;
479    a
480});
481
482auto_ops::impl_op_ex!(-=|a: &mut Matrix, b: &Matrix| {
483    detail::check_size(a.row_size(), b.row_size());
484    detail::check_size(a.col_size(), b.col_size());
485
486    for r in 0..a.row_size() {
487        a[r] -= &b[r];
488    }
489});
490
491auto_ops::impl_op_ex!(-|a: &Matrix, b: &Matrix| -> Matrix {
492    let mut a = a.clone();
493    a -= b;
494    a
495});
496
497auto_ops::impl_op_ex!(*=|a: &mut Matrix, b: Fraction| {
498    for r in 0..a.row_size() {
499        a.rows[r] *= b;
500    }
501});
502
503auto_ops::impl_op_ex_commutative!(*|a: Matrix, b: Fraction| -> Matrix {
504    let mut a = a;
505    a *= b;
506    a
507});
508
509auto_ops::impl_op_ex!(*=|a: &mut Matrix, b: i32| {
510    for r in 0..a.row_size() {
511        a.rows[r] *= b;
512    }
513});
514
515auto_ops::impl_op_ex_commutative!(*|a: Matrix, b: i32| -> Matrix {
516    let mut a = a;
517    a *= b;
518    a
519});
520
521auto_ops::impl_op_ex!(*|a: &Matrix, b: &Matrix| -> Matrix {
522    detail::check_size(a.col_size(), b.row_size());
523
524    let mut result = Matrix::zeros(a.row_size(), b.col_size());
525    let rt = b.transpose();
526    for r in 0..a.row_size() {
527        for c in 0..b.col_size() {
528            result[r][c] = &a[r] * &rt[c];
529        }
530    }
531    result
532});
533
534impl IntoIterator for Matrix {
535    type Item = Vector;
536    type IntoIter = std::vec::IntoIter<Self::Item>;
537
538    fn into_iter(self) -> Self::IntoIter {
539        self.rows.into_iter()
540    }
541}