1use std::sync::Arc;
20
21use algebra::{module::Module, pair_algebra::PairAlgebra};
22use ext::{
23 chain_complex::{ChainComplex, ChainHomotopy, FreeChainComplex},
24 resolution_homomorphism::ResolutionHomomorphism,
25 secondary::*,
26 utils::{QueryModuleResolution, query_module},
27};
28use fp::{
29 matrix::{Matrix, Subspace},
30 vector::FpVector,
31};
32use itertools::Itertools;
33use sseq::coordinates::{Bidegree, BidegreeElement};
34
35struct HomData {
36 name: String,
37 class: FpVector,
38 hom_lift: Arc<SecondaryResolutionHomomorphism<QueryModuleResolution, QueryModuleResolution>>,
39 lambda_part: Option<Arc<ResolutionHomomorphism<QueryModuleResolution, QueryModuleResolution>>>,
40}
41
42fn get_hom(
43 name: &str,
44 source: Arc<SecondaryResolution<QueryModuleResolution>>,
45 target: Arc<SecondaryResolution<QueryModuleResolution>>,
46) -> HomData {
47 let p = source.prime();
48
49 let shift = Bidegree::n_s(
50 query::raw(&format!("n of {name}"), str::parse),
51 query::raw(&format!("s of {name}"), str::parse),
52 );
53
54 let ext_name: String = query::raw(&format!("Name of Ext part of {name}"), str::parse);
55
56 source
57 .underlying()
58 .compute_through_stem(shift + LAMBDA_BIDEGREE);
59
60 let hom = Arc::new(ResolutionHomomorphism::new(
61 ext_name.clone(),
62 source.underlying(),
63 target.underlying(),
64 shift,
65 ));
66
67 let num_gens = source.underlying().number_of_gens_in_bidegree(shift);
68 let num_lambda_gens = hom
69 .source
70 .number_of_gens_in_bidegree(shift + LAMBDA_BIDEGREE);
71
72 let mut class = FpVector::new(p, num_gens + num_lambda_gens);
73
74 let mut matrix = Matrix::new(p, num_gens, 1);
75
76 if !hom.name().is_empty() {
77 if matrix.rows() == 0 {
78 eprintln!("No classes in this bidegree");
79 } else {
80 let v: Vec<u32> = query::vector(&format!("Input Ext class {ext_name}"), num_gens);
81 for (i, &x) in v.iter().enumerate() {
82 matrix.row_mut(i).set_entry(0, x);
83 class.set_entry(i, x);
84 }
85 }
86 }
87
88 hom.extend_step(shift, Some(&matrix));
89
90 let hom_lift = Arc::new(SecondaryResolutionHomomorphism::new(source, target, hom));
91
92 let lambda_part = if num_lambda_gens > 0 {
93 let lambda_name: String = query::raw(&format!("Name of λ part of {name}"), str::parse);
94 if lambda_name.is_empty() {
95 None
96 } else {
97 let v = query::vector(&format!("Input Ext class {lambda_name}"), num_lambda_gens);
98 for (i, &x) in v.iter().enumerate() {
99 class.set_entry(num_gens + i, x);
100 }
101 Some(Arc::new(ResolutionHomomorphism::from_class(
102 lambda_name,
103 hom_lift.source(),
104 hom_lift.target(),
105 shift + LAMBDA_BIDEGREE,
106 &v,
107 )))
108 }
109 } else {
110 None
111 };
112
113 let name = match (&*ext_name, lambda_part.as_ref().map_or("", |x| x.name())) {
114 ("", "") => panic!("Do not compute zero Massey product"),
115 ("", x) => format!("λ{x}"),
116 (x, "") => format!("[{x}]"),
117 (x, y) => format!("[{x}] + λ{y}"),
118 };
119 HomData {
120 name,
121 class,
122 hom_lift,
123 lambda_part,
124 }
125}
126
127fn main() -> anyhow::Result<()> {
128 ext::utils::init_logging()?;
129
130 eprintln!(
131 "We are going to compute <-, b, a> for all (-), where a is an element in Ext(M, k) and b \
132 and (-) are elements in Ext(k, k)."
133 );
134
135 let resolution = Arc::new(query_module(Some(algebra::AlgebraType::Milnor), true)?);
136
137 let (is_unit, unit) = ext::utils::get_unit(Arc::clone(&resolution))?;
138
139 let p = resolution.prime();
140
141 let res_lift = Arc::new(SecondaryResolution::new(Arc::clone(&resolution)));
142 let unit_lift = if is_unit {
143 Arc::clone(&res_lift)
144 } else {
145 let lift = SecondaryResolution::new(Arc::clone(&unit));
146 Arc::new(lift)
147 };
148
149 let HomData {
150 name: a_name,
151 class: _,
152 hom_lift: a,
153 lambda_part: a_lambda,
154 } = get_hom("a", Arc::clone(&res_lift), Arc::clone(&unit_lift));
155 let HomData {
156 name: b_name,
157 class: b_class,
158 hom_lift: b,
159 lambda_part: b_lambda,
160 } = get_hom("b", Arc::clone(&unit_lift), Arc::clone(&unit_lift));
161
162 let shift = Bidegree::s_t(
163 (a.underlying().shift + b.underlying().shift).s(),
164 (a.shift() + b.shift()).t(),
165 );
166
167 if !is_unit {
169 let res_max = Bidegree::n_s(
170 resolution.module(0).max_computed_degree(),
171 resolution.next_homological_degree() - 1,
172 );
173 unit.compute_through_stem(res_max - a.underlying().shift);
174 }
175
176 if is_unit {
177 res_lift.extend_all();
178 } else {
179 maybe_rayon::join(|| res_lift.extend_all(), || unit_lift.extend_all());
180 }
181
182 maybe_rayon::scope(|s| {
184 s.spawn(|_| {
185 a.underlying().extend_all();
186 a.extend_all();
187 });
188 s.spawn(|_| {
189 b.underlying().extend_all();
190 b.extend_all();
191 });
192 if let Some(a_lambda) = &a_lambda {
193 s.spawn(|_| a_lambda.extend_all());
194 }
195 if let Some(b_lambda) = &b_lambda {
196 s.spawn(|_| b_lambda.extend_all());
197 }
198 });
199
200 let res_sseq = Arc::new(res_lift.e3_page());
201 let unit_sseq = if is_unit {
202 Arc::clone(&res_sseq)
203 } else {
204 Arc::new(res_lift.e3_page())
205 };
206
207 let b_shift = b.underlying().shift;
208
209 let chain_homotopy = Arc::new(ChainHomotopy::new(a.underlying(), b.underlying()));
210 chain_homotopy.initialize_homotopies((b_shift + a.underlying().shift).s());
211
212 {
214 let v = a.product_nullhomotopy(a_lambda.as_deref(), &res_sseq, b_shift, b_class.as_slice());
215 let homotopy = chain_homotopy.homotopy(b_shift.s() + a.underlying().shift.s() - 1);
216 let htpy_source = a.shift() + b_shift;
217 homotopy.extend_by_zero(htpy_source.t() - 1);
218 homotopy.add_generators_from_rows(
219 htpy_source.t(),
220 v.into_iter()
221 .map(|x| FpVector::from_slice(p, &[x]))
222 .collect(),
223 );
224 }
225
226 chain_homotopy.extend_all();
227
228 let ch_lift = SecondaryChainHomotopy::new(
229 Arc::clone(&a),
230 Arc::clone(&b),
231 a_lambda.clone(),
232 b_lambda.clone(),
233 Arc::clone(&chain_homotopy),
234 );
235
236 if let Some(s) = ext::utils::secondary_job() {
237 ch_lift.compute_partial(s);
238 return Ok(());
239 }
240
241 ch_lift.extend_all();
242
243 fn get_page_data(sseq: &sseq::Sseq<2, sseq::Adams>, b: Bidegree) -> &fp::matrix::Subquotient {
244 let d = sseq.page_data(b);
245 &d[std::cmp::min(3, d.len() - 1)]
246 }
247
248 let mut scratch0: Vec<u32> = Vec::new();
249 let mut scratch1 = FpVector::new(p, 0);
250
251 let h_0 = ch_lift.algebra().p_tilde();
252
253 for c in unit.iter_stem() {
255 if !resolution.has_computed_bidegree(c + shift - Bidegree::s_t(2, 0))
256 || !resolution.has_computed_bidegree(c + shift + Bidegree::s_t(0, 1))
257 {
258 continue;
259 }
260
261 let source = c + shift - Bidegree::s_t(1, 0);
263
264 let source_num_gens = resolution.number_of_gens_in_bidegree(source);
265 let source_lambda_num_gens =
266 resolution.number_of_gens_in_bidegree(source + LAMBDA_BIDEGREE);
267
268 if source_num_gens + source_lambda_num_gens == 0 {
269 continue;
270 }
271
272 let target_num_gens = unit.number_of_gens_in_bidegree(c);
274 let target_lambda_num_gens = unit.number_of_gens_in_bidegree(c + LAMBDA_BIDEGREE);
275 let target_all_gens = target_num_gens + target_lambda_num_gens;
276
277 let prod_num_gens = unit.number_of_gens_in_bidegree(c + b_shift);
278 let prod_lambda_num_gens = unit.number_of_gens_in_bidegree(c + b_shift + LAMBDA_BIDEGREE);
279 let prod_all_gens = prod_num_gens + prod_lambda_num_gens;
280
281 let e3_kernel = {
282 let target_page_data = get_page_data(&unit_sseq, c);
283 let target_lambda_page_data = get_page_data(&unit_sseq, c + LAMBDA_BIDEGREE);
284 let product_lambda_page_data = get_page_data(&unit_sseq, c + b_shift + LAMBDA_BIDEGREE);
285
286 let e2_kernel: Subspace = {
290 let mut product_matrix = Matrix::new(
291 p,
292 target_page_data.subspace_dimension(),
293 target_num_gens + prod_num_gens,
294 );
295
296 let m0 = Matrix::from_vec(
297 p,
298 &b.underlying()
299 .get_map(c.s() + b.underlying().shift.s())
300 .hom_k(c.t()),
301 );
302 for (g, mut out) in target_page_data
303 .subspace_gens()
304 .zip_eq(product_matrix.iter_mut())
305 {
306 out.slice_mut(prod_num_gens, prod_num_gens + target_num_gens)
307 .add(g, 1);
308 for (i, v) in g.iter_nonzero() {
309 out.slice_mut(0, prod_num_gens).add(m0.row(i), v);
310 }
311 }
312 product_matrix.row_reduce();
313 product_matrix.compute_kernel(prod_num_gens)
314 };
315
316 {
318 let e2_ker_dim = e2_kernel.dimension();
320 let mut product_matrix = Matrix::new(
321 p,
322 e2_ker_dim + target_lambda_page_data.quotient_dimension(),
323 target_all_gens + prod_all_gens,
324 );
325
326 b.hom_k_with(
327 b_lambda.as_deref(),
328 Some(&unit_sseq),
329 c,
330 e2_kernel.basis(),
331 product_matrix
332 .slice_mut(0, e2_ker_dim, 0, prod_all_gens)
333 .iter_mut(),
334 );
335 for (v, mut t) in e2_kernel.basis().zip(product_matrix.iter_mut()) {
336 t.slice_mut(prod_all_gens, prod_all_gens + target_num_gens)
337 .assign(v);
338 }
339
340 let m = Matrix::from_vec(
342 p,
343 &b.underlying()
344 .get_map(b_shift.s() + c.s() + 1)
345 .hom_k(c.t() + 1),
346 );
347
348 let mut count = 0;
349 for (i, &v) in target_lambda_page_data.quotient_pivots().iter().enumerate() {
350 if v >= 0 {
351 continue;
352 }
353 let mut row = product_matrix.row_mut(e2_ker_dim + count as usize);
354 row.add_basis_element(prod_all_gens + target_num_gens + i, 1);
355 row.slice_mut(prod_num_gens, prod_all_gens).add(m.row(i), 1);
356 product_lambda_page_data
357 .reduce_by_quotient(row.slice_mut(prod_num_gens, prod_all_gens));
358 count += 1;
359 }
360
361 product_matrix.row_reduce();
362 product_matrix.compute_kernel(prod_all_gens)
363 }
364 };
365
366 if e3_kernel.dimension() == 0 {
367 continue;
368 }
369
370 let m0 = chain_homotopy.homotopy(source.s()).hom_k(c.t());
371 let mt = Matrix::from_vec(p, &chain_homotopy.homotopy(source.s() + 1).hom_k(c.t() + 1));
372 let m1 = Matrix::from_vec(
373 p,
374 &ch_lift.homotopies()[source.s() + 1].homotopies.hom_k(c.t()),
375 );
376 let mp = Matrix::from_vec(
377 p,
378 &resolution
379 .filtration_one_product(1, h_0, Bidegree::s_t(source.s(), c.t() + shift.t()))
380 .unwrap(),
381 );
382 let ma = a
383 .underlying()
384 .get_map(source.s())
385 .hom_k(c.t() + b_shift.t());
386 let mb = b.underlying().get_map(c.s() + b_shift.s()).hom_k(c.t());
387
388 for g in e3_kernel.iter() {
389 {
391 print!("<{a_name}, {b_name}, ");
392 let has_ext = {
393 let ext_part = g.restrict(0, target_num_gens);
394 if ext_part.iter_nonzero().count() > 0 {
395 print!(
396 "[{basis_string}]",
397 basis_string =
398 BidegreeElement::new(c, ext_part.to_owned()).to_basis_string()
399 );
400 true
401 } else {
402 false
403 }
404 };
405
406 let lambda_part = g.restrict(target_num_gens, target_all_gens);
407 let num_entries = lambda_part.iter_nonzero().count();
408 if num_entries > 0 {
409 if has_ext {
410 print!(" + ");
411 }
412 print!("λ");
413
414 let basis_string = BidegreeElement::new(
415 c + LAMBDA_BIDEGREE,
416 g.restrict(target_num_gens, target_all_gens).to_owned(),
417 )
418 .to_basis_string();
419 if num_entries == 1 {
420 print!("{basis_string}",);
421 } else {
422 print!("({basis_string})",);
423 }
424 }
425 print!("> = ±");
426 }
427
428 scratch0.clear();
429 scratch0.resize(source_num_gens, 0);
430 scratch1.set_scratch_vector_size(source_lambda_num_gens);
431
432 for (i, v) in g.restrict(0, target_num_gens).iter_nonzero() {
434 scratch0
435 .iter_mut()
436 .zip_eq(&m0[i])
437 .for_each(|(a, b)| *a += v * b);
438 scratch1.as_slice_mut().add(m1.row(i), v);
439 }
440 for (i, v) in g.restrict(target_num_gens, target_all_gens).iter_nonzero() {
441 scratch1.as_slice_mut().add(mt.row(i), v);
442 }
443 {
445 let sign = p * p - 1;
446 let out = b.product_nullhomotopy(b_lambda.as_deref(), &unit_sseq, c, g);
447 for (i, v) in out.iter_nonzero() {
448 scratch0
449 .iter_mut()
450 .zip_eq(&ma[i])
451 .for_each(|(a, b)| *a += v * b * sign);
452 }
453 }
454
455 for (i, v) in scratch0.iter().enumerate() {
456 let extra = *v / p;
457 scratch1.as_slice_mut().add(mp.row(i), extra % p);
458 }
459
460 print!("[{}]", scratch0.iter().map(|x| *x % p).format(", "));
461
462 scratch0.clear();
465 scratch0.resize(prod_num_gens, 0);
466
467 for (i, v) in g.restrict(0, target_num_gens).iter_nonzero() {
468 scratch0
469 .iter_mut()
470 .zip_eq(&mb[i])
471 .for_each(|(a, b)| *a += v * b);
472 }
473 for (i, v) in scratch0.iter().enumerate() {
474 let extra = (*v / p) % p;
475 if extra == 0 {
476 continue;
477 }
478 for gen_idx in 0..source_lambda_num_gens {
479 let m = a.underlying().get_map((source + LAMBDA_BIDEGREE).s());
480 let dx = m.output((source + LAMBDA_BIDEGREE).t(), gen_idx);
481 let idx = unit.module((c + shift).s()).operation_generator_to_index(
482 1,
483 h_0,
484 (c + shift).t(),
485 i,
486 );
487 scratch1.add_basis_element(gen_idx, dx.entry(idx));
488 }
489 }
490 println!(" + λ{scratch1}");
491 }
492 }
493 Ok(())
494}