algebra/module/
finite_dimensional_module.rs

1use std::{fmt::Write as _, sync::Arc};
2
3use anyhow::{Context, anyhow};
4use bivec::BiVec;
5use fp::vector::{FpSliceMut, FpVector};
6use serde::Deserialize;
7use serde_json::{json, value::Value};
8
9use crate::{
10    algebra::{Algebra, GeneratedAlgebra},
11    module::{Module, ModuleFailedRelationError, ZeroModule},
12};
13
14pub struct FiniteDimensionalModule<A: Algebra> {
15    algebra: Arc<A>,
16    pub name: String,
17    graded_dimension: BiVec<usize>,
18    gen_names: BiVec<Vec<String>>,
19    // This goes input_degree --> output_degree --> operation --> input_index --> Vector
20    actions: BiVec<BiVec<Vec<Vec<FpVector>>>>,
21}
22
23impl<A: Algebra> std::fmt::Display for FiniteDimensionalModule<A> {
24    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
25        write!(f, "{}", self.name)
26    }
27}
28
29impl<A: Algebra> Clone for FiniteDimensionalModule<A> {
30    fn clone(&self) -> Self {
31        Self {
32            algebra: Arc::clone(&self.algebra),
33            name: self.name.clone(),
34            graded_dimension: self.graded_dimension.clone(),
35            gen_names: self.gen_names.clone(),
36            actions: self.actions.clone(),
37        }
38    }
39}
40
41impl<A: Algebra> PartialEq for FiniteDimensionalModule<A> {
42    fn eq(&self, other: &Self) -> bool {
43        self.test_equal(other).is_ok()
44    }
45}
46
47impl<A: Algebra> Eq for FiniteDimensionalModule<A> {}
48
49impl<A: Algebra> FiniteDimensionalModule<A> {
50    pub fn test_equal(&self, other: &Self) -> Result<(), String> {
51        if self.graded_dimension != other.graded_dimension {
52            if self.graded_dimension.min_degree() != other.graded_dimension.min_degree() {
53                return Err(format!(
54                    "Min degrees disagree. left.min_degree() = {} but right.min_degree() = {}.",
55                    self.graded_dimension.min_degree(),
56                    other.graded_dimension.min_degree()
57                ));
58            }
59            let mut disagreements = vec![];
60            for i in self.graded_dimension.min_degree()
61                ..std::cmp::max(self.graded_dimension.len(), other.graded_dimension.len())
62            {
63                if self.graded_dimension.get(i).copied().unwrap_or(0)
64                    != other.graded_dimension.get(i).copied().unwrap_or(0)
65                {
66                    disagreements.push(i);
67                }
68            }
69            if !disagreements.is_empty() {
70                return Err(format!(
71                    "Graded dimensions disagree in positions {:?}. Left has graded \
72                        dimensions:\n    {:?}\nRight has graded dimension:\n    {:?}\n",
73                    disagreements, self.graded_dimension, other.graded_dimension
74                ));
75            }
76        }
77        let max_degree = std::cmp::min(self.actions.len(), other.actions.len());
78        if self.actions != other.actions {
79            // actions goes input_degree --> output_degree --> operation --> input_index --> Vector
80            let mut disagreements = vec![];
81            for input_degree in self.actions.min_degree()..max_degree {
82                for output_degree in self.actions[input_degree].min_degree()..max_degree {
83                    for operation in 0..self.actions[input_degree][output_degree].len() {
84                        for input_index in
85                            0..self.actions[input_degree][output_degree][operation].len()
86                        {
87                            let self_action =
88                                &self.actions[input_degree][output_degree][operation][input_index];
89                            let other_action =
90                                &other.actions[input_degree][output_degree][operation][input_index];
91                            if self_action != other_action {
92                                disagreements.push((
93                                    input_degree,
94                                    output_degree,
95                                    operation,
96                                    input_index,
97                                    self_action,
98                                    other_action,
99                                ));
100                            }
101                        }
102                    }
103                }
104            }
105
106            if !disagreements.is_empty() {
107                let mut err_string = "Actions disagree.\n".to_string();
108                for x in disagreements {
109                    let _ = write!(
110                        err_string,
111                        "  {} * {} disagreement.\n    Left: {}\n    Right: {}\n",
112                        self.algebra.basis_element_to_string(x.1 - x.0, x.2),
113                        self.basis_element_to_string(x.0, x.3),
114                        self.element_to_string(x.1, x.4.as_slice()),
115                        self.element_to_string(x.1, x.5.as_slice())
116                    );
117                }
118                return Err(err_string);
119            }
120        }
121        Ok(())
122    }
123}
124
125impl<A: Algebra> Module for FiniteDimensionalModule<A> {
126    type Algebra = A;
127
128    fn algebra(&self) -> Arc<Self::Algebra> {
129        Arc::clone(&self.algebra)
130    }
131
132    fn min_degree(&self) -> i32 {
133        self.graded_dimension.min_degree()
134    }
135
136    fn max_computed_degree(&self) -> i32 {
137        i32::MAX
138    }
139
140    fn compute_basis(&self, _degree: i32) {}
141
142    fn dimension(&self, degree: i32) -> usize {
143        if degree < self.graded_dimension.min_degree() {
144            return 0;
145        }
146        if degree > self.graded_dimension.max_degree() {
147            return 0;
148        }
149        self.graded_dimension[degree]
150    }
151
152    fn basis_element_to_string(&self, degree: i32, idx: usize) -> String {
153        self.gen_names[degree][idx].clone()
154    }
155
156    fn act_on_basis(
157        &self,
158        mut result: FpSliceMut,
159        coeff: u32,
160        op_degree: i32,
161        op_index: usize,
162        mod_degree: i32,
163        mod_index: usize,
164    ) {
165        assert!(op_index < self.algebra().dimension(op_degree));
166        assert!(mod_index < self.dimension(mod_degree));
167        let output_dimension = self.dimension(mod_degree + op_degree);
168        if output_dimension == 0 {
169            return;
170        }
171        if op_degree == 0 {
172            // We assume our algebras are connected so just add input to output.
173            result.add_basis_element(mod_index, coeff);
174            return;
175        }
176        let output = self.action(op_degree, op_index, mod_degree, mod_index);
177        result.add(output.as_slice(), coeff);
178    }
179
180    fn max_degree(&self) -> Option<i32> {
181        Some(self.graded_dimension.max_degree())
182    }
183}
184
185impl<A: Algebra> ZeroModule for FiniteDimensionalModule<A> {
186    fn zero_module(algebra: Arc<A>, min_degree: i32) -> Self {
187        Self::new(algebra, "zero".to_string(), BiVec::new(min_degree))
188    }
189}
190
191impl<A: Algebra> FiniteDimensionalModule<A> {
192    pub fn new(algebra: Arc<A>, name: String, graded_dimension: BiVec<usize>) -> Self {
193        let min_degree = graded_dimension.min_degree();
194        let max_degree = graded_dimension.len();
195        let degree_difference = max_degree - min_degree;
196        algebra.compute_basis(degree_difference);
197        let mut gen_names = BiVec::with_capacity(min_degree, max_degree);
198        for (i, dim) in graded_dimension.iter_enum() {
199            let mut names = Vec::with_capacity(*dim);
200            for j in 0..*dim {
201                names.push(format!("x{i}_{j}"));
202            }
203            gen_names.push(names);
204        }
205        let actions = Self::allocate_actions(&algebra, &graded_dimension);
206        Self {
207            algebra,
208            name,
209            graded_dimension,
210            gen_names,
211            actions,
212        }
213    }
214
215    pub fn set_basis_element_name(&mut self, degree: i32, idx: usize, name: String) {
216        self.gen_names[degree][idx] = name;
217    }
218
219    fn allocate_actions(
220        algebra: &Arc<A>,
221        graded_dimension: &BiVec<usize>,
222    ) -> BiVec<BiVec<Vec<Vec<FpVector>>>> {
223        let min_degree = graded_dimension.min_degree();
224        let max_degree = graded_dimension.len();
225        let mut result: BiVec<BiVec<Vec<Vec<FpVector>>>> =
226            BiVec::with_capacity(min_degree, max_degree);
227
228        for input_degree in min_degree..max_degree {
229            let mut outputs_vec: BiVec<Vec<Vec<FpVector>>> =
230                BiVec::with_capacity(input_degree, max_degree);
231            // We assume our algebra is connected, so we can manually fill in the first entry.
232            let number_of_inputs = graded_dimension[input_degree];
233            let mut ops_vec: Vec<Vec<FpVector>> = vec![Vec::with_capacity(number_of_inputs)];
234            for i in 0..number_of_inputs {
235                let mut result = FpVector::new(algebra.prime(), number_of_inputs);
236                result.set_entry(i, 1);
237                ops_vec[0].push(result);
238            }
239            outputs_vec.push(ops_vec);
240
241            for output_degree in input_degree + 1..max_degree {
242                let op_deg = output_degree - input_degree;
243                let number_of_operations = algebra.dimension(op_deg);
244                let number_of_inputs = graded_dimension[input_degree];
245                let number_of_outputs = graded_dimension[output_degree];
246
247                outputs_vec.push(vec![
248                    vec![
249                        FpVector::new(algebra.prime(), number_of_outputs);
250                        number_of_inputs
251                    ];
252                    number_of_operations
253                ]);
254            }
255            assert!(outputs_vec.len() == max_degree);
256            result.push(outputs_vec);
257        }
258        assert!(result.len() == max_degree);
259        result
260    }
261
262    pub fn add_generator(&mut self, degree: i32, name: String) {
263        let old_max_degree = self.max_degree().unwrap();
264        let algebra = self.algebra();
265
266        self.graded_dimension.extend_with(degree, |_| 0);
267        self.graded_dimension[degree] += 1;
268
269        self.gen_names.extend_with(degree, |_| Vec::new());
270        self.gen_names[degree].push(name);
271
272        let min_degree = self.graded_dimension.min_degree();
273        let max_degree = self.graded_dimension.len();
274
275        // Now allocate actions
276        if old_max_degree < degree {
277            self.actions.reserve((degree - old_max_degree) as usize);
278            for input_degree in min_degree..max_degree {
279                if input_degree <= old_max_degree {
280                    self.actions[input_degree].reserve((degree - old_max_degree) as usize);
281                } else {
282                    self.actions
283                        .push(BiVec::with_capacity(input_degree, max_degree));
284
285                    // We assume our algebra is connected, so we can manually fill in the first entry.
286                    let number_of_inputs = self.dimension(input_degree);
287                    let mut ops_vec: Vec<Vec<FpVector>> =
288                        vec![Vec::with_capacity(number_of_inputs)];
289                    for i in 0..number_of_inputs {
290                        let mut result = FpVector::new(algebra.prime(), number_of_inputs);
291                        result.set_entry(i, 1);
292                        ops_vec[0].push(result);
293                    }
294                    self.actions[input_degree].push(ops_vec);
295                }
296
297                for output_degree in std::cmp::max(input_degree + 1, old_max_degree + 1)..max_degree
298                {
299                    // This code is copied from allocate_actions
300                    let op_deg = output_degree - input_degree;
301                    let number_of_operations = algebra.dimension(op_deg);
302                    let number_of_inputs = self.dimension(input_degree);
303                    let number_of_outputs = self.dimension(output_degree);
304
305                    self.actions[input_degree].push(vec![
306                        vec![
307                            FpVector::new(
308                                algebra.prime(),
309                                number_of_outputs
310                            );
311                            number_of_inputs
312                        ];
313                        number_of_operations
314                    ]);
315                }
316            }
317        } else {
318            let new_dim = self.dimension(degree);
319
320            // input_degree = degree
321            for output_degree in min_degree..max_degree {
322                let number_of_outputs = self.dimension(output_degree);
323                // iterate over operations
324                for v in &mut self.actions[degree][output_degree] {
325                    v.push(FpVector::new(algebra.prime(), number_of_outputs));
326                }
327            }
328            // output_degree = degree
329            for input_degree in min_degree..max_degree {
330                // iterate over operations
331                for v in &mut self.actions[input_degree][degree] {
332                    // Iterate over input index
333                    for w in v {
334                        w.extend_len(new_dim);
335                    }
336                }
337            }
338
339            // input_degree = output_degree = degree. We already extend everything to the right
340            // dimension. We just need to set the identity action
341            self.actions[degree][degree][0][new_dim - 1].set_entry(new_dim - 1, 1);
342        }
343    }
344
345    pub fn string_to_basis_element(&self, string: &str) -> Option<(i32, usize)> {
346        for (i, v) in self.gen_names.iter_enum() {
347            for (j, n) in v.iter().enumerate() {
348                if n == string {
349                    return Some((i, j));
350                }
351            }
352        }
353        None
354    }
355
356    pub fn set_action(
357        &mut self,
358        operation_degree: i32,
359        operation_idx: usize,
360        input_degree: i32,
361        input_idx: usize,
362        output: &[u32],
363    ) {
364        assert!(operation_idx < self.algebra.dimension(operation_degree));
365        assert!(input_idx < self.dimension(input_degree));
366        let output_degree = input_degree + operation_degree;
367        // (in_deg) -> (out_deg) -> (op_index) -> (in_index) -> Vector
368        let output_vector =
369            &mut self.actions[input_degree][output_degree][operation_idx][input_idx];
370        output_vector.copy_from_slice(output);
371    }
372
373    /// This function will panic if you call it with input such that `module.dimension(input_degree +
374    /// operation_degree) = 0`.
375    pub fn action(
376        &self,
377        operation_degree: i32,
378        operation_idx: usize,
379        input_degree: i32,
380        input_idx: usize,
381    ) -> &FpVector {
382        let output_degree = input_degree + operation_degree;
383        &self.actions[input_degree][output_degree][operation_idx][input_idx]
384    }
385
386    /// This function will panic if you call it with input such that `module.dimension(input_degree +
387    /// operation_degree) = 0`.
388    pub fn action_mut(
389        &mut self,
390        operation_degree: i32,
391        operation_idx: usize,
392        input_degree: i32,
393        input_idx: usize,
394    ) -> &mut FpVector {
395        let output_degree = input_degree + operation_degree;
396        &mut self.actions[input_degree][output_degree][operation_idx][input_idx]
397    }
398}
399
400impl<M: Module> From<&M> for FiniteDimensionalModule<M::Algebra> {
401    /// This should really by try_from but orphan rules prohibit this
402    fn from(module: &M) -> Self {
403        let min_degree = module.min_degree();
404        let max_degree = module
405            .max_degree()
406            .expect("Can only convert to fininte dimensional module if bounded");
407        module.compute_basis(max_degree);
408
409        let mut graded_dimension = BiVec::with_capacity(min_degree, max_degree + 1);
410        for t in min_degree..=max_degree {
411            graded_dimension.push(module.dimension(t));
412        }
413        let mut result = Self::new(module.algebra(), module.to_string(), graded_dimension);
414        for t in min_degree..=max_degree {
415            for idx in 0..result.dimension(t) {
416                result.set_basis_element_name(t, idx, module.basis_element_to_string(t, idx));
417            }
418        }
419
420        let algebra = module.algebra();
421        for input_degree in min_degree..=max_degree {
422            for output_degree in (input_degree + 1)..=max_degree {
423                let output_dimension = result.dimension(output_degree);
424                if output_dimension == 0 {
425                    continue;
426                }
427                let op_degree = output_degree - input_degree;
428
429                for input_idx in 0..result.dimension(input_degree) {
430                    for op_idx in 0..algebra.dimension(op_degree) {
431                        let output_vec: &mut FpVector =
432                            result.action_mut(op_degree, op_idx, input_degree, input_idx);
433                        module.act_on_basis(
434                            output_vec.as_slice_mut(),
435                            1,
436                            op_degree,
437                            op_idx,
438                            input_degree,
439                            input_idx,
440                        );
441                    }
442                }
443            }
444        }
445        result
446    }
447}
448
449impl<A: GeneratedAlgebra> FiniteDimensionalModule<A> {
450    pub fn from_json(algebra: Arc<A>, json: &Value) -> anyhow::Result<Self> {
451        let (graded_dimension, gen_names, gen_to_idx) = crate::module_gens_from_json(&json["gens"]);
452        let name = json["name"].as_str().unwrap_or("").to_string();
453
454        let mut result = Self::new(Arc::clone(&algebra), name, graded_dimension.clone());
455        for (i, dim) in graded_dimension.iter_enum() {
456            for j in 0..*dim {
457                result.set_basis_element_name(i, j, gen_names[i][j].clone());
458            }
459        }
460
461        let actions = Vec::<String>::deserialize(&json["actions"]).unwrap();
462        for action in actions {
463            result
464                .parse_action(&gen_to_idx, &action, false)
465                .with_context(|| format!("Failed to parse action: {action}"))?;
466        }
467        for input_degree in (result.min_degree()..=result.max_degree().unwrap()).rev() {
468            for output_degree in input_degree + 1..=result.max_degree().unwrap() {
469                result.extend_actions(input_degree, output_degree);
470                result.check_validity(input_degree, output_degree)?;
471            }
472        }
473        Ok(result)
474    }
475
476    pub fn to_json(&self, json: &mut Value) {
477        if !self.name.is_empty() {
478            json["name"] = Value::String(self.name.clone());
479        }
480        json["type"] = Value::from("finite dimensional module");
481        json["gens"] = json!({});
482        for (i, deg_i_gens) in self.gen_names.iter_enum() {
483            for g in deg_i_gens {
484                json["gens"][g] = Value::from(i);
485            }
486        }
487
488        json["actions"] = self.actions_to_json();
489    }
490
491    pub fn parse_action(
492        &mut self,
493        gen_to_idx: impl for<'a> Fn(&'a str) -> anyhow::Result<(i32, usize)>,
494        entry: &str,
495        overwrite: bool,
496    ) -> anyhow::Result<()> {
497        let algebra = self.algebra();
498
499        let (lhs, rhs) = entry
500            .split_once(" = ")
501            .ok_or_else(|| anyhow!("Invalid action: {entry}"))?;
502
503        let (action, g) = lhs
504            .rsplit_once(' ')
505            .ok_or_else(|| anyhow!("Invalid action: {entry}"))?;
506
507        let (op_deg, op_idx) = algebra
508            .basis_element_from_string(action)
509            .ok_or_else(|| anyhow!("Invalid algebra element: {action}"))?;
510
511        let (input_deg, input_idx) = gen_to_idx(g.trim())?;
512
513        let row = self.action_mut(op_deg, op_idx, input_deg, input_idx);
514
515        if overwrite {
516            row.set_to_zero();
517        }
518
519        if rhs == "0" {
520            return Ok(());
521        }
522
523        for item in rhs.split(" + ") {
524            let (coef, g) = match item.split_once(' ') {
525                Some((coef, g)) => (
526                    str::parse(coef)
527                        .map_err(|_| anyhow!("Invalid item on right-hand side: {item}"))?,
528                    g,
529                ),
530                None => (1, item),
531            };
532            let (deg, idx) = gen_to_idx(g.trim())?;
533            if deg != input_deg + op_deg {
534                return Err(anyhow!(
535                    "Degree of {g} is {deg} but degree of LHS is {}",
536                    input_deg + op_deg
537                ));
538            }
539            row.add_basis_element(idx, coef);
540        }
541        Ok(())
542    }
543
544    pub fn check_validity(
545        &self,
546        input_deg: i32,
547        output_deg: i32,
548    ) -> Result<(), ModuleFailedRelationError> {
549        assert!(output_deg > input_deg);
550        let p = self.prime();
551        let algebra = self.algebra();
552        let op_deg = output_deg - input_deg;
553        let mut output_vec = FpVector::new(p, self.dimension(output_deg));
554        let mut tmp_output = FpVector::new(p, self.dimension(output_deg));
555        for idx in 0..self.dimension(input_deg) {
556            let relations = algebra.generating_relations(op_deg);
557            for relation in relations {
558                for &(coef, (deg_1, idx_1), (deg_2, idx_2)) in &relation {
559                    let intermediate_dim = self.dimension(input_deg + deg_2);
560                    tmp_output.set_scratch_vector_size(intermediate_dim);
561                    self.act_on_basis(tmp_output.as_slice_mut(), 1, deg_2, idx_2, input_deg, idx);
562                    self.act(
563                        output_vec.as_slice_mut(),
564                        coef,
565                        deg_1,
566                        idx_1,
567                        deg_2 + input_deg,
568                        tmp_output.as_slice(),
569                    );
570                }
571
572                if !output_vec.is_zero() {
573                    let mut relation_string = String::new();
574                    for (coef, (deg_1, idx_1), (deg_2, idx_2)) in &relation {
575                        let _ = write!(
576                            relation_string,
577                            "{} * {} * {}  +  ",
578                            *coef,
579                            &algebra.basis_element_to_string(*deg_1, *idx_1),
580                            &algebra.basis_element_to_string(*deg_2, *idx_2)
581                        );
582                    }
583                    for _ in 0..5 {
584                        relation_string.pop();
585                    }
586
587                    let value_string = self.element_to_string(output_deg, output_vec.as_slice());
588                    return Err(ModuleFailedRelationError {
589                        relation: relation_string,
590                        value: value_string,
591                    });
592                }
593            }
594        }
595        Ok(())
596    }
597
598    pub fn extend_actions(&mut self, input_deg: i32, output_deg: i32) {
599        let p = self.prime();
600        let algebra = self.algebra();
601        let op_deg = output_deg - input_deg;
602        if self.dimension(output_deg) == 0 || self.dimension(input_deg) == 0 {
603            return;
604        }
605
606        let mut tmp_output = FpVector::new(p, self.dimension(output_deg));
607        let generators = algebra.generators(op_deg);
608        for idx in 0..self.dimension(input_deg) {
609            for op_idx in 0..algebra.dimension(op_deg) {
610                if !generators.contains(&op_idx) {
611                    let mut output_vec = std::mem::replace(
612                        &mut self.actions[input_deg][output_deg][op_idx][idx],
613                        FpVector::new(p, 0),
614                    );
615                    let decomposition = algebra.decompose_basis_element(op_deg, op_idx);
616                    for (coef, (deg_1, idx_1), (deg_2, idx_2)) in decomposition {
617                        let intermediate_dim = self.dimension(input_deg + deg_2);
618                        if intermediate_dim > tmp_output.len() {
619                            tmp_output = FpVector::new(p, intermediate_dim);
620                        }
621                        self.act_on_basis(
622                            tmp_output.slice_mut(0, intermediate_dim),
623                            1,
624                            deg_2,
625                            idx_2,
626                            input_deg,
627                            idx,
628                        );
629                        self.act(
630                            output_vec.as_slice_mut(),
631                            coef,
632                            deg_1,
633                            idx_1,
634                            deg_2 + input_deg,
635                            tmp_output.slice(0, intermediate_dim),
636                        );
637                        tmp_output.set_to_zero();
638                    }
639                    let _ = std::mem::replace(
640                        &mut self.actions[input_deg][output_deg][op_idx][idx],
641                        output_vec,
642                    );
643                }
644            }
645        }
646    }
647
648    fn actions_to_json(&self) -> Value {
649        let algebra = self.algebra();
650        let min_degree = self.min_degree();
651        let max_degree = self.graded_dimension.len();
652        let mut actions = Vec::new();
653        for input_degree in min_degree..max_degree {
654            for output_degree in (input_degree + 1)..max_degree {
655                if self.dimension(output_degree) == 0 {
656                    continue;
657                }
658                let op_degree = output_degree - input_degree;
659                for op_idx in algebra.generators(op_degree) {
660                    for input_idx in 0..self.dimension(input_degree) {
661                        let vec = self.action(op_degree, op_idx, input_degree, input_idx);
662                        if vec.is_zero() {
663                            continue;
664                        }
665                        actions.push(format!(
666                            "{} {} = {}",
667                            algebra.generator_to_string(op_degree, op_idx),
668                            self.gen_names[input_degree][input_idx],
669                            self.element_to_string(output_degree, vec.as_slice())
670                        ))
671                    }
672                }
673            }
674        }
675        json!(actions)
676    }
677}
678
679#[cfg(test)]
680mod tests {
681    use super::*;
682    use crate::algebra::AdemAlgebra;
683
684    #[test]
685    fn test_module_check_validity() {
686        let p = fp::prime::ValidPrime::new(2);
687        let adem_algebra = Arc::new(AdemAlgebra::new(p, false));
688        adem_algebra.compute_basis(10);
689        let mut adem_module = FiniteDimensionalModule::new(
690            Arc::clone(&adem_algebra),
691            "".to_string(),
692            BiVec::from_vec(0, vec![1, 2, 1]),
693        );
694        adem_module.set_basis_element_name(0, 0, "x0".to_string());
695        adem_module.set_basis_element_name(1, 0, "x10".to_string());
696        adem_module.set_basis_element_name(1, 1, "x11".to_string());
697        adem_module.set_basis_element_name(2, 0, "x2".to_string());
698        adem_module.set_action(1, 0, 0, 0, &[1, 1]);
699        adem_module.set_action(1, 0, 1, 0, &[1]);
700        adem_module.set_action(1, 0, 1, 1, &[1]);
701        adem_module.set_action(2, 0, 0, 0, &[1]);
702        adem_module.check_validity(0, 2).unwrap();
703    }
704}