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}