russell_tensor/
as_matrix_9x9.rs

1use russell_lab::Matrix;
2
3/// Defines a trait to handle 9x9 matrices
4///
5/// # Examples
6///
7/// ```
8/// use russell_lab::Matrix;
9/// use russell_tensor::{AsMatrix9x9, MN_TO_IJKL};
10///
11/// fn diagonal(mat: &dyn AsMatrix9x9) -> Vec<f64> {
12///     let mut res = vec![0.0; 9];
13///     for i in 0..9 {
14///         res[i] = mat.at(i, i);
15///     }
16///     res
17/// }
18///
19/// // heap-allocated matrix (vector of vectors)
20/// // ┌                                              ┐
21/// // │ 1111 1122 1133 1112 1123 1113 1121 1132 1131 │
22/// // │ 2211 2222 2233 2212 2223 2213 2221 2232 2231 │
23/// // │ 3311 3322 3333 3312 3323 3313 3321 3332 3331 │
24/// // │ 1211 1222 1233 1212 1223 1213 1221 1232 1231 │
25/// // │ 2311 2322 2333 2312 2323 2313 2321 2332 2331 │
26/// // │ 1311 1322 1333 1312 1323 1313 1321 1332 1331 │
27/// // │ 2111 2122 2133 2112 2123 2113 2121 2132 2131 │
28/// // │ 3211 3222 3233 3212 3223 3213 3221 3232 3231 │
29/// // │ 3111 3122 3133 3112 3123 3113 3121 3132 3131 │
30/// // └                                              ┘
31/// let mut mat = vec![vec![0.0; 9]; 9];
32/// for m in 0..9 {
33///     for n in 0..9 {
34///         let (i, j, k, l) = MN_TO_IJKL[m][n];
35///         mat[m][n] = (1000 * (i + 1) + 100 * (j + 1) + 10 * (k + 1) + (l + 1)) as f64;
36///     }
37/// }
38/// assert_eq!(
39///     diagonal(&mat),
40///     &[1111.0, 2222.0, 3333.0, 1212.0, 2323.0, 1313.0, 2121.0, 3232.0, 3131.0]
41/// );
42/// ```
43pub trait AsMatrix9x9 {
44    /// Returns the value at (i,j) indices
45    ///
46    /// # Panics
47    ///
48    /// This function panics if the indices are out of range.
49    fn at(&self, i: usize, j: usize) -> f64;
50}
51
52/// Defines a heap-allocated 9x9 matrix (vector of vectors)
53///
54/// # Panics
55///
56/// * The array must be 9x9; otherwise a panic will occur.
57/// * The methods may panic if the array is empty.
58impl AsMatrix9x9 for Vec<Vec<f64>> {
59    fn at(&self, i: usize, j: usize) -> f64 {
60        self[i][j]
61    }
62}
63
64/// Defines a heap-allocated 9x9 matrix (slice of slices)
65///
66/// # Panics
67///
68/// * The array must be 9x9; otherwise a panic will occur.
69/// * The methods may panic if the array is empty.
70impl AsMatrix9x9 for &[&[f64]] {
71    fn at(&self, i: usize, j: usize) -> f64 {
72        self[i][j]
73    }
74}
75
76/// Defines a stack-allocated (fixed-size) 9x9 matrix
77///
78/// # Panics
79///
80/// * The array must be 9x9; otherwise a panic will occur.
81/// * The methods may panic if the array is empty.
82impl AsMatrix9x9 for [[f64; 9]; 9] {
83    fn at(&self, i: usize, j: usize) -> f64 {
84        self[i][j]
85    }
86}
87
88/// Defines a 9x9 matrix from russell_lab::Matrix
89///
90/// # Panics
91///
92/// * The matrix must be 9x9; otherwise a panic will occur.
93/// * The methods may panic if the array is empty.
94impl AsMatrix9x9 for Matrix {
95    fn at(&self, i: usize, j: usize) -> f64 {
96        self.get(i, j)
97    }
98}
99
100////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
101
102#[cfg(test)]
103mod tests {
104    use super::AsMatrix9x9;
105    use crate::MN_TO_IJKL;
106    use russell_lab::Matrix;
107
108    fn diagonal(mat: &dyn AsMatrix9x9) -> Vec<f64> {
109        let mut res = vec![0.0; 9];
110        for i in 0..9 {
111            res[i] = mat.at(i, i);
112        }
113        res
114    }
115
116    #[test]
117    fn as_matrix_9x9_works() {
118        // heap-allocated matrix (vector of vectors)
119        // ┌                                              ┐
120        // │ 1111 1122 1133 1112 1123 1113 1121 1132 1131 │
121        // │ 2211 2222 2233 2212 2223 2213 2221 2232 2231 │
122        // │ 3311 3322 3333 3312 3323 3313 3321 3332 3331 │
123        // │ 1211 1222 1233 1212 1223 1213 1221 1232 1231 │
124        // │ 2311 2322 2333 2312 2323 2313 2321 2332 2331 │
125        // │ 1311 1322 1333 1312 1323 1313 1321 1332 1331 │
126        // │ 2111 2122 2133 2112 2123 2113 2121 2132 2131 │
127        // │ 3211 3222 3233 3212 3223 3213 3221 3232 3231 │
128        // │ 3111 3122 3133 3112 3123 3113 3121 3132 3131 │
129        // └                                              ┘
130        let mut mat = vec![vec![0.0; 9]; 9];
131        for m in 0..9 {
132            for n in 0..9 {
133                let (i, j, k, l) = MN_TO_IJKL[m][n];
134                mat[m][n] = (1000 * (i + 1) + 100 * (j + 1) + 10 * (k + 1) + (l + 1)) as f64;
135            }
136        }
137        assert_eq!(
138            diagonal(&mat),
139            &[1111.0, 2222.0, 3333.0, 1212.0, 2323.0, 1313.0, 2121.0, 3232.0, 3131.0]
140        );
141
142        // heap-allocated 2D array (aka slice of slices)
143        let ___ = 0.0;
144        let mat: &[&[f64]] = &[
145            &[1.0, ___, ___, ___, ___, ___, ___, ___, ___],
146            &[___, 2.0, ___, ___, ___, ___, ___, ___, ___],
147            &[___, ___, 3.0, ___, ___, ___, ___, ___, ___],
148            &[___, ___, ___, 4.0, ___, ___, ___, ___, ___],
149            &[___, ___, ___, ___, 5.0, ___, ___, ___, ___],
150            &[___, ___, ___, ___, ___, 6.0, ___, ___, ___],
151            &[___, ___, ___, ___, ___, ___, 7.0, ___, ___],
152            &[___, ___, ___, ___, ___, ___, ___, 8.0, ___],
153            &[___, ___, ___, ___, ___, ___, ___, ___, 9.0],
154        ];
155        assert_eq!(diagonal(&mat), &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]);
156
157        // stack-allocated (fixed-size) 2D array
158        let mat = [
159            [1.0, ___, ___, ___, ___, ___, ___, ___, ___],
160            [___, 2.0, ___, ___, ___, ___, ___, ___, ___],
161            [___, ___, 3.0, ___, ___, ___, ___, ___, ___],
162            [___, ___, ___, 4.0, ___, ___, ___, ___, ___],
163            [___, ___, ___, ___, 5.0, ___, ___, ___, ___],
164            [___, ___, ___, ___, ___, 6.0, ___, ___, ___],
165            [___, ___, ___, ___, ___, ___, 7.0, ___, ___],
166            [___, ___, ___, ___, ___, ___, ___, 8.0, ___],
167            [___, ___, ___, ___, ___, ___, ___, ___, 9.0],
168        ];
169        assert_eq!(diagonal(&mat), &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]);
170
171        // russell_lab::Matrix
172        let diag = [10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0];
173        let mat = Matrix::diagonal(&diag);
174        assert_eq!(diagonal(&mat), &diag);
175    }
176}