mathhook_core/matrices/decomposition.rs
1//! Matrix decomposition algorithms
2//!
3//! This module provides various matrix decomposition methods including LU, QR,
4//! Cholesky, and SVD decompositions optimized for the unified matrix system.
5
6pub mod cholesky;
7pub mod decomposition_tests;
8pub mod lu;
9pub mod qr;
10pub mod svd;
11use crate::core::Expression;
12use crate::matrices::types::*;
13use crate::matrices::unified::Matrix;
14
15/// Matrix decomposition operations trait
16///
17/// This trait provides a unified interface for all matrix decomposition methods.
18/// Each method returns an Option to handle cases where decomposition is not possible.
19pub trait MatrixDecomposition {
20 /// Perform LU decomposition with partial pivoting
21 ///
22 /// Decomposes matrix A into PA = LU where:
23 /// - P is a permutation matrix
24 /// - L is lower triangular with 1s on diagonal
25 /// - U is upper triangular
26 ///
27 /// # Examples
28 ///
29 /// ```rust
30 /// use mathhook_core::matrices::{Matrix, MatrixDecomposition};
31 /// use mathhook_core::Expression;
32 ///
33 /// let matrix = Matrix::from_arrays([
34 /// [2, 1, 1],
35 /// [4, 3, 3],
36 /// [8, 7, 9]
37 /// ]);
38 ///
39 /// let lu = matrix.lu_decomposition().unwrap();
40 /// // Verify: P*A = L*U
41 /// ```
42 fn lu_decomposition(&self) -> Option<LUDecomposition>;
43
44 /// Perform QR decomposition using Gram-Schmidt process
45 ///
46 /// Decomposes matrix A into A = QR where:
47 /// - Q is orthogonal (Q^T * Q = I)
48 /// - R is upper triangular
49 ///
50 /// # Examples
51 ///
52 /// ```rust
53 /// use mathhook_core::matrices::{Matrix, MatrixDecomposition};
54 ///
55 /// let matrix = Matrix::from_arrays([
56 /// [1, 1, 0],
57 /// [1, 0, 1],
58 /// [0, 1, 1]
59 /// ]);
60 ///
61 /// let qr = matrix.qr_decomposition().unwrap();
62 /// // Verify: A = Q*R and Q^T*Q = I
63 /// ```
64 fn qr_decomposition(&self) -> Option<QRDecomposition>;
65
66 /// Perform Cholesky decomposition for positive definite matrices
67 ///
68 /// Decomposes symmetric positive definite matrix A into A = LL^T where:
69 /// - L is lower triangular with positive diagonal elements
70 ///
71 /// # Examples
72 ///
73 /// ```rust
74 /// use mathhook_core::matrices::{Matrix, MatrixDecomposition};
75 ///
76 /// let matrix = Matrix::from_arrays([
77 /// [4, 2, 1],
78 /// [2, 3, 0],
79 /// [1, 0, 2]
80 /// ]);
81 ///
82 /// if let Some(chol) = matrix.cholesky_decomposition() {
83 /// // Verify: A = L*L^T
84 /// }
85 /// ```
86 fn cholesky_decomposition(&self) -> Option<CholeskyDecomposition>;
87
88 /// Perform Singular Value Decomposition
89 ///
90 /// Decomposes matrix A into A = UΣV^T where:
91 /// - U contains left singular vectors (orthogonal)
92 /// - Σ contains singular values (diagonal, non-negative)
93 /// - V^T contains right singular vectors (orthogonal)
94 ///
95 /// # Examples
96 ///
97 /// ```rust
98 /// use mathhook_core::matrices::{Matrix, MatrixDecomposition};
99 ///
100 /// let matrix = Matrix::from_arrays([
101 /// [1, 2],
102 /// [3, 4],
103 /// [5, 6]
104 /// ]);
105 ///
106 /// let svd = matrix.svd_decomposition().unwrap();
107 /// // Verify: A = U*Σ*V^T
108 /// ```
109 fn svd_decomposition(&self) -> Option<SVDDecomposition>;
110
111 /// Get matrix rank using SVD
112 fn rank(&self) -> usize;
113
114 /// Check if matrix is positive definite
115 fn is_positive_definite(&self) -> bool;
116
117 /// Get condition number (ratio of largest to smallest singular value)
118 fn condition_number(&self) -> Expression;
119}
120
121/// Implementation of MatrixDecomposition trait for Matrix
122impl MatrixDecomposition for Matrix {
123 fn lu_decomposition(&self) -> Option<LUDecomposition> {
124 // Delegate to lu module implementation
125 self.lu_decomposition()
126 }
127
128 fn qr_decomposition(&self) -> Option<QRDecomposition> {
129 // Delegate to qr module implementation
130 self.qr_decomposition()
131 }
132
133 fn cholesky_decomposition(&self) -> Option<CholeskyDecomposition> {
134 // Delegate to cholesky module implementation
135 self.cholesky_decomposition()
136 }
137
138 fn svd_decomposition(&self) -> Option<SVDDecomposition> {
139 // Delegate to svd module implementation
140 self.svd_decomposition()
141 }
142
143 fn rank(&self) -> usize {
144 // Delegate to svd module implementation
145 self.rank_via_svd()
146 }
147
148 fn is_positive_definite(&self) -> bool {
149 // Delegate to cholesky module implementation
150 self.is_positive_definite_cholesky()
151 }
152
153 fn condition_number(&self) -> Expression {
154 // Delegate to svd module implementation
155 self.condition_number_via_svd()
156 }
157}
158
159/// Helper methods for matrix operations
160impl Matrix {
161 /// Convert any matrix to dense representation
162 pub(crate) fn to_dense_matrix(&self) -> Matrix {
163 let (rows, cols) = self.dimensions();
164 let mut dense_rows = Vec::with_capacity(rows);
165
166 for i in 0..rows {
167 let mut row = Vec::with_capacity(cols);
168 for j in 0..cols {
169 row.push(self.get_element(i, j));
170 }
171 dense_rows.push(row);
172 }
173
174 Matrix::dense(dense_rows)
175 }
176
177 /// Swap two rows in a matrix
178 pub(crate) fn swap_rows(&self, row1: usize, row2: usize) -> Matrix {
179 if row1 == row2 {
180 return self.clone();
181 }
182
183 let (rows, cols) = self.dimensions();
184 let mut new_rows = Vec::with_capacity(rows);
185
186 for i in 0..rows {
187 let mut row = Vec::with_capacity(cols);
188 let source_row = if i == row1 {
189 row2
190 } else if i == row2 {
191 row1
192 } else {
193 i
194 };
195
196 for j in 0..cols {
197 row.push(self.get_element(source_row, j));
198 }
199 new_rows.push(row);
200 }
201
202 Matrix::dense(new_rows)
203 }
204
205 /// Set element at position (i, j) - returns new matrix
206 pub(crate) fn set_element(&self, i: usize, j: usize, value: &Expression) -> Matrix {
207 let (rows, cols) = self.dimensions();
208 let mut new_rows = Vec::with_capacity(rows);
209
210 for row_idx in 0..rows {
211 let mut row = Vec::with_capacity(cols);
212 for col_idx in 0..cols {
213 if row_idx == i && col_idx == j {
214 row.push(value.clone());
215 } else {
216 row.push(self.get_element(row_idx, col_idx));
217 }
218 }
219 new_rows.push(row);
220 }
221
222 Matrix::dense(new_rows)
223 }
224}