1mod chain_homotopy;
2mod finite_chain_complex;
3
4use std::sync::Arc;
5
6use algebra::{
7 Algebra, MuAlgebra,
8 module::{
9 Module, MuFreeModule,
10 homomorphism::{ModuleHomomorphism, MuFreeModuleHomomorphism},
11 },
12};
13pub use chain_homotopy::ChainHomotopy;
15pub use finite_chain_complex::{FiniteAugmentedChainComplex, FiniteChainComplex};
16use fp::{
17 matrix::Matrix,
18 prime::ValidPrime,
19 vector::{FpSlice, FpSliceMut},
20};
21use itertools::Itertools;
22use sseq::coordinates::{Bidegree, BidegreeGenerator};
23
24use crate::{save::SaveDirectory, utils::unicode_num};
25
26pub enum ChainComplexGrading {
27 Homological,
28 Cohomological,
29}
30
31pub trait FreeChainComplex<const U: bool = false>:
32 ChainComplex<
33 Module = MuFreeModule<U, <Self as ChainComplex>::Algebra>,
34 Homomorphism = MuFreeModuleHomomorphism<
35 U,
36 MuFreeModule<U, <Self as ChainComplex>::Algebra>,
37 >,
38 >
39where
40 <Self as ChainComplex>::Algebra: MuAlgebra<U>,
41{
42 fn graded_dimension_string(&self) -> String {
43 let mut result = String::new();
44 let min_degree = self.min_degree();
45 for s in (0..self.next_homological_degree()).rev() {
46 let module = self.module(s);
47
48 for t in min_degree + s..=module.max_computed_degree() {
49 result.push(unicode_num(module.number_of_gens_in_degree(t)));
50 result.push(' ');
51 }
52 result.push('\n');
53 if result.trim_start().is_empty() {
55 result.clear()
56 }
57 }
58 result
59 }
60
61 fn to_sseq(&self) -> sseq::Sseq<2, sseq::Adams> {
62 let p = self.prime();
63 let mut sseq = sseq::Sseq::new(p);
64 for b in self.iter_stem() {
65 sseq.set_dimension(b, self.number_of_gens_in_bidegree(b));
66 }
67 sseq
68 }
69
70 fn filtration_one_products(&self, op_deg: i32, op_idx: usize) -> sseq::Product<2> {
71 let p = self.prime();
72 let matrices = once::MultiIndexed::new();
73 for x in self.min_degree()..self.module(0).max_computed_degree() - op_deg + 2 {
74 let mut b = Bidegree::n_s(x, 0);
75 while self.has_computed_bidegree(b + Bidegree::s_t(1, op_deg)) {
76 if let Some(m) = self.filtration_one_product(op_deg, op_idx, b) {
77 matrices.insert(b, Matrix::from_vec(p, &m));
78 }
79 b = b + Bidegree::n_s(0, 1);
80 }
81 }
82
83 sseq::Product {
84 b: Bidegree::x_y(op_deg - 1, 1),
85 left: true,
86 matrices,
87 }
88 }
89
90 fn filtration_one_product(
96 &self,
97 op_deg: i32,
98 op_idx: usize,
99 source: Bidegree,
100 ) -> Option<Vec<Vec<u32>>> {
101 let target = source + Bidegree::s_t(1, op_deg);
102 if !self.has_computed_bidegree(target) {
103 return None;
104 }
105
106 let source_mod = self.module(target.s() - 1);
107 let target_mod = self.module(target.s());
108
109 if U && op_idx >= self.algebra().dimension_unstable(op_deg, source.t()) {
110 return None;
111 }
112
113 let source_dim = source_mod.number_of_gens_in_degree(source.t());
114 let target_dim = target_mod.number_of_gens_in_degree(target.t());
115
116 let d = self.differential(target.s());
117
118 let mut products = vec![Vec::with_capacity(target_dim); source_dim];
119 for i in 0..target_dim {
120 let dx = d.output(target.t(), i);
121
122 for (j, row) in products.iter_mut().enumerate() {
123 let idx = source_mod.operation_generator_to_index(op_deg, op_idx, source.t(), j);
124 row.push(dx.entry(idx));
125 }
126 }
127
128 Some(products)
129 }
130
131 fn number_of_gens_in_bidegree(&self, b: Bidegree) -> usize {
132 self.module(b.s()).number_of_gens_in_degree(b.t())
133 }
134
135 fn iter_nonzero_stem(&self) -> impl Iterator<Item = Bidegree> + '_ {
137 self.iter_stem()
138 .filter(move |&b| self.number_of_gens_in_bidegree(b) > 0)
139 }
140
141 fn boundary_string(&self, g: BidegreeGenerator) -> String {
143 let d = self.differential(g.s());
144 let target = d.target();
145 let result_vector = d.output(g.t(), g.idx());
146
147 target.element_to_string(g.t(), result_vector.as_slice())
148 }
149}
150
151impl<const U: bool, CC> FreeChainComplex<U> for CC
152where
153 CC: ChainComplex<
154 Module = MuFreeModule<U, Self::Algebra>,
155 Homomorphism = MuFreeModuleHomomorphism<U, MuFreeModule<U, Self::Algebra>>,
156 >,
157 Self::Algebra: MuAlgebra<U>,
158{
159}
160
161pub trait ChainComplex: Send + Sync {
164 type Algebra: Algebra;
165 type Module: Module<Algebra = Self::Algebra>;
166 type Homomorphism: ModuleHomomorphism<Source = Self::Module, Target = Self::Module>;
167
168 fn prime(&self) -> ValidPrime {
169 self.algebra().prime()
170 }
171
172 fn algebra(&self) -> Arc<Self::Algebra>;
173 fn min_degree(&self) -> i32;
174 fn zero_module(&self) -> Arc<Self::Module>;
175 fn module(&self, homological_degree: i32) -> Arc<Self::Module>;
176
177 fn differential(&self, s: i32) -> Arc<Self::Homomorphism>;
179
180 fn has_computed_bidegree(&self, b: Bidegree) -> bool;
185
186 fn compute_through_bidegree(&self, b: Bidegree);
188
189 fn next_homological_degree(&self) -> i32;
191
192 fn iter_stem(&self) -> StemIterator<'_, Self> {
194 StemIterator {
195 cc: self,
196 current: Bidegree::n_s(self.min_degree(), 0),
197 max_s: self.next_homological_degree(),
198 }
199 }
200
201 #[must_use]
207 fn apply_quasi_inverse<T, S>(&self, results: &mut [T], b: Bidegree, inputs: &[S]) -> bool
208 where
209 for<'a> &'a mut T: Into<FpSliceMut<'a>>,
210 for<'a> &'a S: Into<FpSlice<'a>>,
211 {
212 assert_eq!(results.len(), inputs.len());
213 if results.is_empty() {
214 return true;
215 }
216
217 let mut iter = inputs.iter().zip_eq(results);
218 let (input, result) = iter.next().unwrap();
219 let d = self.differential(b.s());
220 if d.apply_quasi_inverse(result.into(), b.t(), input.into()) {
221 for (input, result) in iter {
222 assert!(d.apply_quasi_inverse(result.into(), b.t(), input.into()));
223 }
224 true
225 } else {
226 false
227 }
228 }
229
230 fn save_dir(&self) -> &SaveDirectory {
232 &SaveDirectory::None
233 }
234
235 fn save_file(
237 &self,
238 kind: crate::save::SaveKind,
239 b: Bidegree,
240 ) -> crate::save::SaveFile<Self::Algebra> {
241 crate::save::SaveFile {
242 algebra: self.algebra(),
243 kind,
244 b,
245 idx: None,
246 }
247 }
248}
249
250pub struct StemIterator<'a, CC: ?Sized> {
252 cc: &'a CC,
253 current: Bidegree,
254 max_s: i32,
255}
256
257impl<CC: ChainComplex + ?Sized> Iterator for StemIterator<'_, CC> {
258 type Item = Bidegree;
259
260 fn next(&mut self) -> Option<Self::Item> {
261 if self.max_s == 0 {
262 return None;
263 }
264 let cur = self.current;
265
266 if cur.s() == self.max_s {
267 self.current = Bidegree::n_s(cur.n() + 1, 0);
268 return self.next();
269 }
270 if cur.t() > self.cc.module(cur.s()).max_computed_degree() {
271 if cur.s() == 0 {
272 return None;
273 } else {
274 self.current = Bidegree::n_s(cur.n() + 1, 0);
275 return self.next();
276 }
277 }
278 self.current = cur + Bidegree::n_s(0, 1);
279 Some(cur)
280 }
281}
282
283pub trait AugmentedChainComplex: ChainComplex {
286 type TargetComplex: ChainComplex<Algebra = Self::Algebra>;
287 type ChainMap: ModuleHomomorphism<
288 Source = Self::Module,
289 Target = <Self::TargetComplex as ChainComplex>::Module,
290 >;
291
292 fn target(&self) -> Arc<Self::TargetComplex>;
293 fn chain_map(&self, s: i32) -> Arc<Self::ChainMap>;
294}
295
296pub trait BoundedChainComplex: ChainComplex {
298 fn max_s(&self) -> i32;
299
300 fn euler_characteristic(&self, t: i32) -> isize {
301 (0..self.max_s())
302 .map(|s| (if s % 2 == 0 { 1 } else { -1 }) * self.module(s).dimension(t) as isize)
303 .sum()
304 }
305}
306
307pub struct ChainMap<F: ModuleHomomorphism> {
309 pub s_shift: i32,
310 pub chain_maps: Vec<F>,
311}