1#![deny(clippy::use_self, unsafe_op_in_unsafe_fn)]
7
8pub mod module;
9pub mod steenrod_evaluator;
10pub(crate) mod steenrod_parser;
11
12mod algebra;
13
14pub use crate::algebra::*;
15
16pub(crate) fn module_gens_from_json(
17 gens: &serde_json::Value,
18) -> (
19 bivec::BiVec<usize>,
20 bivec::BiVec<Vec<String>>,
21 impl for<'a> Fn(&'a str) -> anyhow::Result<(i32, usize)> + '_,
22) {
23 use anyhow::anyhow;
24 let gens = gens.as_object().unwrap();
25
26 let degrees = gens
27 .iter()
28 .map(|(_, x)| x.as_i64().unwrap() as i32)
29 .collect::<Vec<_>>();
30
31 let min_degree = degrees.iter().copied().min().unwrap_or(0);
32 let max_degree = degrees.iter().copied().max().unwrap_or(-1) + 1;
33
34 let mut gen_to_idx = rustc_hash::FxHashMap::default();
35 let mut graded_dimension = bivec::BiVec::with_capacity(min_degree, max_degree);
36 let mut gen_names = bivec::BiVec::with_capacity(min_degree, max_degree);
37
38 for _ in min_degree..max_degree {
39 graded_dimension.push(0);
40 gen_names.push(vec![]);
41 }
42
43 for (name, degree) in gens {
44 let degree = degree.as_i64().unwrap() as i32;
45 gen_names[degree].push(name.clone());
46 gen_to_idx.insert(name.clone(), (degree, graded_dimension[degree]));
47 graded_dimension[degree] += 1;
48 }
49 (graded_dimension, gen_names, move |g| {
50 gen_to_idx
51 .get(g)
52 .copied()
53 .ok_or_else(|| anyhow!("Invalid generator: {g}"))
54 })
55}
56
57#[cfg(test)]
58pub mod tests {
59 pub fn joker_json() -> serde_json::Value {
60 use serde_json::json;
61
62 json!({
63 "type" : "finite dimensional module",
64 "p": 2,
65 "gens": {
66 "x0": 0,
67 "x1": 1,
68 "x2": 2,
69 "x3": 3,
70 "x4": 4
71 },
72 "actions": [
73 "Sq1 x0 = x1",
74 "Sq2 x1 = x3",
75 "Sq1 x3 = x4",
76 "Sq2 x0 = x2",
77 "Sq2 x2 = x4"
78 ]
79 })
80 }
81}