Skip to main content

open_hypergraphs/lax/
category.rs

1//! Implement [`crate::category`] traits for [`crate::lax::OpenHypergraph`]
2use crate::array::vec::VecKind;
3use crate::category::*;
4use crate::lax::*;
5
6impl<O: Clone + PartialEq, A: Clone> Arrow for OpenHypergraph<O, A> {
7    type Object = Vec<O>;
8
9    fn source(&self) -> Self::Object {
10        self.sources
11            .iter()
12            .map(|i| self.hypergraph.nodes[i.0].clone())
13            .collect()
14    }
15
16    fn target(&self) -> Self::Object {
17        self.targets
18            .iter()
19            .map(|i| self.hypergraph.nodes[i.0].clone())
20            .collect()
21    }
22
23    fn identity(a: Self::Object) -> Self {
24        OpenHypergraph::identity(a)
25    }
26
27    fn compose(&self, other: &Self) -> Option<Self> {
28        if self.target() != other.source() {
29            return None;
30        }
31        self.lax_compose(other)
32    }
33}
34
35impl<O: Clone, A: Clone> OpenHypergraph<O, A> {
36    /// Compose two open hypergraphs, unifying the boundary nodes without checking labels.
37    ///
38    /// Returns None when the boundary arities do not match.
39    pub fn lax_compose(&self, other: &Self) -> Option<Self> {
40        if self.targets.len() != other.sources.len() {
41            return None;
42        }
43
44        let n = self.hypergraph.nodes.len();
45        let mut f = self.tensor(other);
46        for (u, v) in self.targets.iter().zip(other.sources.iter()) {
47            f.unify(*u, NodeId(v.0 + n));
48        }
49
50        f.sources.truncate(self.sources.len());
51        f.targets = f.targets[self.targets.len()..].to_vec();
52
53        Some(f)
54    }
55}
56
57impl<O: Clone + PartialEq, A: Clone> Monoidal for OpenHypergraph<O, A> {
58    fn unit() -> Self::Object {
59        vec![]
60    }
61
62    fn tensor(&self, other: &Self) -> Self {
63        OpenHypergraph::tensor(self, other)
64    }
65}
66
67use crate::array::vec::VecArray;
68use crate::semifinite::*;
69
70impl<O: Clone + PartialEq, A: Clone + PartialEq> SymmetricMonoidal for OpenHypergraph<O, A> {
71    fn twist(a: Self::Object, b: Self::Object) -> Self {
72        let f = crate::strict::open_hypergraph::OpenHypergraph::twist(
73            SemifiniteFunction(VecArray(a)),
74            SemifiniteFunction(VecArray(b)),
75        );
76        OpenHypergraph::from_strict(f)
77    }
78}
79
80impl<O: Clone + PartialEq, A: Clone + PartialEq> Spider<VecKind> for OpenHypergraph<O, A> {
81    fn dagger(&self) -> Self {
82        let mut f = self.clone();
83        f.sources = self.targets.clone();
84        f.targets = self.sources.clone();
85        f
86    }
87
88    fn spider(
89        s: crate::finite_function::FiniteFunction<VecKind>,
90        t: crate::finite_function::FiniteFunction<VecKind>,
91        w: Self::Object,
92    ) -> Option<Self> {
93        OpenHypergraph::spider(s, t, w)
94    }
95}
96
97use core::ops::{BitOr, Shr};
98
99impl<O: Clone + PartialEq, A: Clone> Shr<&OpenHypergraph<O, A>> for &OpenHypergraph<O, A> {
100    type Output = Option<OpenHypergraph<O, A>>;
101
102    fn shr(self, rhs: &OpenHypergraph<O, A>) -> Self::Output {
103        self.compose(rhs)
104    }
105}
106
107impl<O: Clone + PartialEq, A: Clone> BitOr<&OpenHypergraph<O, A>> for &OpenHypergraph<O, A> {
108    type Output = OpenHypergraph<O, A>;
109
110    fn bitor(self, rhs: &OpenHypergraph<O, A>) -> Self::Output {
111        self.tensor(rhs)
112    }
113}