massey/
massey.rs

1//! Computes the triple Massey product up to a sign
2//!
3//! This is optimized to compute <a, b, -> for fixed a, b and all -, where a and b have small
4//! degree.
5
6use std::sync::Arc;
7
8use ext::{
9    chain_complex::{ChainComplex, ChainHomotopy, FreeChainComplex},
10    resolution_homomorphism::ResolutionHomomorphism,
11};
12use fp::matrix::{AugmentedMatrix, Matrix};
13use sseq::coordinates::{Bidegree, BidegreeElement, BidegreeGenerator};
14
15fn main() -> anyhow::Result<()> {
16    ext::utils::init_logging()?;
17
18    let resolution = Arc::new(ext::utils::query_module(None, true)?);
19    let p = resolution.prime();
20
21    let (is_unit, unit) = ext::utils::get_unit(Arc::clone(&resolution))?;
22
23    eprintln!("\nComputing Massey products <a, b, ->");
24    eprintln!("\nEnter a:");
25
26    let a = Bidegree::n_s(
27        query::raw("n of Ext class a", str::parse),
28        query::raw("s of Ext class a", str::parse::<std::num::NonZeroI32>).get(),
29    );
30
31    unit.compute_through_stem(a);
32
33    let a_class = query::vector("Input Ext class a", unit.number_of_gens_in_bidegree(a));
34
35    eprintln!("\nEnter b:");
36
37    let b = Bidegree::n_s(
38        query::raw("n of Ext class b", str::parse),
39        query::raw("s of Ext class b", str::parse::<std::num::NonZeroI32>).get(),
40    );
41
42    unit.compute_through_stem(b);
43
44    let b_class = query::vector("Input Ext class b", unit.number_of_gens_in_bidegree(b));
45
46    // The Massey product shifts the bidegree by this amount
47    let shift = a + b - Bidegree::s_t(1, 0);
48
49    if !is_unit {
50        unit.compute_through_stem(shift);
51    }
52
53    if !resolution.has_computed_bidegree(shift + Bidegree::s_t(0, resolution.min_degree())) {
54        eprintln!("No computable bidegrees");
55        return Ok(());
56    }
57
58    let b_hom = Arc::new(ResolutionHomomorphism::from_class(
59        String::new(),
60        Arc::clone(&unit),
61        Arc::clone(&unit),
62        b,
63        &b_class,
64    ));
65
66    b_hom.extend_through_stem(shift);
67
68    let offset_a = unit.module(a.s()).generator_offset(a.t(), a.t(), 0);
69    for c in resolution.iter_nonzero_stem() {
70        if !resolution.has_computed_bidegree(c + shift) {
71            continue;
72        }
73
74        let tot = c + shift;
75
76        let num_gens = resolution.number_of_gens_in_bidegree(c);
77        let product_num_gens = resolution.number_of_gens_in_bidegree(b + c);
78        let target_num_gens = resolution.number_of_gens_in_bidegree(tot);
79        if target_num_gens == 0 {
80            continue;
81        }
82
83        let mut answers = vec![vec![0; target_num_gens]; num_gens];
84        let mut product = AugmentedMatrix::<2>::new(p, num_gens, [product_num_gens, num_gens]);
85        product.segment(1, 1).add_identity();
86
87        let mut matrix = Matrix::new(p, num_gens, 1);
88        for (idx, answer_row) in answers.iter_mut().enumerate() {
89            let hom = Arc::new(ResolutionHomomorphism::new(
90                String::new(),
91                Arc::clone(&resolution),
92                Arc::clone(&unit),
93                c,
94            ));
95
96            matrix.row_mut(idx).set_entry(0, 1);
97            hom.extend_step(c, Some(&matrix));
98            matrix.row_mut(idx).set_entry(0, 0);
99
100            hom.extend_through_stem(tot);
101
102            let homotopy = ChainHomotopy::new(Arc::clone(&hom), Arc::clone(&b_hom));
103
104            homotopy.extend(tot);
105
106            let last = homotopy.homotopy(tot.s());
107            for (i, answer) in answer_row.iter_mut().enumerate() {
108                let output = last.output(tot.t(), i);
109                for (k, &v) in a_class.iter().enumerate() {
110                    if v != 0 {
111                        *answer += v * output.entry(offset_a + k);
112                    }
113                }
114            }
115
116            for (k, &v) in b_class.iter().enumerate() {
117                if v != 0 {
118                    let g = BidegreeGenerator::new(b, k);
119                    hom.act(product.row_mut(idx).slice_mut(0, product_num_gens), v, g);
120                }
121            }
122        }
123        product.row_reduce();
124        let kernel = product.compute_kernel();
125
126        for row in kernel.iter() {
127            let c_element = BidegreeElement::new(c, row.to_owned());
128            print!(
129                "<a, b, {c_string}> = [",
130                c_string = c_element.to_basis_string()
131            );
132
133            #[allow(clippy::needless_range_loop)]
134            for i in 0..target_num_gens {
135                let mut entry = 0;
136                for (j, v) in row.iter().enumerate() {
137                    entry += v * answers[j][i];
138                }
139                if i != 0 {
140                    print!(", ");
141                }
142                print!("{}", entry % p);
143            }
144            println!("]");
145        }
146    }
147
148    Ok(())
149}