mathhook_core/matrices/decomposition/
qr.rs1use crate::core::Expression;
7use crate::matrices::types::*;
8use crate::matrices::unified::Matrix;
9use crate::simplify::Simplify;
10
11impl Matrix {
13 pub fn qr_decomposition(&self) -> Option<QRDecomposition> {
35 match self {
36 Matrix::Identity(data) => Some(QRDecomposition {
37 q: Matrix::identity(data.size),
38 r: Matrix::identity(data.size),
39 }),
40 Matrix::Zero(data) => Some(QRDecomposition {
41 q: Matrix::identity(data.rows),
42 r: Matrix::zero(data.rows, data.cols),
43 }),
44 _ => {
45 self.gram_schmidt_qr()
47 }
48 }
49 }
50
51 fn gram_schmidt_qr(&self) -> Option<QRDecomposition> {
53 let (rows, cols) = self.dimensions();
54 let mut q_columns: Vec<Vec<Expression>> = Vec::new();
55 let mut r_elements = vec![vec![Expression::integer(0); cols]; cols];
56
57 for (j, r_column) in r_elements.iter_mut().enumerate() {
59 let mut column: Vec<Expression> = (0..rows).map(|i| self.get_element(i, j)).collect();
60
61 for (k, q_col) in q_columns.iter().enumerate() {
63 let dot_product = self.vector_dot(&column, q_col);
64 r_column[k] = dot_product.clone();
65
66 for (col_elem, q_elem) in column.iter_mut().zip(q_col) {
68 let old_val = col_elem.clone();
69 let subtract_val = Expression::mul(vec![dot_product.clone(), q_elem.clone()]);
70 *col_elem = Expression::add(vec![
71 old_val,
72 Expression::mul(vec![Expression::integer(-1), subtract_val]),
73 ])
74 .simplify();
75 }
76 }
77
78 let norm = self.vector_norm(&column);
80 if norm.is_zero() {
81 return None; }
83
84 r_column[j] = norm.clone();
85
86 let q_column: Vec<Expression> = column
88 .iter()
89 .map(|elem| {
90 Expression::mul(vec![
92 elem.clone(),
93 Expression::pow(norm.clone(), Expression::integer(-1)),
94 ])
95 .simplify()
96 })
97 .collect();
98 q_columns.push(q_column);
99 }
100
101 let q_rows: Vec<Vec<Expression>> = (0..rows)
103 .map(|i| {
104 (0..cols)
105 .map(|j| {
106 if j < q_columns.len() {
107 q_columns[j][i].clone()
108 } else {
109 Expression::integer(0)
110 }
111 })
112 .collect()
113 })
114 .collect();
115
116 Some(QRDecomposition {
117 q: Matrix::dense(q_rows),
118 r: Matrix::dense(r_elements),
119 })
120 }
121
122 fn vector_dot(&self, v1: &[Expression], v2: &[Expression]) -> Expression {
126 if v1.len() != v2.len() {
127 return Expression::integer(0);
128 }
129
130 let products: Vec<Expression> = v1
131 .iter()
132 .zip(v2.iter())
133 .map(|(a, b)| Expression::mul(vec![a.clone(), b.clone()]))
134 .collect();
135
136 Expression::add(products).simplify()
137 }
138
139 fn vector_norm(&self, v: &[Expression]) -> Expression {
143 let sum_of_squares: Vec<Expression> = v
144 .iter()
145 .map(|x| Expression::pow(x.clone(), Expression::integer(2)))
146 .collect();
147
148 let sum = Expression::add(sum_of_squares).simplify();
149 Expression::pow(sum, Expression::rational(1, 2))
150 }
151}