1use std::f64::EPSILON;
2
3#[derive(Debug, PartialEq)]
5pub struct Matrix2D {
6 pub rows: usize,
8 pub cols: usize,
10 pub data: Vec<Vec<f64>>,
12}
13
14impl Clone for Matrix2D {
15 fn clone(&self) -> Self {
16 let mut cloned_data = Vec::with_capacity(self.rows);
17
18 for row in &self.data {
19 let cloned_row: Vec<f64> = row.clone();
20 cloned_data.push(cloned_row);
21 }
22
23 Matrix2D {
24 rows: self.rows,
25 cols: self.cols,
26 data: cloned_data,
27 }
28 }
29}
30#[allow(dead_code)]
31impl Matrix2D {
32 pub fn new(data: Vec<Vec<f64>>) -> Matrix2D {
49 let rows = data.len();
51 assert!(rows > 0, "Matrix must have at least one row");
52
53 let cols = data[0].len();
54 assert!(cols > 0, "Matrix must have at least one column");
55
56 for row in &data {
57 assert_eq!(row.len(), cols, "All rows must have the same number of columns");
58 }
59
60 Matrix2D { rows, cols, data }
61 }
62
63 pub fn print(&self) {
65 for row in &self.data {
66 for &elem in row {
67 print!("{} ", elem);
68 }
69 println!();
70 }
71 }
72 pub fn add(&self, other: &Matrix2D) -> Option<Matrix2D> {
82 if self.rows == other.rows && self.cols == other.cols {
83 let mut result_data = Vec::with_capacity(self.rows);
84 for i in 0..self.rows {
85 let mut row = Vec::with_capacity(self.cols);
86 for j in 0..self.cols {
87 row.push(self.data[i][j] + other.data[i][j]);
88 }
89 result_data.push(row);
90 }
91 Some(Matrix2D {
92 rows: self.rows,
93 cols: self.cols,
94 data: result_data,
95 })
96 } else {
97 None
98 }
99 }
100
101 pub fn subtract(&self, other: &Matrix2D) -> Option<Matrix2D> {
111 if self.rows == other.rows && self.cols == other.cols {
112 let mut result_data = Vec::with_capacity(self.rows);
113 for i in 0..self.rows {
114 let mut row = Vec::with_capacity(self.cols);
115 for j in 0..self.cols {
116 row.push(self.data[i][j] - other.data[i][j]);
117 }
118 result_data.push(row);
119 }
120 Some(Matrix2D {
121 rows: self.rows,
122 cols: self.cols,
123 data: result_data,
124 })
125 } else {
126 None
127 }
128 }
129
130 pub fn multiply(&self, other: &Matrix2D) -> Matrix2D {
144 if self.cols != other.rows {
146 panic!("Matrix dimensions do not match for multiplication.")
147 }
148
149 let mut result_data = Vec::with_capacity(self.rows);
150 for i in 0..self.rows {
151 let mut row = Vec::with_capacity(other.cols);
152 for j in 0..other.cols {
153 let mut sum = 0.0;
154 for k in 0..self.cols {
155 sum += self.data[i][k] * other.data[k][j];
156 }
157 row.push(sum);
158 }
159 result_data.push(row);
160 }
161
162 Matrix2D {
163 rows: self.rows,
164 cols: other.cols,
165 data: result_data,
166 }
167 }
168
169 pub fn transpose(&self) -> Matrix2D {
175 let mut result_data = Vec::with_capacity(self.cols);
176 for j in 0..self.cols {
177 let mut row = Vec::with_capacity(self.rows);
178 for i in 0..self.rows {
179 row.push(self.data[i][j]);
180 }
181 result_data.push(row);
182 }
183
184 Matrix2D {
185 rows: self.cols,
186 cols: self.rows,
187 data: result_data,
188 }
189 }
190
191 pub fn determinant(&self) -> Option<f64> {
193 if self.rows != self.cols {
195 return None;
196 }
197
198 self.calculate_determinant(&self.data)
200 }
201
202 fn calculate_determinant(&self, matrix: &Vec<Vec<f64>>) -> Option<f64> {
204 match self.rows {
205 1 => Some(matrix[0][0]), 2 => Some(matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0]), _ => {
208 let mut det = 0.0;
209
210 for col in 0..self.cols {
212 let submatrix_data: Vec<Vec<f64>> = matrix
214 .iter()
215 .enumerate()
216 .filter(|&(i, _)| i != 0)
217 .map(|(_, row)| row.iter().enumerate().filter(|&(j, _)| j != col).map(|(_, &val)| val).collect())
218 .collect();
219
220 let submatrix = Matrix2D {
221 rows: self.rows - 1,
222 cols: self.cols - 1,
223 data: submatrix_data,
224 };
225
226 let cofactor = if col % 2 == 0 { 1.0 } else { -1.0 };
227
228 match self.calculate_determinant(&submatrix.data) {
229 Some(sub_det) => det += cofactor * matrix[0][col] * sub_det,
230 None => return None,
231 }
232 }
233
234 Some(det)
235 }
236 }
237 }
238 pub fn inverse(&self) -> Option<Matrix2D> {
240 if self.rows != self.cols {
242 return None;
243 }
244
245 let det_a = self.determinant();
247 if det_a.unwrap() == 0.0 {
248 return None; }
250
251 let adj_a = self.adjoint();
253
254 let inv_det = 1.0 / det_a.unwrap();
256 let mut inv_a_data = Vec::with_capacity(self.rows);
257 for i in 0..self.rows {
258 let mut row = Vec::with_capacity(self.cols);
259 for j in 0..self.cols {
260 row.push(inv_det * adj_a.data[i][j]);
261 }
262 inv_a_data.push(row);
263 }
264
265 Some(Matrix2D {
266 rows: self.rows,
267 cols: self.cols,
268 data: inv_a_data,
269 })
270 }
271 fn adjoint(&self) -> Matrix2D {
273 let mut adj_a_data = Vec::with_capacity(self.rows);
275 for i in 0..self.rows {
276 let mut row = Vec::with_capacity(self.cols);
277 for j in 0..self.cols {
278 let submatrix_data: Vec<Vec<f64>> = self.data
280 .iter()
281 .enumerate()
282 .filter(|&(row_idx, _)| row_idx != i)
283 .map(|(_, row)| row.iter().enumerate().filter(|&(col_idx, _)| col_idx != j).map(|(_, &val)| val).collect())
284 .collect();
285
286 let submatrix = Matrix2D {
287 rows: self.rows - 1,
288 cols: self.cols - 1,
289 data: submatrix_data,
290 };
291
292 let cofactor = if (i + j) % 2 == 0 { 1.0 } else { -1.0 };
293 row.push(cofactor * self.calculate_determinant(&submatrix.data).unwrap());
294 }
295 adj_a_data.push(row);
296 }
297
298 Matrix2D {
299 rows: self.rows,
300 cols: self.cols,
301 data: adj_a_data,
302 }
303 }
304
305 pub fn eigenvalue_eigenvector(&self) -> Option<(Vec<f64>, Vec<Vec<f64>>)> {
307 if self.rows != self.cols {
309 return None;
310 }
311
312 let a_minus_lambda_i: Matrix2D = self.subtract_identity();
314
315 let eigenvalues = match a_minus_lambda_i.determinant() {
317 Some(det) => self.find_eigenvalues(det),
318 None => return None,
319 };
320
321 let mut eigenvectors: Vec<Vec<f64>> = Vec::with_capacity(eigenvalues.len());
323 for &eigenvalue in &eigenvalues {
324 let eigenvector = self.solve_eigenvector(eigenvalue);
325 eigenvectors.push(eigenvector);
326 }
327
328 Some((eigenvalues, eigenvectors))
329 }
330
331 fn subtract_identity(&self) -> Matrix2D {
333 let mut result_data = Vec::with_capacity(self.rows);
334 for i in 0..self.rows {
335 let mut row = Vec::with_capacity(self.cols);
336 for j in 0..self.cols {
337 let element = if i == j {
338 self.data[i][j] - 1.0 } else {
340 self.data[i][j]
341 };
342 row.push(element);
343 }
344 result_data.push(row);
345 }
346
347 Matrix2D {
348 rows: self.rows,
349 cols: self.cols,
350 data: result_data,
351 }
352 }
353
354 fn find_eigenvalues(&self, _det_a_minus_lambda_i: f64) -> Vec<f64> {
356 let mut eigenvalues = Vec::with_capacity(self.rows);
357 for i in 0..self.rows {
358 eigenvalues.push(self.data[i][i]);
359 }
360 eigenvalues
361 }
362
363 fn solve_eigenvector(&self, eigenvalue: f64) -> Vec<f64> {
365 let mut augmented_matrix_data = Vec::with_capacity(self.rows);
366 for i in 0..self.rows {
367 let mut row = Vec::with_capacity(self.cols + 1);
368 for j in 0..self.cols {
369 row.push(self.data[i][j] - eigenvalue * if i == j { 1.0 } else { 0.0 });
370 }
371 row.push(0.0); augmented_matrix_data.push(row);
373 }
374
375 let mut augmented_matrix = Matrix2D {
376 rows: self.rows,
377 cols: self.cols + 1,
378 data: augmented_matrix_data,
379 };
380
381 let mut solution = Vec::with_capacity(self.rows);
383 for i in 0..self.rows {
384 let mut pivot_row = i;
385 for j in i + 1..self.rows {
386 if augmented_matrix.data[j][i].abs() > augmented_matrix.data[pivot_row][i].abs() {
387 pivot_row = j;
388 }
389 }
390
391 if augmented_matrix.data[pivot_row][i].abs() < EPSILON {
392 return vec![];
393 }
394
395 augmented_matrix.swap_rows(i, pivot_row);
396
397 for j in i + 1..self.rows {
398 let factor = augmented_matrix.data[j][i] / augmented_matrix.data[i][i];
399 for k in i..self.cols + 1 {
400 augmented_matrix.data[j][k] -= factor * augmented_matrix.data[i][k];
401 }
402 }
403 }
404
405 for i in (0..self.rows).rev() {
407 let mut sum = 0.0;
408 for j in i + 1..self.cols {
409 sum += augmented_matrix.data[i][j] * solution[j - i - 1];
410 }
411 solution.push((augmented_matrix.data[i][self.cols] - sum) / augmented_matrix.data[i][i]);
412 }
413
414 let norm = solution.iter().fold(0.0, |acc, &x| acc + x.powi(2)).sqrt();
416 solution.iter().map(|&x| x / norm).collect()
417 }
418
419 fn swap_rows(&self, i: usize, j: usize) {
421 let mut data_copy = self.data.clone();
422 data_copy.swap(i, j);
423 Matrix2D {
424 rows: self.rows,
425 cols: self.cols,
426 data: data_copy,
427 };
428 }
429
430 pub fn svd(&self) -> (Matrix2D, Matrix2D, Matrix2D) {
435 let mut u = self.clone();
436 let mut vt = self.clone();
437
438 let mut s = Matrix2D::zeros(self.cols, self.cols);
439
440 let mut ut = Matrix2D::eye(self.cols);
442 let mut v = Matrix2D::eye(self.cols);
443
444 let max_iter = 100;
446
447 for _ in 0..max_iter {
448 let uu = u.transpose().multiply(&u);
450 let (u_eigenvalues, u_eigenvectors) = uu.eigen();
451 let u_sort_indices = Matrix2D::argsort(&u_eigenvalues);
452
453 u = u.multiply_by_vector(&u_eigenvectors.column(u_sort_indices[0]));
454
455 let vv = vt.transpose().multiply(&vt);
457 let (v_eigenvalues, v_eigenvectors) = vv.eigen();
458 let v_sort_indices = Matrix2D::argsort(&v_eigenvalues);
459
460 vt = vt.multiply_by_vector(&v_eigenvectors.column(v_sort_indices[0])).transpose();
461
462 s.data = u.transpose().multiply(&self.multiply(&vt)).data;
464
465 ut = ut.multiply(&u);
467 v = v.multiply(&vt);
468 }
469
470 for i in 0..self.cols {
472 s.data[i][i] = s.data[i][i].sqrt();
473 }
474
475 (ut, s, v)
476 }
477 pub fn multiply_by_vector(&self, vector: &Vec<f64>) -> Matrix2D {
479 let mut result = Matrix2D::zeros(self.rows, 1);
480
481 for i in 0..self.rows {
482 for j in 0..1 {
483 for k in 0..self.cols {
484 result.data[i][j] += self.data[i][k] * vector[k];
485 }
486 }
487 }
488
489 result
490 }
491 pub fn eye(size: usize) -> Matrix2D {
493 let mut result = Matrix2D::zeros(size, size);
494 for i in 0..size {
495 result.data[i][i] = 1.0;
496 }
497 result
498 }
499
500 pub fn zeros(rows: usize, cols: usize) -> Matrix2D {
502 Matrix2D {
503 rows,
504 cols,
505 data: vec![vec![0.0; cols]; rows],
506 }
507 }
508 pub fn eigen(&self) -> (Vec<f64>, Matrix2D) {
510 let n = self.rows;
513 let mut a = self.clone();
514 let mut v = Matrix2D::eye(n);
515
516 let mut d = Vec::with_capacity(n);
517 for i in 0..n {
518 d.push(a.data[i][i]);
519 }
520
521 let max_iter = 100;
523
524 for _ in 0..max_iter {
525 let mut sm = 0.0;
526 for i in 0..n - 1 {
527 for j in i + 1..n {
528 sm += f64::abs(a.data[i][j]);
529 }
530 }
531
532 if sm == 0.0 {
533 return (d, v);
535 }
536
537 let tresh = if a.data[0][0] < a.data[0][n - 1] {
538 0.2 * sm / (n as f64)
539 } else {
540 0.2 * sm / (n as f64)
541 };
542
543 for ip in 0..n - 1 {
544 for iq in ip + 1..n {
545 let g = 100.0 * f64::abs(a.data[ip][iq]);
546
547 if ip > 0 && ip < n - 1 {
548 let mut _h = 0.5 * (a.data[ip][ip] - a.data[iq][iq]);
549 let t = f64::sqrt(_h * _h + g * g);
550 _h = _h / t;
551 let c = f64::sqrt(0.5 + 0.5 * _h);
552 let s = -0.5 * _h / c;
553 _h = 0.5 * (g / c) * (_h / c);
554 let mut b = Matrix2D::eye(n);
555 b.data[ip][ip] = c;
556 b.data[iq][iq] = c;
557 b.data[ip][iq] = s;
558 b.data[iq][ip] = -s;
559
560 let at = b.transpose().multiply(&a).multiply(&b);
561 a = at.clone();
562 let vt = b.multiply(&v);
563 v = vt.clone();
564 }
565
566 if f64::abs(a.data[ip][iq]) > tresh {
567 let _h = a.data[ip][ip] - a.data[iq][iq];
568 let t = if _h.abs() + g == _h.abs() {
569 a.data[ip][iq] / _h
570 } else {
571 let theta = 0.5 * _h / (a.data[ip][iq]);
572 1.0 / (f64::abs(theta) + f64::sqrt(1.0 + theta * theta))
573 };
574
575 let c = 1.0 / f64::sqrt(1.0 + t * t);
576 let s = t * c;
577
578 let _z = 1.0 / f64::sqrt(1.0 + t * t);
579 let mut b = Matrix2D::eye(n);
580 b.data[ip][ip] = c;
581 b.data[iq][iq] = c;
582 b.data[ip][iq] = s;
583 b.data[iq][ip] = -s;
584
585 let at = b.transpose().multiply(&a).multiply(&b);
586 a = at.clone();
587 let vt = b.multiply(&v);
588 v = vt.clone();
589 }
590 }
591 }
592 }
593
594 (d, v)
595 }
596
597 pub fn argsort(vector: &Vec<f64>) -> Vec<usize> {
599 let mut indices: Vec<usize> = (0..vector.len()).collect();
600 indices.sort_by(|&a, &b| vector[a].partial_cmp(&vector[b]).unwrap());
601 indices
602 }
603 pub fn column(&self, col_index: usize) -> Vec<f64> {
605 assert!(col_index < self.cols, "Column index out of bounds.");
606 self.data.iter().map(|row| row[col_index]).collect()
607 }
608
609}