1use crate::array::*;
2use crate::category::*;
3use crate::finite_function::*;
4use crate::operations::*;
5use crate::semifinite::*;
6use crate::strict::hypergraph::{Hypergraph, InvalidHypergraph};
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 pub fn source(&self) -> SemifiniteFunction<K, O> {
96 (&self.s >> &self.h.w).expect("invalid open hypergraph: cospan source has invalid codomain")
98 }
99
100 pub fn target(&self) -> SemifiniteFunction<K, O> {
101 (&self.t >> &self.h.w).expect("invalid open hypergraph: cospan target has invalid codomain")
102 }
103
104 pub fn identity(w: SemifiniteFunction<K, O>) -> OpenHypergraph<K, O, A> {
105 let s = FiniteFunction::<K>::identity(w.0.len());
106 let t = FiniteFunction::<K>::identity(w.0.len());
107 let h = Hypergraph::<K, O, A>::discrete(w);
108 OpenHypergraph { s, t, h }
109 }
110
111 pub fn spider(
112 s: FiniteFunction<K>,
113 t: FiniteFunction<K>,
114 w: SemifiniteFunction<K, O>,
115 ) -> Option<Self> {
116 if s.target() != w.len() || t.target() != w.len() {
117 return None;
118 }
119
120 let h = Hypergraph::discrete(w);
121 Some(OpenHypergraph { s, t, h })
122 }
123}
124
125impl<K: ArrayKind, O, A> OpenHypergraph<K, O, A>
126where
127 K::Type<K::I>: NaturalArray<K>,
128 K::Type<O>: Array<K, O> + PartialEq,
129 K::Type<A>: Array<K, A>,
130{
131 fn compose(&self, other: &Self) -> Option<Self> {
132 if self.target() != other.source() {
133 return None;
134 }
135
136 let q_lhs = self.t.inject0(other.h.w.0.len());
138 let q_rhs = other.s.inject1(self.h.w.0.len());
139 let q = q_lhs.coequalizer(&q_rhs).expect("Invalid OpenHypergraph");
140
141 let s = self.s.inject0(other.h.w.0.len()).compose(&q).unwrap();
145 let t = other.t.inject1(self.h.w.0.len()).compose(&q).unwrap();
146
147 let h = self.tensor(other).h.coequalize_vertices(&q).unwrap();
150
151 Some(OpenHypergraph { s, t, h })
152 }
153}
154
155impl<K: ArrayKind, O, A> Arrow for OpenHypergraph<K, O, A>
156where
157 K::Type<K::I>: NaturalArray<K>,
158 K::Type<O>: Array<K, O> + PartialEq,
159 K::Type<A>: Array<K, A>,
160{
161 type Object = SemifiniteFunction<K, O>;
163
164 fn source(&self) -> Self::Object {
165 self.source()
166 }
167
168 fn target(&self) -> Self::Object {
169 self.target()
170 }
171
172 fn identity(w: Self::Object) -> Self {
173 Self::identity(w)
174 }
175
176 fn compose(&self, other: &Self) -> Option<Self> {
177 self.compose(other)
178 }
179}
180
181impl<K: ArrayKind, O, A> Monoidal for OpenHypergraph<K, O, A>
182where
183 K::Type<K::I>: NaturalArray<K>,
184 K::Type<O>: Array<K, O> + PartialEq,
185 K::Type<A>: Array<K, A>,
186{
187 fn unit() -> Self::Object {
188 SemifiniteFunction::<K, O>::zero()
189 }
190
191 fn tensor(&self, other: &Self) -> Self {
192 OpenHypergraph {
193 s: &self.s | &other.s,
194 t: &self.t | &other.t,
195 h: &self.h + &other.h,
196 }
197 }
198}
199
200impl<K: ArrayKind, O, A> SymmetricMonoidal for OpenHypergraph<K, O, A>
201where
202 K::Type<K::I>: NaturalArray<K>,
203 K::Type<O>: Array<K, O> + PartialEq,
204 K::Type<A>: Array<K, A>,
205{
206 fn twist(a: Self::Object, b: Self::Object) -> Self {
207 let s = FiniteFunction::twist(a.len(), b.len());
208 let t = FiniteFunction::identity(a.len() + b.len());
209
210 let h = Hypergraph::discrete(b + a);
213 OpenHypergraph { s, t, h }
214 }
215}
216
217impl<K: ArrayKind, O, A> Spider<K> for OpenHypergraph<K, O, A>
218where
219 K::Type<K::I>: NaturalArray<K>,
220 K::Type<O>: Array<K, O> + PartialEq,
221 K::Type<A>: Array<K, A>,
222{
223 fn dagger(&self) -> Self {
224 OpenHypergraph {
225 s: self.t.clone(),
226 t: self.s.clone(),
227 h: self.h.clone(),
228 }
229 }
230
231 fn spider(s: FiniteFunction<K>, t: FiniteFunction<K>, w: Self::Object) -> Option<Self> {
232 OpenHypergraph::spider(s, t, w)
233 }
234}
235
236impl<K: ArrayKind, O, A> Shr<&OpenHypergraph<K, O, A>> for &OpenHypergraph<K, O, A>
238where
239 K::Type<K::I>: NaturalArray<K>,
240 K::Type<O>: Array<K, O> + PartialEq,
241 K::Type<A>: Array<K, A>,
242{
243 type Output = Option<OpenHypergraph<K, O, A>>;
244 fn shr(self, rhs: &OpenHypergraph<K, O, A>) -> Option<OpenHypergraph<K, O, A>> {
245 self.compose(rhs)
246 }
247}
248
249impl<K: ArrayKind, O, A> BitOr<&OpenHypergraph<K, O, A>> for &OpenHypergraph<K, O, A>
251where
252 K::Type<K::I>: NaturalArray<K>,
253 K::Type<O>: Array<K, O> + PartialEq,
254 K::Type<A>: Array<K, A>,
255{
256 type Output = OpenHypergraph<K, O, A>;
257 fn bitor(self, rhs: &OpenHypergraph<K, O, A>) -> OpenHypergraph<K, O, A> {
258 self.tensor(rhs)
259 }
260}
261
262impl<K: ArrayKind, O, A> Clone for OpenHypergraph<K, O, A>
263where
264 K::Type<O>: Clone,
265 K::Type<A>: Clone,
266 K::Type<K::I>: Clone,
267{
268 fn clone(&self) -> Self {
269 Self {
270 s: self.s.clone(),
271 t: self.t.clone(),
272 h: self.h.clone(),
273 }
274 }
275}
276
277impl<K: ArrayKind, O: Debug, A: Debug> Debug for OpenHypergraph<K, O, A>
278where
279 K::Index: Debug,
280 K::Type<K::I>: Debug,
281 K::Type<O>: Debug,
282 K::Type<A>: Debug,
283{
284 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
285 f.debug_struct("OpenHypergraph")
286 .field("s", &self.s)
287 .field("t", &self.t)
288 .field("h", &self.h)
289 .finish()
290 }
291}