algebra/module/
hom_module.rs1use std::sync::Arc;
2
3use bivec::BiVec;
4use fp::vector::FpSliceMut;
5use once::OnceBiVec;
6
7use crate::{
8 algebra::Field,
9 module::{FreeModule, Module, block_structure::BlockStructure},
10};
11
12pub struct HomModule<M: Module> {
18 algebra: Arc<Field>,
19 source: Arc<FreeModule<M::Algebra>>,
20 target: Arc<M>,
21 pub block_structures: OnceBiVec<BlockStructure>,
22}
23
24impl<M: Module> std::fmt::Display for HomModule<M> {
25 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
26 write!(f, "Hom({}, {})", self.source, self.target)
27 }
28}
29
30impl<M: Module> HomModule<M> {
31 pub fn new(source: Arc<FreeModule<M::Algebra>>, target: Arc<M>) -> Self {
32 let p = source.prime();
33 let algebra = Arc::new(Field::new(p));
34 let min_degree = source.min_degree()
35 - target
36 .max_degree()
37 .expect("HomModule requires target to be bounded");
38 Self {
39 algebra,
40 source,
41 target,
42 block_structures: OnceBiVec::new(min_degree), }
44 }
45
46 pub fn source(&self) -> Arc<FreeModule<M::Algebra>> {
47 Arc::clone(&self.source)
48 }
49
50 pub fn target(&self) -> Arc<M> {
51 Arc::clone(&self.target)
52 }
53}
54
55impl<M: Module> Module for HomModule<M> {
56 type Algebra = Field;
57
58 fn algebra(&self) -> Arc<Self::Algebra> {
59 Arc::clone(&self.algebra)
60 }
61
62 fn min_degree(&self) -> i32 {
63 self.block_structures.min_degree()
64 }
65
66 fn max_computed_degree(&self) -> i32 {
67 self.source.max_computed_degree() - self.target.max_degree().unwrap()
68 }
69
70 fn compute_basis(&self, degree: i32) {
71 self.source
72 .compute_basis(degree + self.target.max_degree().unwrap());
73 self.block_structures.extend(degree, |d| {
74 let mut block_sizes = BiVec::new(self.target.min_degree() + d);
75 block_sizes.extend_with(self.target.max_degree().unwrap() + d, |gen_deg| {
76 vec![
77 self.target.dimension(gen_deg - d);
78 if self.source.max_computed_degree() >= gen_deg {
79 self.source.number_of_gens_in_degree(gen_deg)
80 } else {
81 0
82 }
83 ]
84 });
85 BlockStructure::new(&block_sizes)
86 });
87 }
88
89 fn dimension(&self, degree: i32) -> usize {
90 self.block_structures[degree].total_dimension()
91 }
92
93 fn act_on_basis(
94 &self,
95 mut result: FpSliceMut,
96 coeff: u32,
97 op_degree: i32,
98 op_index: usize,
99 _mod_degree: i32,
100 mod_index: usize,
101 ) {
102 assert_eq!(op_degree, 0);
103 assert_eq!(op_index, 0);
104 result.add_basis_element(mod_index, coeff);
105 }
106
107 fn basis_element_to_string(&self, degree: i32, idx: usize) -> String {
108 let gen_basis_elt = self.block_structures[degree].index_to_generator_basis_elt(idx);
109 let gen_deg = gen_basis_elt.generator_degree;
110 let gen_idx = gen_basis_elt.generator_index;
111 let gen_mod_idx = self
112 .source
113 .operation_generator_to_index(0, 0, gen_deg, gen_idx);
114 let basis_deg = gen_deg - degree;
115 let basis_idx = gen_basis_elt.basis_index;
116 format!(
117 "{}*⊗{}",
118 self.source.basis_element_to_string(gen_deg, gen_mod_idx),
119 self.target.basis_element_to_string(basis_deg, basis_idx),
120 )
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127 use crate::{MilnorAlgebra, module::FDModule};
128
129 #[test]
130 fn test_hom_dim() {
131 const NUM_GENS: [usize; 3] = [1, 2, 1];
132 const TARGET_DIM: [usize; 3] = [1, 3, 4];
133
134 let algebra = Arc::new(MilnorAlgebra::new(fp::prime::TWO, false));
135 let f = Arc::new(FreeModule::new(Arc::clone(&algebra), "F0".to_string(), 0));
136 let m = Arc::new(
137 FDModule::from_json(Arc::clone(&algebra), &crate::tests::joker_json()).unwrap(),
138 );
139
140 for (deg, num_gens) in NUM_GENS.into_iter().enumerate() {
141 f.add_generators(deg as i32, num_gens, None);
142 }
143 f.compute_basis(NUM_GENS.len() as i32 - 1);
144
145 let hom = HomModule::new(f, m);
146 assert_eq!(hom.min_degree(), -4);
147 assert_eq!(hom.max_computed_degree(), -2);
148 hom.compute_basis(-2);
149
150 for (&target_dim, deg) in
151 std::iter::zip(&TARGET_DIM, hom.min_degree()..=hom.max_computed_degree())
152 {
153 assert_eq!(hom.dimension(deg), target_dim);
154 }
155 }
156}