rs_math/matrix/
matrix_2d.rs

1use std::f64::EPSILON;
2
3/// 表示具有指定行数和列数的二维矩阵。
4#[derive(Debug, PartialEq)]
5pub struct Matrix2D {
6    /// 矩阵的行数。
7    pub rows: usize,
8    /// 矩阵的列数。
9    pub cols: usize,
10    /// 以二维向量形式存储在矩阵中的数据。
11    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    /// 创建一个新的矩阵。
33    ///
34    /// # 参数
35    ///
36    /// * `data` - 以二维向量形式表示的矩阵数据。
37    ///
38    /// # 返回
39    ///
40    /// 返回具有指定数据的 `Matrix2D` 实例。
41    ///
42    /// # 错误
43    ///
44    /// 如果输入数据不合法,将引发断言错误:
45    /// - 矩阵必须至少有一行
46    /// - 矩阵必须至少有一列
47    /// - 所有行必须具有相同的列数
48    pub fn new(data: Vec<Vec<f64>>) -> Matrix2D {
49        // 检查输入数据的合法性
50        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    // 打印矩阵的方法
64    pub fn print(&self) {
65        for row in &self.data {
66            for &elem in row {
67                print!("{} ", elem);
68            }
69            println!();
70        }
71    }
72    /// 执行矩阵加法运算。
73    ///
74    /// # 参数
75    ///
76    /// * `other` - 与当前矩阵相加的另一个矩阵。
77    ///
78    /// # 返回
79    ///
80    /// 如果矩阵维度相同,返回包含相加结果的 `Matrix2D` 实例;如果维度不同,返回 `None`。
81    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    /// 执行矩阵减法运算。
102    ///
103    /// # 参数
104    ///
105    /// * `other` - 从当前矩阵中减去的另一个矩阵。
106    ///
107    /// # 返回
108    ///
109    /// 如果矩阵维度相同,返回包含相减结果的 `Matrix2D` 实例;如果维度不同,返回 `None`。
110    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    /// 执行矩阵乘法运算。
131    ///
132    /// # 参数
133    ///
134    /// * `other` - 与当前矩阵相乘的另一个矩阵。
135    ///
136    /// # 返回
137    ///
138    /// 包含相乘结果的 `Matrix2D` 实例。
139    ///
140    /// # 注意
141    ///
142    /// 如果矩阵维度不符合相乘规则,将会引发 panic。
143    pub fn multiply(&self, other: &Matrix2D) -> Matrix2D {
144        // 检查矩阵维度是否允许相乘
145        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    /// 获取当前矩阵的转置。
170    ///
171    /// # 返回
172    ///
173    /// 包含转置结果的 `Matrix2D` 实例。
174    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    // 计算矩阵的行列式
192    pub fn determinant(&self) -> Option<f64> {
193        // 检查矩阵是否为方阵
194        if self.rows != self.cols {
195            return None;
196        }
197
198        // 递归计算行列式
199        self.calculate_determinant(&self.data)
200    }
201
202    // 递归计算行列式的辅助函数
203    fn calculate_determinant(&self, matrix: &Vec<Vec<f64>>) -> Option<f64> {
204        match self.rows {
205            1 => Some(matrix[0][0]), // 1x1 矩阵的行列式为其唯一元素的值
206            2 => Some(matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0]), // 2x2 矩阵的行列式计算公式
207            _ => {
208                let mut det = 0.0;
209
210                // 计算代数余子式
211                for col in 0..self.cols {
212                    // 计算代数余子式
213                    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    // 计算矩阵的逆矩阵
239    pub fn inverse(&self) -> Option<Matrix2D> {
240        // 检查矩阵是否为方阵
241        if self.rows != self.cols {
242            return None;
243        }
244
245        // 递归计算行列式
246        let det_a = self.determinant();
247        if det_a.unwrap() == 0.0 {
248            return None; // 行列式为零,逆矩阵不存在
249        }
250
251        // 计算矩阵的伴随矩阵
252        let adj_a = self.adjoint();
253
254        // 计算逆矩阵
255        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    // 计算矩阵的伴随矩阵
272    fn adjoint(&self) -> Matrix2D {
273        // 计算代数余子式
274        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                // 计算代数余子式
279                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    // 计算矩阵的特征值和特征向量
306    pub fn eigenvalue_eigenvector(&self) -> Option<(Vec<f64>, Vec<Vec<f64>>)> {
307        // 检查矩阵是否为方阵
308        if self.rows != self.cols {
309            return None;
310        }
311
312        // 构造特征值方程的左侧矩阵 A - λI
313        let a_minus_lambda_i: Matrix2D = self.subtract_identity();
314
315        // 求解特征值
316        let eigenvalues = match a_minus_lambda_i.determinant() {
317            Some(det) => self.find_eigenvalues(det),
318            None => return None,
319        };
320
321        // 求解特征向量
322        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    // 辅助方法:构造 A - λI
332    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 // λ 对应的位置减去 1
339                } 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    // 辅助方法:求解特征值方程的根
355    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    // 辅助方法:求解特征向量
364    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); // 右侧的常数项
372            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        // 简单的高斯消元法求解线性方程组
382        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        // 回代求解
406        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        // 归一化特征向量
415        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    // 辅助方法:交换矩阵的两行
420    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    //////////////
431
432
433    // 计算矩阵的奇异值分解
434    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        // 初始化 U、Σ、V
441        let mut ut = Matrix2D::eye(self.cols);
442        let mut v = Matrix2D::eye(self.cols);
443
444        // 迭代次数,可以根据需要调整
445        let max_iter = 100;
446
447        for _ in 0..max_iter {
448            // U的计算
449            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            // V的计算
456            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            // 更新 Σ
463            s.data = u.transpose().multiply(&self.multiply(&vt)).data;
464
465            // 更新 U、V
466            ut = ut.multiply(&u);
467            v = v.multiply(&vt);
468        }
469
470        // Σ的对角线元素开平方得到奇异值
471        for i in 0..self.cols {
472            s.data[i][i] = s.data[i][i].sqrt();
473        }
474
475        (ut, s, v)
476    }
477    // 计算矩阵乘以向量
478    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    // 单位矩阵
492    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    // 全0矩阵
501    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    // 求解特征值和特征向量
509    pub fn eigen(&self) -> (Vec<f64>, Matrix2D) {
510        // 简化处理,假设矩阵是实对称矩阵
511        // 在实际应用中,可以使用更复杂的算法来处理一般情况
512        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        // 迭代次数,可以根据需要调整
522        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                // 矩阵已经对称
534                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    // 对向量进行排序并返回排序后的索引
598    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    // 获取矩阵的某一列
604    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}