open_hypergraphs/lax/
functor.rs

1//! Strict symmetric monoidal hypergraph functors on lax open hypergraphs.
2use crate::array::vec::VecKind;
3use crate::lax::open_hypergraph::*;
4use crate::operations::Operations;
5use crate::strict;
6
7// Problems:
8//  1. No ownership of OpenHypergraph ⇒ have to copy in to_strict!
9//  2. Sized constraint coming from to_dyn_functor
10//  3. Can't give nice default impl - constraints from `define_map_arrow` / `to_dyn_functor`
11
12/// An easier-to-implement `Functor` trait for lax `OpenHypergraph`
13pub trait Functor<O1, A1, O2, A2> {
14    /// Map a generating object of the theory
15    fn map_object(&self, o: &O1) -> impl ExactSizeIterator<Item = O2>;
16
17    /// Map a single operation of the theory with specified source and target type.
18    /// This must be consistent with `map_object`, i.e. we must have:
19    ///     - `F.map_operation(x, s, t).sources == F.map_object(s)`
20    ///     - `F.map_operation(x, s, t).targets == F.map_object(t)`
21    /// This condition is *not* checked, but may panic if not satisfied.
22    fn map_operation(&self, a: &A1, source: &[O1], target: &[O1]) -> OpenHypergraph<O2, A2>;
23
24    /// Apply this functor to an [`OpenHypergraph`].
25    /// Once `map_operation` is defined, this can typically be defined as
26    /// `define_map_arrow(self, f)`
27    fn map_arrow(&self, f: &OpenHypergraph<O1, A1>) -> OpenHypergraph<O2, A2>;
28}
29
30// TODO: write a to_strict_functor returning impl strict::functor::Functor
31pub fn define_map_arrow<
32    F: Functor<O1, A1, O2, A2> + Clone,
33    O1: Clone + PartialEq,
34    A1: Clone,
35    O2: Clone + PartialEq,
36    A2: Clone,
37>(
38    functor: &F,
39    f: &OpenHypergraph<O1, A1>,
40) -> OpenHypergraph<O2, A2> {
41    // Default implementation using strict::functor::Functor
42    let strict_functor: DynFunctor<F, O1, A1, O2, A2> = to_dyn_functor(functor.clone());
43    let strict_f = to_strict(f.clone());
44    let strict_g = <_ as strict::functor::Functor<VecKind, O1, A1, O2, A2>>::map_arrow(
45        &strict_functor,
46        &strict_f,
47    );
48    OpenHypergraph::from_strict(strict_g)
49}
50
51fn to_dyn_functor<F: Functor<O1, A1, O2, A2>, O1, A1, O2, A2>(
52    functor: F,
53) -> DynFunctor<F, O1, A1, O2, A2> {
54    DynFunctor {
55        inner: functor,
56        _phantom: std::marker::PhantomData,
57    }
58}
59
60fn to_strict<O: Clone, A: Clone>(f: OpenHypergraph<O, A>) -> strict::OpenHypergraph<VecKind, O, A> {
61    f.to_open_hypergraph()
62}
63
64// A dynamic functor using closures for map_object and map_operation
65struct DynFunctor<F: Functor<O1, A1, O2, A2>, O1, A1, O2, A2> {
66    inner: F,
67    _phantom: std::marker::PhantomData<(O1, A1, O2, A2)>,
68}
69
70impl<
71        F: Functor<O1, A1, O2, A2>,
72        O1: Clone + PartialEq,
73        A1: Clone,
74        O2: Clone + PartialEq,
75        A2: Clone,
76    > strict::functor::Functor<VecKind, O1, A1, O2, A2> for DynFunctor<F, O1, A1, O2, A2>
77{
78    fn map_object(
79        &self,
80        a: &strict::SemifiniteFunction<VecKind, O1>,
81    ) -> strict::IndexedCoproduct<VecKind, strict::SemifiniteFunction<VecKind, O2>> {
82        let mut sizes = Vec::new();
83        let mut values = Vec::new();
84
85        for obj in a.0 .0.iter() {
86            let iter = self.inner.map_object(obj);
87            sizes.push(iter.len());
88            values.extend(iter);
89        }
90
91        use crate::array::vec::VecArray;
92        use crate::semifinite::SemifiniteFunction;
93        let sizes = SemifiniteFunction::<VecKind, usize>(VecArray(sizes));
94        let values = SemifiniteFunction(VecArray(values));
95        strict::IndexedCoproduct::from_semifinite(sizes, values).unwrap()
96    }
97
98    fn map_operations(
99        &self,
100        ops: Operations<VecKind, O1, A1>,
101    ) -> strict::OpenHypergraph<VecKind, O2, A2> {
102        // TODO: add a *slice* iterator for IndexedCoproduct<VecKind, _>
103        let op_iter = ops.x.0 .0.iter();
104        let source_iter = ops.a.into_iter();
105        let target_iter = ops.b.into_iter();
106
107        let mut acc: OpenHypergraph<O2, A2> = OpenHypergraph::empty();
108        for (op, (source, target)) in op_iter.zip(source_iter.zip(target_iter)) {
109            acc.tensor_assign(self.inner.map_operation(op, &source.0, &target.0))
110        }
111
112        acc.to_open_hypergraph()
113    }
114
115    fn map_arrow(
116        &self,
117        f: &strict::OpenHypergraph<VecKind, O1, A1>,
118    ) -> strict::OpenHypergraph<VecKind, O2, A2> {
119        strict::functor::define_map_arrow(self, f)
120    }
121}
122
123/// The identity functor for lax open hypergraphs.
124#[derive(Clone)]
125pub struct Identity;
126
127impl<O: PartialEq + Clone, A: Clone + PartialEq> Functor<O, A, O, A> for Identity {
128    fn map_object(&self, o: &O) -> impl ExactSizeIterator<Item = O> {
129        std::iter::once(o.clone())
130    }
131
132    fn map_operation(&self, a: &A, source: &[O], target: &[O]) -> crate::lax::OpenHypergraph<O, A> {
133        OpenHypergraph::singleton(a.clone(), source.to_vec(), target.to_vec())
134    }
135
136    fn map_arrow(&self, f: &crate::lax::OpenHypergraph<O, A>) -> crate::lax::OpenHypergraph<O, A> {
137        define_map_arrow(self, f)
138    }
139}