1use super::*;
2use crate::module::{
3 finitely_free_module::FinitelyFreeModuleStructure,
4 finitely_free_submodule::FinitelyFreeSubmodule,
5};
6
7#[derive(Debug, Clone)]
8pub struct JordanBlock<FS: AlgebraicClosureSignature>
9where
10 PolynomialStructure<FS::BFS, FS::BFS>: FactoringMonoidSignature<FactoredExponent = NaturalCanonicalStructure>
11 + SetSignature<Set = Polynomial<<FS::BFS as SetSignature>::Set>>,
12{
13 eigenvalue: FS::Set,
14 blocksize: usize,
15}
16
17impl<FS: AlgebraicClosureSignature> JordanBlock<FS>
18where
19 PolynomialStructure<FS::BFS, FS::BFS>: FactoringMonoidSignature<FactoredExponent = NaturalCanonicalStructure>
20 + SetSignature<Set = Polynomial<<FS::BFS as SetSignature>::Set>>,
21{
22 pub fn matrix(&self, field: &FS) -> Matrix<FS::Set> {
23 Matrix::construct(self.blocksize, self.blocksize, |r, c| {
25 if r == c {
26 self.eigenvalue.clone()
27 } else if r + 1 == c {
28 field.one()
29 } else {
30 field.zero()
31 }
32 })
33 }
34}
35
36#[derive(Debug, Clone)]
37pub struct JordanNormalForm<FS: AlgebraicClosureSignature>
38where
39 PolynomialStructure<FS::BFS, FS::BFS>: FactoringMonoidSignature<FactoredExponent = NaturalCanonicalStructure>
40 + SetSignature<Set = Polynomial<<FS::BFS as SetSignature>::Set>>,
41{
42 field: FS,
43 blocks: Vec<JordanBlock<FS>>,
44}
45
46impl<FS: AlgebraicClosureSignature> JordanNormalForm<FS>
47where
48 PolynomialStructure<FS::BFS, FS::BFS>: FactoringMonoidSignature<FactoredExponent = NaturalCanonicalStructure>
49 + SetSignature<Set = Polynomial<<FS::BFS as SetSignature>::Set>>,
50{
51 pub fn matrix(&self) -> Matrix<FS::Set> {
52 let ac_mat_structure = MatrixStructure::new(self.field.clone());
53 ac_mat_structure.join_diag(
54 self.blocks
55 .iter()
56 .map(|block| block.matrix(&self.field))
57 .collect(),
58 )
59 }
60}
61
62impl<FS: AlgebraicClosureSignature, FSB: BorrowedStructure<FS>> MatrixStructure<FS, FSB>
63where
64 PolynomialStructure<FS::BFS, FS::BFS>: FactoringMonoidSignature<FactoredExponent = NaturalCanonicalStructure>
65 + SetSignature<Set = Polynomial<<FS::BFS as SetSignature>::Set>>,
66{
67 pub fn eigenvalues_list(&self, mat: Matrix<<FS::BFS as SetSignature>::Set>) -> Vec<FS::Set> {
68 let base_field_mat_structure = MatrixStructure::new(self.ring().base_field().clone());
69 self.ring()
70 .all_roots_list(
71 &base_field_mat_structure
72 .characteristic_polynomial(mat)
73 .unwrap(),
74 )
75 .unwrap()
76 }
77
78 pub fn eigenvalues_unique(&self, mat: Matrix<<FS::BFS as SetSignature>::Set>) -> Vec<FS::Set> {
79 let base_field_mat_structure = MatrixStructure::new(self.ring().base_field().clone());
80 self.ring()
81 .all_roots_unique(
82 &base_field_mat_structure
83 .characteristic_polynomial(mat)
84 .unwrap(),
85 )
86 .unwrap()
87 }
88
89 pub fn eigenvalues_powers(
90 &self,
91 mat: Matrix<<FS::BFS as SetSignature>::Set>,
92 ) -> Vec<(FS::Set, usize)> {
93 let base_field_mat_structure = MatrixStructure::new(self.ring().base_field().clone());
94 self.ring()
95 .all_roots_powers(
96 &base_field_mat_structure
97 .characteristic_polynomial(mat)
98 .unwrap(),
99 )
100 .unwrap()
101 }
102
103 pub fn generalized_col_eigenspace(
104 &self,
105 mat: &Matrix<<FS::BFS as SetSignature>::Set>,
106 eigenvalue: &FS::Set,
107 k: usize,
108 ) -> FinitelyFreeSubmodule<FS::Set> {
109 let n = mat.rows();
110 assert_eq!(n, mat.cols());
111 self.col_kernel(
113 self.nat_pow(
114 &self
115 .add(
116 &mat.apply_map(|x| self.ring().base_field_inclusion(x)),
117 &self.neg(self.mul_scalar(self.ident(n), eigenvalue)),
118 )
119 .unwrap(),
120 &Natural::from(k),
121 )
122 .unwrap(),
123 )
124 }
125
126 pub fn generalized_row_eigenspace(
127 &self,
128 mat: &Matrix<<FS::BFS as SetSignature>::Set>,
129 eigenvalue: &FS::Set,
130 k: usize,
131 ) -> FinitelyFreeSubmodule<FS::Set> {
132 self.generalized_col_eigenspace(&mat.transpose_ref(), eigenvalue, k)
133 }
134
135 pub fn col_eigenspace(
136 &self,
137 mat: &Matrix<<FS::BFS as SetSignature>::Set>,
138 eigenvalue: &FS::Set,
139 ) -> FinitelyFreeSubmodule<FS::Set> {
140 self.generalized_col_eigenspace(mat, eigenvalue, 1)
141 }
142
143 pub fn row_eigenspace(
144 &self,
145 mat: &Matrix<<FS::BFS as SetSignature>::Set>,
146 eigenvalue: &FS::Set,
147 ) -> FinitelyFreeSubmodule<FS::Set> {
148 self.generalized_row_eigenspace(mat, eigenvalue, 1)
149 }
150
151 pub fn jordan_algorithm(
154 &self,
155 mat: &Matrix<<FS::BFS as SetSignature>::Set>,
156 ) -> (JordanNormalForm<FS>, Matrix<FS::Set>) {
157 let n = mat.rows();
158 assert_eq!(n, mat.cols());
159
160 let ac_field = self.ring();
161 let ac_mat_structure = self;
162
163 let ac_mat = mat.apply_map(|x| self.ring().base_field_inclusion(x));
164
165 let mut basis = vec![];
166 let mut eigenvalues = vec![]; for (eigenvalue, multiplicity) in self.eigenvalues_powers(mat.clone()) {
168 let eigenspace = self.generalized_col_eigenspace(mat, &eigenvalue, multiplicity);
169 debug_assert_eq!(eigenspace.rank(), multiplicity);
170 basis.append(&mut eigenspace.basis());
171 eigenvalues.push((eigenvalue, multiplicity));
172 }
173
174 let gesp_basis = Matrix::construct(mat.rows(), basis.len(), |r, c| basis[c][r].clone());
176 let gesp_blocks_mat = ac_mat_structure
178 .mul(
179 &ac_mat_structure.inv(gesp_basis.clone()).unwrap(),
180 &ac_mat_structure.mul(&ac_mat, &gesp_basis).unwrap(),
181 )
182 .unwrap();
183
184 let mut idx_to_block = vec![];
185 for (b, (_eval, mult)) in eigenvalues.iter().enumerate() {
186 for _i in 0..*mult {
187 idx_to_block.push(b);
188 }
189 }
190
191 let mut gesp_blocks = vec![];
193 let mut cum_mult = 0;
194 for (eval, mult) in eigenvalues {
195 gesp_blocks.push((
196 eval,
197 mult,
198 Matrix::construct(mult, mult, |r, c| {
199 gesp_blocks_mat
200 .at(cum_mult + r, cum_mult + c)
201 .unwrap()
202 .clone()
203 }),
204 ));
205 cum_mult += mult;
206 }
207 debug_assert_eq!(cum_mult, n);
208 drop(gesp_blocks_mat);
209
210 let jnf_info = gesp_blocks
212 .into_iter()
213 .map(|(eval, m, mat_t)| {
214 debug_assert_eq!(mat_t.rows(), m);
215 debug_assert_eq!(mat_t.cols(), m);
216 let mat_s = ac_mat_structure
219 .add(
220 &mat_t,
221 &ac_mat_structure
222 .mul_scalar(ac_mat_structure.ident(m), &ac_field.neg(&eval)),
223 )
224 .unwrap();
225
226 let jb_basis = {
227 debug_assert!(m >= 1);
228
229 let mut mat_s_pows = vec![ac_mat_structure.ident(m), mat_s.clone()];
230 for _i in 0..(m - 1) {
231 mat_s_pows.push(
232 ac_mat_structure
233 .mul(mat_s_pows.last().unwrap(), &mat_s)
234 .unwrap(),
235 );
236 }
237 debug_assert!(
238 ac_mat_structure.equal(&ac_mat_structure.zero(m, m), &mat_s_pows[m])
239 );
240
241 let mat_s_pow_kers = mat_s_pows
242 .into_iter()
243 .map(|s_mat_pow| ac_mat_structure.col_kernel(s_mat_pow))
244 .collect_vec();
245 let module = FinitelyFreeModuleStructure::<FS, _>::new(ac_field, m);
248 let mut accounted = module.submodules().zero_submodule();
249
250 let mut jordan_block_bases = vec![];
251 for k in (0..m).rev() {
252 let ker_ext = module.submodules().span(
254 module
255 .submodules()
256 .extension_basis(&mat_s_pow_kers[k], &mat_s_pow_kers[k + 1])
257 .iter()
258 .collect(),
259 );
260
261 let unaccounted_ker_ext_basis = module.submodules().extension_basis(
262 &module
263 .submodules()
264 .intersect(accounted.clone(), ker_ext.clone()),
265 &ker_ext,
266 );
267
268 for ukeb in unaccounted_ker_ext_basis {
269 let mut jb_basis = vec![ukeb];
272 for _i in 0..k {
273 let ukeb_img = ac_mat_structure
274 .mul(
275 &mat_s,
276 &Matrix::construct(m, 1, |r, _| {
277 jb_basis.last().unwrap()[r].clone()
278 }),
279 )
280 .unwrap();
281 assert_eq!(ukeb_img.cols(), 1);
282 assert_eq!(ukeb_img.rows(), m);
283 jb_basis.push(ukeb_img.get_col(0));
285 }
286
287 accounted = module.submodules().add(
288 accounted,
289 module.submodules().span(jb_basis.iter().collect()),
290 );
291 jordan_block_bases.push(jb_basis.into_iter().rev().collect_vec());
292 }
293 }
294
295 jordan_block_bases
296 };
297
298 (eval, m, jb_basis)
299 })
300 .collect_vec();
301
302 let mut jordan_blocks = vec![];
303 let mut jnf_basis_rel_gesp_basis: Vec<Matrix<FS::Set>> = vec![];
304 for (eval, mult, blocks) in jnf_info {
305 let mut eigenblock_basis = vec![];
307 for mut block in blocks {
308 jordan_blocks.push(JordanBlock {
309 eigenvalue: eval.clone(),
310 blocksize: block.len(),
311 });
312 eigenblock_basis.append(&mut block);
313 }
314 jnf_basis_rel_gesp_basis.push(Matrix::join_cols(
315 mult,
316 eigenblock_basis
317 .into_iter()
318 .map(|col| Matrix::from_cols(vec![col]))
319 .collect(),
320 ));
321 }
322 let jnf = JordanNormalForm {
323 field: self.ring().clone(),
324 blocks: jordan_blocks,
325 };
326 let jordan_blocks_basis = ac_mat_structure.join_diag(jnf_basis_rel_gesp_basis);
327
328 let jnf_basis = ac_mat_structure
334 .mul(&gesp_basis, &jordan_blocks_basis)
335 .unwrap();
336 debug_assert!(
341 ac_mat_structure.equal(
342 &ac_mat_structure
343 .mul(
344 &ac_mat_structure.inv(jnf_basis.clone()).unwrap(),
345 &ac_mat_structure.mul(&ac_mat, &jnf_basis).unwrap(),
346 )
347 .unwrap(),
348 &jnf.matrix()
349 )
350 );
351 (jnf, jnf_basis)
357 }
358
359 pub fn jordan_normal_form(
360 &self,
361 mat: &Matrix<<FS::BFS as SetSignature>::Set>,
362 ) -> Matrix<FS::Set> {
363 self.jordan_algorithm(mat).0.matrix()
364 }
365
366 }
397
398#[cfg(test)]
399mod tests {
400 use super::*;
401 use crate::isolated_algebraic::ComplexAlgebraic;
402
403 #[test]
404 fn jordan_normal_form() {
405 let mat = Matrix::from_rows(vec![
406 vec![
407 Rational::from(3),
408 Rational::from(1),
409 Rational::from(0),
410 Rational::from(1),
411 ],
412 vec![
413 Rational::from(-1),
414 Rational::from(5),
415 Rational::from(4),
416 Rational::from(1),
417 ],
418 vec![
419 Rational::from(0),
420 Rational::from(0),
421 Rational::from(2),
422 Rational::from(0),
423 ],
424 vec![
425 Rational::from(0),
426 Rational::from(0),
427 Rational::from(0),
428 Rational::from(4),
429 ],
430 ]);
431
432 mat.pprint();
433 for root in
434 MatrixStructure::new(ComplexAlgebraic::structure()).eigenvalues_list(mat.clone())
435 {
436 println!("{}", root);
437 }
438
439 let (j, b) = MatrixStructure::new(ComplexAlgebraic::structure()).jordan_algorithm(&mat);
440 println!("{:?}", j);
441 j.matrix().pprint();
442 b.pprint();
443
444 let mat = Matrix::<Rational>::from_rows(vec![vec![1, 0, 0], vec![0, 0, -1], vec![0, 2, 0]]);
445
446 mat.pprint();
447 for root in
448 MatrixStructure::new(ComplexAlgebraic::structure()).eigenvalues_list(mat.clone())
449 {
450 println!("{}", root);
451 }
452
453 let (j, b) = MatrixStructure::new(ComplexAlgebraic::structure()).jordan_algorithm(&mat);
454 println!("{:?}", j);
455 j.matrix().pprint();
456 b.pprint();
457 }
458}