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
51pub fn 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 + PartialEq, A: Clone>(
61    f: OpenHypergraph<O, A>,
62) -> strict::OpenHypergraph<VecKind, O, A> {
63    f.to_strict()
64}
65
66// A dynamic functor using closures for map_object and map_operation
67pub struct DynFunctor<F: Functor<O1, A1, O2, A2>, O1, A1, O2, A2> {
68    inner: F,
69    _phantom: std::marker::PhantomData<(O1, A1, O2, A2)>,
70}
71
72impl<
73        F: Functor<O1, A1, O2, A2>,
74        O1: Clone + PartialEq,
75        A1: Clone,
76        O2: Clone + PartialEq,
77        A2: Clone,
78    > strict::functor::Functor<VecKind, O1, A1, O2, A2> for DynFunctor<F, O1, A1, O2, A2>
79{
80    fn map_object(
81        &self,
82        a: &strict::SemifiniteFunction<VecKind, O1>,
83    ) -> strict::IndexedCoproduct<VecKind, strict::SemifiniteFunction<VecKind, O2>> {
84        let mut sizes = Vec::new();
85        let mut values = Vec::new();
86
87        for obj in a.0 .0.iter() {
88            let iter = self.inner.map_object(obj);
89            sizes.push(iter.len());
90            values.extend(iter);
91        }
92
93        use crate::array::vec::VecArray;
94        use crate::semifinite::SemifiniteFunction;
95        let sizes = SemifiniteFunction::<VecKind, usize>(VecArray(sizes));
96        let values = SemifiniteFunction(VecArray(values));
97        strict::IndexedCoproduct::from_semifinite(sizes, values).unwrap()
98    }
99
100    fn map_operations(
101        &self,
102        ops: Operations<VecKind, O1, A1>,
103    ) -> strict::OpenHypergraph<VecKind, O2, A2> {
104        // TODO: add a *slice* iterator for IndexedCoproduct<VecKind, _>
105        let op_iter = ops.x.0 .0.iter();
106        let source_iter = ops.a.into_iter();
107        let target_iter = ops.b.into_iter();
108
109        let mut acc: OpenHypergraph<O2, A2> = OpenHypergraph::empty();
110        for (op, (source, target)) in op_iter.zip(source_iter.zip(target_iter)) {
111            acc.tensor_assign(self.inner.map_operation(op, &source.0, &target.0))
112        }
113
114        acc.to_strict()
115    }
116
117    fn map_arrow(
118        &self,
119        f: &strict::OpenHypergraph<VecKind, O1, A1>,
120    ) -> strict::OpenHypergraph<VecKind, O2, A2> {
121        strict::functor::define_map_arrow(self, f)
122    }
123}
124
125/// The identity functor for lax open hypergraphs.
126#[derive(Clone)]
127pub struct Identity;
128
129impl<O: PartialEq + Clone, A: Clone + PartialEq> Functor<O, A, O, A> for Identity {
130    fn map_object(&self, o: &O) -> impl ExactSizeIterator<Item = O> {
131        std::iter::once(o.clone())
132    }
133
134    fn map_operation(&self, a: &A, source: &[O], target: &[O]) -> crate::lax::OpenHypergraph<O, A> {
135        OpenHypergraph::singleton(a.clone(), source.to_vec(), target.to_vec())
136    }
137
138    fn map_arrow(&self, f: &crate::lax::OpenHypergraph<O, A>) -> crate::lax::OpenHypergraph<O, A> {
139        define_map_arrow(self, f)
140    }
141}