comodules/comodule/
kcomodule.rs

1use std::{collections::HashMap, sync::Arc};
2
3use ahash::RandomState;
4use serde::{Deserialize, Serialize};
5
6use crate::linalg::{
7    field::Field,
8    graded::{BasisElement, GradedLinearMap, GradedVectorSpace},
9    grading::Grading,
10    matrix::Matrix,
11};
12
13use super::{
14    kcoalgebra::kCoalgebra, kmorphism::kComoduleMorphism, ktensor::kTensor, traits::Comodule,
15};
16
17#[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize)]
18#[allow(non_camel_case_types)]
19pub struct kBasisElement {
20    pub name: String,
21    pub generator: bool,
22    pub primitive: Option<usize>,
23    pub generated_index: usize,
24}
25
26impl BasisElement for kBasisElement {}
27
28#[derive(Clone, PartialEq)]
29#[allow(non_camel_case_types)]
30pub struct kComodule<G: Grading, F: Field, M: Matrix<F>> {
31    pub coalgebra: Arc<kCoalgebra<G, F, M>>,
32    pub space: GradedVectorSpace<G, kBasisElement>,
33    pub coaction: GradedLinearMap<G, F, M>,
34    pub tensor: kTensor<G>,
35}
36
37impl<G: Grading, F: Field, M: Matrix<F>> std::fmt::Debug for kComodule<G, F, M> {
38    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39        write!(f, "{:?}", self.space.0)
40    }
41}
42
43impl<G: Grading, F: Field, M: Matrix<F>> kComodule<G, F, M> {
44    pub fn verify(&self) -> bool {
45        for (&(m_gr, m_id), map) in &self.tensor.construct {
46            let &(t_gr, t_id) = map.get(&(G::zero(), 0)).unwrap();
47            if t_gr != m_gr {
48                return false;
49            };
50
51            let val = self.coaction.maps.get(&t_gr).unwrap().get(m_id, t_id);
52            if val != F::one() {
53                return false;
54            };
55        }
56        true
57    }
58
59    pub fn new(
60        coalgebra: Arc<kCoalgebra<G, F, M>>,
61        space: GradedVectorSpace<G, kBasisElement>,
62        coaction: GradedLinearMap<G, F, M>,
63        tensor: kTensor<G>,
64    ) -> Self {
65        let com = Self {
66            coalgebra,
67            space,
68            coaction,
69            tensor,
70        };
71        debug_assert!(com.verify());
72        com
73    }
74
75    pub fn find_cogens(&self, limit: G) -> usize {
76        let mut temp_coac = self.coaction.clone();
77
78        self.space.0.iter().for_each(|(g, els)| {
79            (0..els.len()).into_iter().for_each(|domain| {
80                let (_, codomain) = self.tensor.construct[&(*g, domain)][&(G::zero(), 0)];
81                temp_coac
82                    .maps
83                    .get_mut(&g)
84                    .unwrap()
85                    .set(domain, codomain, F::zero());
86            })
87        });
88
89        temp_coac
90            .maps
91            .iter()
92            .filter(|(&gr, _)| gr <= limit)
93            .map(|(_, map)| {
94                let kernel = map.kernel();
95                kernel.codomain()
96            })
97            .sum()
98    }
99}
100
101impl<G: Grading, F: Field, M: Matrix<F>> Comodule<G> for kComodule<G, F, M> {
102    type Element = kBasisElement;
103    type Coalgebra = kCoalgebra<G, F, M>;
104    type Morphism = kComoduleMorphism<G, F, M>;
105
106    fn get_generators(&self) -> Vec<(usize, G, Option<String>)> {
107        self.space
108            .0
109            .iter()
110            .flat_map(|(k, v)| {
111                v.iter().filter_map(|b| {
112                    if b.generator {
113                        Some((b.generated_index, *k, None))
114                    } else {
115                        None
116                    }
117                })
118            })
119            .collect()
120    }
121
122    fn zero_comodule(coalgebra: Arc<Self::Coalgebra>) -> Self {
123        Self {
124            coalgebra: coalgebra,
125            space: GradedVectorSpace::new(),
126            coaction: GradedLinearMap::empty(),
127            tensor: kTensor::new(),
128        }
129    }
130
131    fn fp_comodule(coalgebra: Arc<Self::Coalgebra>) -> Self {
132        let zero = G::zero();
133
134        // (zero,
135        let el = kBasisElement {
136            name: "fp".to_string(),
137            generator: false,
138            primitive: None,
139            generated_index: 0,
140        };
141
142        let space_map: HashMap<G, Vec<kBasisElement>, RandomState> =
143            [(zero, vec![el])].into_iter().collect();
144        let space = GradedVectorSpace::from(space_map);
145
146        let coact_map: HashMap<G, M, RandomState> = [(zero, M::identity(1))].into_iter().collect();
147        let coaction = GradedLinearMap::from(coact_map);
148
149        debug_assert_eq!(
150            coalgebra
151                .space
152                .0
153                .get(&zero)
154                .expect("Coalgebra has no element in grade zero")
155                .len(),
156            1,
157            "Coalgebra is not a connected coalgebra"
158        );
159
160        let mut dimensions = HashMap::default();
161        dimensions.insert(zero, 1);
162
163        let mut construct = HashMap::default();
164        let mut first_entry = HashMap::default();
165        first_entry.insert((zero, 0), (zero, 0));
166        construct.insert((zero, 0), first_entry);
167
168        let mut deconstruct = HashMap::default();
169        deconstruct.insert((zero, 0), ((zero, 0), (zero, 0)));
170
171        let tensor = kTensor {
172            construct,
173            deconstruct,
174            dimensions,
175        };
176
177        Self {
178            coalgebra,
179            space,
180            coaction,
181            tensor,
182        }
183    }
184
185    fn direct_sum(&mut self, other: &mut Self) {
186        self.coaction.block_sum(&mut other.coaction);
187
188        let self_dimensions = self.space.0.iter().map(|(g, v)| (*g, v.len())).collect();
189
190        other.space.0.iter_mut().for_each(|(g, other_els)| {
191            self.space
192                .0
193                .entry(*g)
194                .and_modify(|self_els| {
195                    self_els.extend(other_els.drain(0..));
196                })
197                .or_insert(other_els.drain(0..).collect());
198        });
199
200        self.tensor.direct_sum(&mut other.tensor, &self_dimensions);
201
202        debug_assert!(self.verify());
203    }
204
205    fn cofree_comodule(coalgebra: Arc<Self::Coalgebra>, index: usize, grade: G, limit: G) -> Self {
206        let coaction: HashMap<G, M, RandomState> = coalgebra
207            .coaction
208            .maps
209            .iter()
210            .filter_map(|(g, v)| {
211                let sum = *g + grade;
212                if sum <= limit {
213                    Some((*g + grade, v.clone()))
214                } else {
215                    None
216                }
217            })
218            .collect();
219        let space = coalgebra
220            .space
221            .0
222            .iter()
223            .filter_map(|(g, v)| {
224                let sum = *g + grade;
225                if sum <= limit {
226                    let k_basis: Vec<kBasisElement> = v
227                        .iter()
228                        .map(|basis| {
229                            let mut el = basis.clone();
230                            el.generated_index = index;
231                            el
232                        })
233                        .collect();
234                    Some((*g + grade, k_basis))
235                } else {
236                    None
237                }
238            })
239            .collect();
240        let tensor = coalgebra.tensor.add_and_restrict(grade, limit);
241
242        kComodule::new(
243            coalgebra,
244            GradedVectorSpace(space),
245            GradedLinearMap::from(coaction),
246            tensor,
247        )
248    }
249}