1use crate::array::*;
2use crate::category::*;
3use crate::finite_function::*;
4use crate::hypergraph::{Hypergraph, InvalidHypergraph};
5use crate::operations::*;
6use crate::semifinite::*;
7
8use core::fmt::Debug;
9use core::ops::{BitOr, Shr};
10use num_traits::Zero;
11
12impl<K: ArrayKind> From<InvalidHypergraph<K>> for InvalidOpenHypergraph<K> {
13 fn from(value: InvalidHypergraph<K>) -> Self {
14 InvalidOpenHypergraph::InvalidHypergraph(value)
15 }
16}
17
18#[derive(Debug)]
19pub enum InvalidOpenHypergraph<K: ArrayKind> {
20 CospanSourceType(K::I, K::I),
21 CospanTargetType(K::I, K::I),
22 InvalidHypergraph(InvalidHypergraph<K>),
23}
24
25pub struct OpenHypergraph<K: ArrayKind, O, A> {
37 pub s: FiniteFunction<K>,
38 pub t: FiniteFunction<K>,
39 pub h: Hypergraph<K, O, A>,
40}
41
42impl<K: ArrayKind, O, A> OpenHypergraph<K, O, A>
43where
44 K::Type<K::I>: NaturalArray<K>,
45 K::Type<O>: Array<K, O>,
46 K::Type<A>: Array<K, A>,
47{
48 pub fn new(
49 s: FiniteFunction<K>,
50 t: FiniteFunction<K>,
51 h: Hypergraph<K, O, A>,
52 ) -> Result<Self, InvalidOpenHypergraph<K>> {
53 let f = OpenHypergraph { s, t, h };
54 f.validate()
55 }
56
57 pub fn validate(self) -> Result<Self, InvalidOpenHypergraph<K>> {
58 let h = self.h.validate()?;
59 let w_source = h.w.0.len();
60 let s_target = self.s.target();
61 let t_target = self.t.target();
62
63 if s_target != w_source {
65 Err(InvalidOpenHypergraph::CospanSourceType(s_target, w_source))
66 } else if t_target != w_source {
67 Err(InvalidOpenHypergraph::CospanTargetType(t_target, w_source))
68 } else {
69 Ok(OpenHypergraph {
70 s: self.s,
71 t: self.t,
72 h,
73 })
74 }
75 }
76
77 pub fn singleton(
78 x: A,
79 a: SemifiniteFunction<K, O>,
80 b: SemifiniteFunction<K, O>,
81 ) -> OpenHypergraph<K, O, A> {
82 Self::tensor_operations(Operations::singleton(x, a, b))
83 }
84
85 pub fn tensor_operations(operations: Operations<K, O, A>) -> OpenHypergraph<K, O, A> {
86 let h = Hypergraph::tensor_operations(operations);
87 let t = h.t.values.clone();
88 let s = h.s.values.clone();
89 OpenHypergraph { s, t, h }
90 }
91}
92
93impl<K: ArrayKind, O, A> Arrow for OpenHypergraph<K, O, A>
94where
95 K::Type<K::I>: NaturalArray<K>,
96 K::Type<O>: Array<K, O>,
97 K::Type<A>: Array<K, A>,
98{
99 type Object = SemifiniteFunction<K, O>;
101
102 fn source(&self) -> Self::Object {
103 (&self.s >> &self.h.w).expect("invalid open hypergraph: cospan source has invalid codomain")
105 }
106
107 fn target(&self) -> Self::Object {
108 (&self.t >> &self.h.w).expect("invalid open hypergraph: cospan target has invalid codomain")
109 }
110
111 fn identity(w: Self::Object) -> Self {
112 let s = FiniteFunction::<K>::identity(w.0.len());
113 let t = FiniteFunction::<K>::identity(w.0.len());
114 let h = Hypergraph::<K, O, A>::discrete(w);
115 OpenHypergraph { s, t, h }
116 }
117
118 fn compose(&self, other: &Self) -> Option<Self> {
119 if self.target() != other.source() {
120 return None;
121 }
122
123 let q_lhs = self.t.inject0(other.h.w.0.len());
125 let q_rhs = other.s.inject1(self.h.w.0.len());
126 let q = q_lhs.coequalizer(&q_rhs).expect("Invalid OpenHypergraph");
127
128 let s = self.s.inject0(other.h.w.0.len()).compose(&q).unwrap();
132 let t = other.t.inject1(self.h.w.0.len()).compose(&q).unwrap();
133
134 let h = self.tensor(other).h.coequalize_vertices(&q).unwrap();
137
138 Some(OpenHypergraph { s, t, h })
139 }
140}
141
142impl<K: ArrayKind, O, A> Monoidal for OpenHypergraph<K, O, A>
143where
144 K::Type<K::I>: NaturalArray<K>,
145 K::Type<O>: Array<K, O>,
146 K::Type<A>: Array<K, A>,
147{
148 fn unit() -> Self::Object {
149 SemifiniteFunction::<K, O>::zero()
150 }
151
152 fn tensor(&self, other: &Self) -> Self {
153 OpenHypergraph {
154 s: &self.s | &other.s,
155 t: &self.t | &other.t,
156 h: &self.h + &other.h,
157 }
158 }
159}
160
161impl<K: ArrayKind, O, A> SymmetricMonoidal for OpenHypergraph<K, O, A>
162where
163 K::Type<K::I>: NaturalArray<K>,
164 K::Type<O>: Array<K, O>,
165 K::Type<A>: Array<K, A>,
166{
167 fn twist(a: Self::Object, b: Self::Object) -> Self {
168 let s = FiniteFunction::twist(a.len(), b.len());
169 let t = FiniteFunction::identity(a.len() + b.len());
170
171 let h = Hypergraph::discrete(b + a);
174 OpenHypergraph { s, t, h }
175 }
176}
177
178impl<K: ArrayKind, O, A> Spider<K> for OpenHypergraph<K, O, A>
179where
180 K::Type<K::I>: NaturalArray<K>,
181 K::Type<O>: Array<K, O>,
182 K::Type<A>: Array<K, A>,
183{
184 fn dagger(&self) -> Self {
185 OpenHypergraph {
186 s: self.t.clone(),
187 t: self.s.clone(),
188 h: self.h.clone(),
189 }
190 }
191
192 fn spider(s: FiniteFunction<K>, t: FiniteFunction<K>, w: Self::Object) -> Option<Self> {
193 if s.target() != w.len() || t.target() != w.len() {
194 return None;
195 }
196
197 let h = Hypergraph::discrete(w);
198 Some(OpenHypergraph { s, t, h })
199 }
200}
201
202impl<K: ArrayKind, O, A> Shr<&OpenHypergraph<K, O, A>> for &OpenHypergraph<K, O, A>
204where
205 K::Type<K::I>: NaturalArray<K>,
206 K::Type<O>: Array<K, O>,
207 K::Type<A>: Array<K, A>,
208{
209 type Output = Option<OpenHypergraph<K, O, A>>;
210 fn shr(self, rhs: &OpenHypergraph<K, O, A>) -> Option<OpenHypergraph<K, O, A>> {
211 self.compose(rhs)
212 }
213}
214
215impl<K: ArrayKind, O, A> BitOr<&OpenHypergraph<K, O, A>> for &OpenHypergraph<K, O, A>
217where
218 K::Type<K::I>: NaturalArray<K>,
219 K::Type<O>: Array<K, O>,
220 K::Type<A>: Array<K, A>,
221{
222 type Output = OpenHypergraph<K, O, A>;
223 fn bitor(self, rhs: &OpenHypergraph<K, O, A>) -> OpenHypergraph<K, O, A> {
224 self.tensor(rhs)
225 }
226}
227
228impl<K: ArrayKind, O, A> Clone for OpenHypergraph<K, O, A>
229where
230 K::Type<O>: Clone,
231 K::Type<A>: Clone,
232 K::Type<K::I>: Clone,
233{
234 fn clone(&self) -> Self {
235 Self {
236 s: self.s.clone(),
237 t: self.t.clone(),
238 h: self.h.clone(),
239 }
240 }
241}
242
243impl<K: ArrayKind, O: Debug, A: Debug> Debug for OpenHypergraph<K, O, A>
244where
245 K::Index: Debug,
246 K::Type<K::I>: Debug,
247 K::Type<O>: Debug,
248 K::Type<A>: Debug,
249{
250 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
251 f.debug_struct("OpenHypergraph")
252 .field("s", &self.s)
253 .field("t", &self.t)
254 .field("h", &self.h)
255 .finish()
256 }
257}