1#![deny(
2 missing_docs,
3 missing_debug_implementations,
4 missing_copy_implementations,
5 trivial_casts,
6 trivial_numeric_casts,
7 unsafe_code,
8 unstable_features,
9 unused_import_braces,
10 unused_qualifications
11)]
12
13pub mod matrix_operations {
15 use core::ops::Add;
17 use core::ops::Mul;
18 use core::ops::Sub;
19
20 #[derive(Debug, Clone, PartialEq)]
22 pub struct Matrix<T> {
23 rows: u32,
24 columns: u32,
25 dimension: (u32, u32),
26 data: Vec<Vec<T>>,
27 }
28
29 impl<T> Matrix<T>
30 where
31 T: Mul<Output = T> + Add<Output = T> + Sub<Output = T> + Default + Clone,
32 {
33 pub fn from_data(data: Vec<Vec<T>>) -> Self {
35 let rows: u32 = data.len() as u32;
36 let columns: u32 = data.get(0).unwrap().len() as u32;
37
38 Matrix {
39 rows: rows,
40 columns: columns,
41 dimension: (rows.clone(), columns.clone()),
42 data: data,
43 }
44 }
45
46 pub fn from_constant(dimension: (u32, u32), constant: T) -> Self {
48 Matrix {
49 rows: dimension.0,
50 columns: dimension.1,
51 dimension: dimension,
52 data: Matrix::data_from_constant(dimension.0, dimension.1, constant),
53 }
54 }
55
56 pub fn diagonal_from_constant(dimension: (u32, u32), constant: T) -> Self {
58 let mut m: Matrix<T> = Matrix::default_from_dimension(dimension);
59 let min_dim: u32 = std::cmp::min(dimension.0, dimension.1);
60
61 for i in 0..min_dim {
62 m.data[i as usize][i as usize] = constant.clone();
63 }
64
65 return m;
66 }
67
68 pub fn default_diagonal(dimension: (u32, u32)) -> Self {
70 Self::diagonal_from_constant(dimension, T::default())
71 }
72
73 pub fn default_from_dimension(dimension: (u32, u32)) -> Self {
75 Matrix {
76 rows: dimension.0,
77 columns: dimension.1,
78 dimension: dimension,
79 data: Matrix::data_from_zeroes(dimension.0, dimension.1),
80 }
81 }
82 pub fn default_from_rows_and_columns(rows: u32, columns: u32) -> Self {
84 Matrix {
85 rows: rows,
86 columns: columns,
87 dimension: (rows, columns),
88 data: Matrix::data_from_zeroes(rows, columns),
89 }
90 }
91
92 fn data_from_zeroes(r: u32, c: u32) -> Vec<Vec<T>> {
93 return vec![vec![T::default(); c as usize]; r as usize];
94 }
95
96 fn data_from_constant(r: u32, c: u32, v: T) -> Vec<Vec<T>> {
97 return vec![vec![v; c as usize]; r as usize];
98 }
99
100 pub fn transpose(self) -> Matrix<T> {
102 let mut transposed_matrix: Matrix<T> =
103 Matrix::default_from_dimension((self.columns, self.rows));
104
105 for i in 0..self.rows {
106 let iu: usize = i as usize;
107 for j in 0..self.columns {
108 let ju: usize = j as usize;
109 transposed_matrix.data[ju][iu] = self.data[iu][ju].clone();
110 }
111 }
112
113 return transposed_matrix;
114 }
115 }
116
117 impl<T> Add for Matrix<T>
118 where
119 T: Mul<Output = T> + Add<Output = T> + Sub<Output = T> + Default + Clone,
120 {
121 type Output = Matrix<T>;
122
123 fn add(self, rhs: Self) -> Self::Output {
124 if self.dimension != rhs.dimension {
125 panic!("Matrices must have the same dimension to perform addition");
126 }
127
128 let mut resultant: Matrix<T> = Matrix::default_from_dimension(self.dimension);
129 for i in 0..self.rows {
130 let iu: usize = i as usize;
131 for j in 0..self.columns {
132 let ju: usize = j as usize;
133 resultant.data[iu][ju] = self.data[iu][ju].clone() + rhs.data[iu][ju].clone();
134 }
135 }
136
137 return resultant;
138 }
139 }
140
141 impl<T> Mul for Matrix<T>
142 where
143 T: Mul<Output = T> + Add<Output = T> + Sub<Output = T> + Default + Clone,
144 {
145 type Output = Matrix<T>;
146
147 fn mul(self, rhs: Self) -> Self::Output {
148 if self.columns != rhs.rows {
149 panic!("Incompatible dimensions for matrix multiplication.")
150 }
151
152 let mut resultant: Matrix<T> =
153 Matrix::<T>::default_from_rows_and_columns(self.rows, rhs.columns);
154
155 for i in 0..self.rows {
156 let iu: usize = i as usize;
157 for j in 0..rhs.columns {
158 let ju: usize = j as usize;
159 for k in 0..self.columns {
160 let ku: usize = k as usize;
161 resultant.data[iu][ju] = resultant.data[iu][ju].clone()
162 + self.data[iu][ku].clone() * rhs.data[ku][ju].clone();
163 }
164 }
165 }
166
167 return resultant;
168 }
169 }
170
171 impl<T> Sub for Matrix<T>
172 where
173 T: Mul<Output = T> + Add<Output = T> + Sub<Output = T> + Default + Clone,
174 {
175 type Output = Matrix<T>;
176
177 fn sub(self, rhs: Self) -> Self::Output {
178 if self.dimension != rhs.dimension {
179 panic!("Matrices must have the same dimension to perform subtraction");
180 }
181
182 let mut resultant: Matrix<T> = Matrix::default_from_dimension(self.dimension);
183 for i in 0..self.rows {
184 let iu: usize = i as usize;
185 for j in 0..self.columns {
186 let ju: usize = j as usize;
187 resultant.data[iu][ju] = self.data[iu][ju].clone() - rhs.data[iu][ju].clone();
188 }
189 }
190
191 return resultant;
192 }
193 }
194
195 impl<T> Default for Matrix<T>
196 where
197 T: Mul<Output = T> + Add<Output = T> + Sub<Output = T> + Default + Clone,
198 {
199 fn default() -> Self {
200 Self {
201 rows: 3,
202 columns: 3,
203 dimension: (3, 3),
204 data: Matrix::data_from_zeroes(3, 3),
205 }
206 }
207 }
208}
209
210#[cfg(test)]
211mod tests {
212 use super::matrix_operations::Matrix;
213
214 #[test]
215 fn test_addition() {
216 let mat_ones: Matrix<i32> = Matrix::from_constant((3, 3), 1);
217 assert_eq!(
218 mat_ones.clone() + mat_ones,
219 Matrix::from_constant((3, 3), 2)
220 );
221 }
222
223 #[test]
224 fn test_multiplication() {
225 let mat_tens: Matrix<i32> = Matrix::from_constant((5, 5), 10);
226 let mat_ones: Matrix<i32> = Matrix::from_constant((5, 5), 1);
227
228 let product: Matrix<i32> = mat_tens * mat_ones;
229
230 assert_eq!(product, Matrix::from_constant((5, 5), 50));
231 }
232
233 #[test]
234 fn test_subtraction() {
235 let mat_ones: Matrix<i32> = Matrix::from_constant((3, 3), 1);
236 assert_eq!(
237 mat_ones.clone() - mat_ones,
238 Matrix::default_from_dimension((3, 3))
239 );
240 }
241
242 #[test]
243 fn test_diagonal_matrix_initialization() {
244 let unit_matrix: Matrix<f32> = Matrix::diagonal_from_constant((5, 5), 1.0);
245 let mat_tens: Matrix<f32> = Matrix::from_constant((5, 5), 10.0);
246
247 assert_eq!(mat_tens.clone() * unit_matrix, mat_tens);
248 }
249}