1use std::{
19 fs::File,
20 io,
21 path::{Path, PathBuf},
22 str::FromStr,
23 sync::Arc,
24};
25
26use algebra::{
27 Algebra, MilnorAlgebra,
28 milnor_algebra::MilnorBasisElement,
29 module::{FreeModule as FM, Module, homomorphism::FreeModuleHomomorphism as FMH},
30};
31use anyhow::{Context, Error, Result};
32use ext::{
33 chain_complex::{ChainComplex, FiniteChainComplex as FCC},
34 resolution_homomorphism::ResolutionHomomorphism,
35};
36use fp::{matrix::Matrix, prime::TWO, vector::FpVector};
37use sseq::coordinates::{Bidegree, BidegreeGenerator};
38
39#[cfg(feature = "nassau")]
40type FreeModule = FM<MilnorAlgebra>;
41#[cfg(not(feature = "nassau"))]
42type FreeModule = FM<algebra::SteenrodAlgebra>;
43
44type FreeModuleHomomorphism = FMH<FreeModule>;
45type FiniteChainComplex = FCC<FreeModule, FreeModuleHomomorphism>;
46
47fn read_line(data: &mut impl io::BufRead, buf: &mut String) -> Result<bool> {
49 buf.clear();
50 while buf.is_empty() {
51 let num_bytes = data.read_line(buf)?;
52 if num_bytes == 0 {
53 return Ok(false);
54 }
55 buf.pop();
57 }
58 Ok(true)
59}
60
61fn entry<T>(x: &str) -> Result<(&str, T)>
63where
64 T: FromStr,
65 Error: From<<T as FromStr>::Err>,
66{
67 let x = x.trim();
68 match x.find(' ') {
69 Some(k) => Ok((&x[k..], x[..k].parse()?)),
70 None => Ok(("", x.parse()?)),
71 }
72}
73
74fn get_algebra_element<'a>(
80 a: &'a MilnorAlgebra,
81 input: &'a str,
82) -> Result<impl Iterator<Item = usize> + 'a> {
83 let (input, t) = entry(input)?;
84 let (input, _) = entry::<u32>(input)?;
85
86 let input = input.trim();
87 assert_eq!(&input[0..1], "i");
88
89 let input = &input[1..];
91 let input = &input[..input.len() - 2];
93
94 Ok(input.split(')').map(move |entry| {
95 let entry = &entry[1..];
96 let elt = MilnorBasisElement {
97 q_part: 0,
98 p_part: entry.split(',').map(|x| x.parse().unwrap()).collect(),
99 degree: t,
100 };
101 a.basis_element_to_index(&elt)
102 }))
103}
104
105fn get_element(
107 a: &MilnorAlgebra,
108 m: &FreeModule,
109 input: &mut impl io::BufRead,
110) -> Result<Option<(i32, FpVector)>> {
111 let mut buf = String::new();
112 if !read_line(input, &mut buf)? {
113 return Ok(None);
114 }
115 let degree: i32 = buf.trim().parse()?;
116 a.compute_basis(degree);
117 m.compute_basis(degree);
118
119 read_line(input, &mut buf)?;
120 let num_lines: usize = buf.trim().parse()?;
121
122 let mut result = FpVector::new(TWO, m.dimension(degree));
123
124 for _ in 0..num_lines {
125 read_line(input, &mut buf)?;
126 let (rem, gen_idx) = entry::<usize>(&buf)?;
127 let offset = m.internal_generator_offset(degree, gen_idx);
128 for op in get_algebra_element(a, &rem[1..])? {
129 result.add_basis_element(offset + op, 1);
130 }
131 }
132 Ok(Some((degree, result)))
133}
134
135fn create_chain_complex(num_s: usize) -> FiniteChainComplex {
137 #[cfg(feature = "nassau")]
138 let algebra: Arc<MilnorAlgebra> = Arc::new(MilnorAlgebra::new(TWO, false));
139
140 #[cfg(not(feature = "nassau"))]
141 let algebra: Arc<algebra::SteenrodAlgebra> = Arc::new(algebra::SteenrodAlgebra::MilnorAlgebra(
142 MilnorAlgebra::new(TWO, false),
143 ));
144
145 let mut modules: Vec<Arc<FreeModule>> = Vec::with_capacity(num_s);
146 let mut differentials: Vec<Arc<FreeModuleHomomorphism>> = Vec::with_capacity(num_s - 1);
147 for _ in 0..num_s {
148 modules.push(Arc::new(FreeModule::new(
149 Arc::clone(&algebra),
150 String::new(),
151 0,
152 )));
153 }
154 for s in 1..num_s {
155 differentials.push(Arc::new(FreeModuleHomomorphism::new(
156 Arc::clone(&modules[s]),
157 Arc::clone(&modules[s - 1]),
158 0,
159 )));
160 }
161 FiniteChainComplex::new(modules, differentials)
162}
163
164fn read_bruner_resolution(data_dir: &Path, max_n: i32) -> Result<(i32, FiniteChainComplex)> {
166 let num_s = data_dir.read_dir()?.count() as i32;
167
168 let cc = create_chain_complex(num_s as usize);
169 let algebra = cc.algebra();
170
171 let algebra: &MilnorAlgebra = algebra.as_ref().try_into()?;
172
173 let mut buf = String::new();
174 let s = num_s - 1;
175
176 algebra.compute_basis(max_n + s + 1);
177 {
179 let m = cc.module(0);
181 m.add_generators(0, 1, None);
182 m.extend_by_zero(max_n + 1);
183 }
184
185 for s in 1..num_s {
186 let m = cc.module(s);
187 let d = cc.differential(s);
188
189 let mut f = io::BufReader::new(
190 File::open(data_dir.join(format!("hDiff.{s}")))
191 .with_context(|| format!("Failed to read hDiff.{s}"))?,
192 );
193
194 read_line(&mut f, &mut buf)?;
195
196 let mut entries: Vec<FpVector> = Vec::new();
197 let mut cur_degree: i32 = 0;
198
199 while let Some((t, g)) = get_element(algebra, cc.module(s - 1).as_ref(), &mut f)? {
200 if t == cur_degree {
201 entries.push(g);
202 } else {
203 m.add_generators(cur_degree, entries.len(), None);
204 d.add_generators_from_rows(cur_degree, entries);
205
206 m.extend_by_zero(t - 1);
207 d.extend_by_zero(t - 1);
208
209 entries = vec![g];
210 cur_degree = t;
211 }
212 }
213 m.add_generators(cur_degree, entries.len(), None);
214 d.add_generators_from_rows(cur_degree, entries);
215
216 m.extend_by_zero(max_n + s + 1);
217 d.extend_by_zero(max_n + s);
218 }
219
220 Ok((s, cc))
221}
222
223fn main() -> anyhow::Result<()> {
224 ext::utils::init_logging()?;
225
226 let data_dir = Path::new(file!()).parent().unwrap().join("bruner_data");
227 let max_n: i32 = query::with_default("Max n", "20", str::parse);
228
229 let (max_s, cc) = read_bruner_resolution(&data_dir, max_n).unwrap();
231 let max = Bidegree::n_s(max_n, max_s);
232 let cc = Arc::new(cc);
233
234 let save_dir = query::optional("Save directory", |x| {
235 core::result::Result::<PathBuf, std::convert::Infallible>::Ok(PathBuf::from(x))
236 });
237
238 #[cfg(feature = "nassau")]
239 assert!(
240 save_dir.is_some(),
241 "A save directory is required for comparison between Bruner and Nassau resolutions."
242 );
243
244 let resolution = ext::utils::construct("S_2@milnor", save_dir).unwrap();
245
246 resolution.compute_through_stem(max);
247
248 let resolution = Arc::new(resolution);
249
250 let hom = ResolutionHomomorphism::new(String::new(), cc, resolution, Bidegree::zero());
252
253 hom.extend_step(Bidegree::zero(), Some(&Matrix::from_vec(TWO, &[vec![1]])));
255 hom.extend_all();
256
257 println!("sseq_basis | bruner_basis");
259 for b in hom.target.iter_stem() {
260 let matrix = hom.get_map(b.s()).hom_k(b.t());
261
262 for (i, row) in matrix.into_iter().enumerate() {
263 let g = BidegreeGenerator::new(b, i);
264 println!("x_{g:#} = {row:?}");
265 }
266 }
267
268 Ok(())
269}