tinymatrix/lib.rs
1#[derive(Debug, Clone)]
2pub struct Matrix {
3 rows: usize,
4 cols: usize,
5 data: Vec<f64>,
6}
7
8impl Matrix {
9
10 /// Returns a new Matrix given the rows and columns. The matrix is full of 0's
11 /// # Arguments
12 /// * `rows` - The amount of rows of the matrix
13 /// * `cols` - The amount of columns of the matrix
14 /// # Examples
15 /// ```
16 /// use tinymatrix::Matrix;
17 /// let matrix = Matrix::new(2, 2);
18 /// ```
19 pub fn new(rows: usize, cols: usize) -> Self {
20 Matrix {
21 rows,
22 cols,
23 data: vec![0.0; rows * cols],
24 }
25 }
26
27 /// Returns a new Matrix given the rows, columns and all the data inside the matrix.
28 /// # Arguments
29 /// * `rows` - The amount of rows of the matrix
30 /// * `cols` - The amount of columns of the matrix
31 /// * `values` - The data that the Matrix is created from (needs to be an 1D Vector)
32 /// # Examples
33 /// ```
34 /// use tinymatrix::Matrix;
35 /// let vector = vec![
36 /// 1.0, 2.0,
37 /// 3.0, 4.0
38 /// ];
39 /// let matrix = Matrix::from_vector(2, 2, vector);
40 /// ```
41 pub fn from_vector(rows: usize, cols: usize, values: Vec<f64>) -> Self {
42 if rows * cols != values.len() {
43 panic!("The vector input needs to match with the amount of columns and rows!");
44 } else {
45 Matrix {
46 rows,
47 cols,
48 data: values,
49 }
50 }
51 }
52
53 /// Returns the data given the coordinates (row and column)
54 /// # Arguments
55 /// * `row` - The row where the data is located
56 /// * `col` - The column where the data is located
57 /// # Examples
58 /// ```
59 /// use tinymatrix::Matrix;
60 /// let vector = vec![
61 /// 1.0, 2.0,
62 /// 3.0, 4.0
63 /// ];
64 /// let matrix = Matrix::from_vector(2, 2, vector);
65 /// matrix.get(0, 0);
66 /// ```
67 /// # Returns
68 /// The value on that coordinate
69 pub fn get(&self, row: usize, col: usize) -> f64 {
70 self.data[row * self.cols + col]
71 }
72
73 /// Sets a value given the coordinates (row and column) and the value
74 /// # Arguments
75 /// * `row` - The row where the data is located
76 /// * `col` - The column where the data is located
77 /// * `value` - The value that is being set.
78 /// # Examples
79 /// ```
80 /// use tinymatrix::Matrix;
81 /// let vector = vec![
82 /// 1.0, 2.0,
83 /// 3.0, 4.0
84 /// ];
85 /// let mut matrix = Matrix::from_vector(2, 2, vector);
86 /// matrix.set(0, 0, 1.5);
87 /// ```
88 pub fn set(&mut self, row: usize, col: usize, value: f64) {
89 self.data[row * self.cols + col] = value;
90 }
91
92 /// Returns if the matrix is squared (e.g the amount of columns is equal to the amount of rows)
93 /// # Examples
94 /// ```
95 /// use tinymatrix::Matrix;
96 /// let vector = vec![
97 /// 1.0, 2.0,
98 /// 3.0, 4.0
99 /// ];
100 /// let matrix = Matrix::from_vector(2, 2, vector);
101 /// matrix.is_squared(); // Should return true
102 /// ```
103 /// # Returns
104 /// A boolean based on the result.
105 pub fn is_squared(&self) -> bool {
106 if self.cols == self.rows {
107 return true;
108 } else {
109 return false;
110 }
111 }
112 /// Returns the main diagonal, all items above and below the main diagonal of a Matrix (only if it's squared)
113 /// # Examples
114 /// ```
115 /// use tinymatrix::Matrix;
116 /// let vector = vec![
117 /// 1.0, 2.0,
118 /// 3.0, 4.0
119 /// ];
120 /// let matrix = Matrix::from_vector(2, 2, vector);
121 /// let (main_diagonal, above_diagonal, below_diagonal) = matrix.main_diagonal();
122 /// ```
123 /// # Returns
124 /// The main diagonal, all numbers above the main diagoan and all numbers below the main diagonal. All diagonals are Vec<f64> (Vectors)
125 pub fn main_diagonal(&self) -> (Vec<f64>, Vec<f64>, Vec<f64>) {
126 if self.is_squared() {
127 let mut m_diagonal: Vec<f64> = Vec::new();
128 let mut a_diagonal: Vec<f64> = Vec::new();
129 let mut b_diagonal: Vec<f64> = Vec::new();
130
131 for i in 0..self.rows {
132 for j in 0..self.cols {
133 if i == j {
134 m_diagonal.push(self.get(i, i));
135 } else if i > j {
136 b_diagonal.push(self.get(i, j));
137 } else {
138 a_diagonal.push(self.get(i, j));
139 }
140 }
141 }
142 (m_diagonal, a_diagonal, b_diagonal)
143 } else {
144 panic!("The matrix needs to be squared!")
145 }
146 }
147
148 /// Returns if the matrix is upper triangular (e.g the matrix is squared and all numbers below the main diagonal are zero)
149 /// # Examples
150 /// ```
151 /// use tinymatrix::Matrix;
152 /// let vector = vec![
153 /// 1.0, 2.0,
154 /// 0.0, 4.0
155 /// ];
156 /// let matrix = Matrix::from_vector(2, 2, vector);
157 /// matrix.is_u_triangular(); // Should return true
158 /// ```
159 /// # Returns
160 /// A boolean based on the result.
161 pub fn is_u_triangular(&self) -> bool {
162 if !self.is_squared() {
163 return false;
164 } else {
165 let (_, _, b_diagonal) = self.main_diagonal();
166 let mut z = 0;
167 for i in 0..b_diagonal.len() {
168 if b_diagonal[i] == 0.0 {
169 z += 1;
170 }
171 }
172 if z == b_diagonal.len() {
173 return true;
174 } else {
175 return false;
176 }
177 }
178 }
179
180 /// Returns if the matrix is lower triangular (e.g the matrix is squared and all numbers above the main diagonal are zero)
181 /// # Examples
182 /// ```
183 /// use tinymatrix::Matrix;
184 /// let vector = vec![
185 /// 1.0, 0.0,
186 /// 1.0, 4.0
187 /// ];
188 /// let matrix = Matrix::from_vector(2, 2, vector);
189 /// matrix.is_l_triangular(); // Should return true
190 /// ```
191 /// # Returns
192 /// A boolean based on the result.
193 pub fn is_l_triangular(&self) -> bool {
194 if !self.is_squared() {
195 return false;
196 } else {
197 let (_, a_diagonal, _) = self.main_diagonal();
198 let mut z = 0;
199 for i in 0..a_diagonal.len() {
200 if a_diagonal[i] == 0.0 {
201 z += 1;
202 }
203 }
204 if z == a_diagonal.len() {
205 return true;
206 } else {
207 return false;
208 }
209 }
210 }
211
212 /// Returns a new Matrix when given two matrices and both matrices have the same number of rows, join all rows
213 /// # Arguments
214 /// * `other` - The matrix that is concatenating all rows.
215 /// # Examples
216 /// ```
217 /// use tinymatrix::Matrix;
218 /// let vector1 = vec![
219 /// 1.0, 2.0,
220 /// 3.0, 4.0
221 /// ];
222 /// let vector2 = vec![
223 /// 5.0, 6.0,
224 /// 7.0, 8.0
225 /// ];
226 /// let matrix1 = Matrix::from_vector(2, 2, vector1);
227 /// let matrix2 = Matrix::from_vector(2, 2, vector2);
228 /// let joined_rows = matrix1.concat_rows(&matrix2);
229 /// ```
230 /// # Returns
231 /// A new matrix with all rows joint.
232 pub fn concat_rows(&self, other: &Self) -> Self {
233 if self.rows != other.rows {
234 panic!("Both matrices need to have the same amount of rows!");
235 } else {
236 let mut result: Vec<f64> = Vec::with_capacity(self.data.len() + other.data.len());
237
238 for i in 0..self.rows {
239 let s_index1 = i * self.cols;
240 let e_index1 = s_index1 + self.cols;
241 result.extend_from_slice(&self.data[s_index1..e_index1]);
242
243 let s_index2 = i * other.cols;
244 let e_index2 = s_index2 + other.cols;
245 result.extend_from_slice(&other.data[s_index2..e_index2]);
246 }
247
248 Matrix {
249 rows: self.rows,
250 cols: self.cols * 2,
251 data: result,
252 }
253 }
254 }
255
256 /// Returns a new Matrix when given two matrices and they have the same amount of columns, join all columns
257 /// # Arguments
258 /// * `other` - The matrix that is concatenating all columns.
259 /// # Examples
260 /// ```
261 /// use tinymatrix::Matrix;
262 /// let vector1 = vec![
263 /// 1.0, 2.0,
264 /// 3.0, 4.0
265 /// ];
266 /// let vector2 = vec![
267 /// 5.0, 6.0,
268 /// 7.0, 8.0
269 /// ];
270 /// let matrix1 = Matrix::from_vector(2, 2, vector1);
271 /// let matrix2 = Matrix::from_vector(2, 2, vector2);
272 /// let joined_rows = matrix1.concat_cols(&matrix2);
273 /// ```
274 /// # Returns
275 /// A new matrix with all columns joint.
276 pub fn concat_cols(&self, other: &Self) -> Self {
277 if self.cols != other.cols {
278 panic!("Both matrices needs to have the same amount of columns!");
279 } else {
280 let mut result: Vec<f64> = Vec::with_capacity(self.data.len() + other.data.len());
281
282 for i in 0..self.rows {
283 for j in 0..self.cols {
284 result.push(self.data[i * self.cols + j]);
285 }
286
287 for j in 0..other.cols {
288 result.push(other.data[i * other.cols + j]);
289 }
290 }
291
292 Matrix {
293 rows: self.rows,
294 cols: self.cols + other.cols,
295 data: result,
296 }
297 }
298 }
299
300 pub fn transpose(&self) -> Self {
301 let mut result = Matrix::new(self.cols, self.rows);
302 for i in 0..self.rows {
303 for j in 0..self.cols {
304 result.set(j, i, self.get(i, j));
305 }
306 }
307 result
308 }
309 /// Returns the identity matrix of a matrix.
310 /// # Examples
311 /// ```
312 /// use tinymatrix::Matrix;
313 /// let vector = vec![
314 /// 1.0, 2.0,
315 /// 3.0, 4.0
316 /// ];
317 /// let matrix = Matrix::from_vector(2, 2, vector);
318 /// let identity = matrix.identity();
319 /// ```
320 /// # Returns
321 /// A new matrix with all the main diagonal 1 and all the other elements zero.
322 pub fn identity(&self) -> Self {
323 let mut result = Matrix::new(self.rows, self.cols);
324 for i in 0..self.rows {
325 result.data[i * self.rows + i] = 1.0;
326 }
327 result
328 }
329
330 pub fn determinant(&self) -> Self {
331 unimplemented!("The determinant of a matrix");
332 }
333
334 pub fn lu_decomposition(&self) -> Self {
335 unimplemented!("The LU decomposition of a matrix");
336 }
337
338 /// Prints the matrix in a nice way. Useful for debugging.
339 /// # Examples
340 /// ```
341 /// use tinymatrix::Matrix;
342 /// let vector = vec![
343 /// 1.0, 2.0,
344 /// 3.0, 4.0
345 /// ];
346 /// let matrix = Matrix::from_vector(2, 2, vector);
347 /// matrix.print_matrix();
348 /// ```
349 pub fn print_matrix(&self) {
350 for i in 0..self.rows {
351 for j in 0..self.cols {
352 print!("{:.2} ", self.get(i, j))
353 }
354 println!();
355 }
356 println!();
357 }
358}
359
360impl std::ops::Mul<Matrix> for Matrix {
361 type Output = Matrix;
362 fn mul(self, other: Matrix) -> Self::Output {
363 if self.cols != other.rows {
364 panic!(
365 "The amount of columns needs to be equal to the amount of rows for multiplication!"
366 )
367 } else {
368 let mut result = Matrix::new(self.rows, other.cols);
369 for i in 0..self.rows {
370 for j in 0..other.cols {
371 let mut sum = 0.0;
372 for k in 0..self.cols {
373 sum += self.get(i, k) * other.get(k, j);
374 }
375 result.set(i, j, sum);
376 }
377 }
378 result
379 }
380 }
381}
382
383impl std::ops::Mul<i32> for Matrix {
384 type Output = Matrix;
385 fn mul(mut self, other: i32) -> Self::Output {
386 for i in self.data.iter_mut() {
387 *i *= other as f64;
388 }
389 self
390 }
391}
392
393impl std::ops::Div<i32> for Matrix {
394 type Output = Matrix;
395 fn div(mut self, other: i32) -> Self::Output {
396 for i in self.data.iter_mut() {
397 *i /= other as f64;
398 }
399 self
400 }
401}
402
403
404impl std::ops::Add<Matrix> for Matrix {
405 type Output = Matrix;
406
407 fn add(self, other: Matrix) -> Self::Output {
408 if self.cols != other.rows {
409 panic!(
410 "The amount of columns needs to be equal to the amount of rows for multiplication!"
411 )
412 } else {
413 Matrix {
414 rows: self.rows,
415 cols: self.cols,
416 data: self
417 .data
418 .iter()
419 .zip(other.data.iter())
420 .map(|(&a, &b)| a + b)
421 .collect(),
422 }
423 }
424 }
425}
426
427impl std::ops::Sub<Matrix> for Matrix {
428 type Output = Matrix;
429
430 fn sub(self, other: Matrix) -> Self::Output {
431 if self.cols != other.rows {
432 panic!(
433 "The amount of columns needs to be equal to the amount of rows for multiplication!"
434 )
435 } else {
436 Matrix {
437 rows: self.rows,
438 cols: self.cols,
439 data: self
440 .data
441 .iter()
442 .zip(other.data.iter())
443 .map(|(&a, &b)| a - b)
444 .collect(),
445 }
446 }
447 }
448}