1use derive_more::From;
4use ref_cast::RefCast;
5
6use super::graph::{FinGraph, Graph};
7use super::path::Path;
8use crate::zero::{FinSet, Set};
9
10pub trait Category {
23 type Ob: Eq + Clone;
25
26 type Mor: Eq + Clone;
28
29 fn has_ob(&self, x: &Self::Ob) -> bool;
31
32 fn has_mor(&self, f: &Self::Mor) -> bool;
34
35 fn dom(&self, f: &Self::Mor) -> Self::Ob;
37
38 fn cod(&self, f: &Self::Mor) -> Self::Ob;
40
41 fn compose(&self, path: Path<Self::Ob, Self::Mor>) -> Self::Mor;
43
44 fn compose2(&self, f: Self::Mor, g: Self::Mor) -> Self::Mor {
46 self.compose(Path::pair(f, g))
47 }
48
49 fn id(&self, x: Self::Ob) -> Self::Mor {
51 self.compose(Path::empty(x))
52 }
53
54 fn morphisms_are_equal(&self, f: Self::Mor, g: Self::Mor) -> bool {
60 f == g
61 }
62}
63
64#[derive(From, RefCast)]
66#[repr(transparent)]
67pub struct ObSet<Cat: Category>(Cat);
68
69impl<Cat: Category> Set for ObSet<Cat> {
70 type Elem = Cat::Ob;
71
72 fn contains(&self, x: &Cat::Ob) -> bool {
73 self.0.has_ob(x)
74 }
75}
76
77#[derive(From, RefCast)]
83#[repr(transparent)]
84pub struct DiscreteCategory<S: Set>(S);
85
86impl<S: Set> Category for DiscreteCategory<S> {
87 type Ob = S::Elem;
88 type Mor = S::Elem;
89
90 fn has_ob(&self, x: &S::Elem) -> bool {
91 self.0.contains(x)
92 }
93 fn has_mor(&self, f: &S::Elem) -> bool {
94 self.0.contains(f)
95 }
96 fn dom(&self, x: &S::Elem) -> S::Elem {
97 x.clone()
98 }
99 fn cod(&self, x: &S::Elem) -> S::Elem {
100 x.clone()
101 }
102
103 fn compose(&self, path: Path<S::Elem, S::Elem>) -> S::Elem {
104 match path {
105 Path::Id(x) => x,
106 Path::Seq(xs) => {
107 let x = xs.head;
108 assert!(
109 xs.tail.into_iter().all(|y| x == y),
110 "Cannot compose identities on different objects"
111 );
112 x
113 }
114 }
115 }
116}
117
118#[derive(From, RefCast)]
124#[repr(transparent)]
125pub struct UnderlyingGraph<Cat: Category>(Cat);
126
127impl<Cat: Category> Graph for UnderlyingGraph<Cat> {
128 type V = Cat::Ob;
129 type E = Cat::Mor;
130
131 fn has_vertex(&self, x: &Self::V) -> bool {
132 self.0.has_ob(x)
133 }
134 fn has_edge(&self, f: &Self::E) -> bool {
135 self.0.has_mor(f)
136 }
137 fn src(&self, f: &Self::E) -> Self::V {
138 self.0.dom(f)
139 }
140 fn tgt(&self, f: &Self::E) -> Self::V {
141 self.0.cod(f)
142 }
143}
144
145#[derive(From, RefCast)]
151#[repr(transparent)]
152pub struct FreeCategory<G: Graph>(G);
153
154impl<G: Graph> Category for FreeCategory<G> {
155 type Ob = G::V;
156 type Mor = Path<G::V, G::E>;
157
158 fn has_ob(&self, x: &G::V) -> bool {
159 self.0.has_vertex(x)
160 }
161 fn has_mor(&self, path: &Path<G::V, G::E>) -> bool {
162 path.contained_in(&self.0)
163 }
164 fn dom(&self, path: &Path<G::V, G::E>) -> G::V {
165 path.src(&self.0)
166 }
167 fn cod(&self, path: &Path<G::V, G::E>) -> G::V {
168 path.tgt(&self.0)
169 }
170
171 fn compose(&self, path: Path<G::V, Path<G::V, G::E>>) -> Path<G::V, G::E> {
172 path.flatten_in(&self.0).expect("Paths should be composable")
173 }
174 fn compose2(&self, path1: Path<G::V, G::E>, path2: Path<G::V, G::E>) -> Path<G::V, G::E> {
175 path1
176 .concat_in(&self.0, path2)
177 .expect("Target of first path should equal source of second path")
178 }
179}
180
181pub trait FgCategory: Category {
190 type ObGen: Eq + Clone + Into<Self::Ob>;
195
196 type MorGen: Eq + Clone + Into<Self::Mor>;
201
202 fn ob_generators(&self) -> impl Iterator<Item = Self::ObGen>;
204
205 fn mor_generators(&self) -> impl Iterator<Item = Self::MorGen>;
207
208 fn mor_generator_dom(&self, f: &Self::MorGen) -> Self::Ob;
210
211 fn mor_generator_cod(&self, f: &Self::MorGen) -> Self::Ob;
213
214 fn objects(&self) -> impl Iterator<Item = Self::Ob> {
216 self.ob_generators().map(|ob_gen| ob_gen.into())
217 }
218
219 fn morphisms(&self) -> impl Iterator<Item = Self::Mor> {
221 self.mor_generators().map(|mor_gen| mor_gen.into())
222 }
223}
224
225impl<S: FinSet> FgCategory for DiscreteCategory<S> {
226 type ObGen = S::Elem;
227 type MorGen = S::Elem;
228
229 fn ob_generators(&self) -> impl Iterator<Item = Self::ObGen> {
230 self.0.iter()
231 }
232
233 fn mor_generators(&self) -> impl Iterator<Item = Self::MorGen> {
234 self.0.iter()
235 }
236
237 fn mor_generator_dom(&self, f: &Self::MorGen) -> Self::Ob {
238 f.clone()
239 }
240
241 fn mor_generator_cod(&self, f: &Self::MorGen) -> Self::Ob {
242 f.clone()
243 }
244}
245
246impl<G: FinGraph> FgCategory for FreeCategory<G> {
247 type ObGen = G::V;
248 type MorGen = G::E;
249
250 fn ob_generators(&self) -> impl Iterator<Item = Self::ObGen> {
251 self.0.vertices()
252 }
253
254 fn mor_generators(&self) -> impl Iterator<Item = Self::MorGen> {
255 self.0.edges()
256 }
257
258 fn mor_generator_dom(&self, f: &Self::MorGen) -> Self::Ob {
259 self.0.src(f)
260 }
261
262 fn mor_generator_cod(&self, f: &Self::MorGen) -> Self::Ob {
263 self.0.tgt(f)
264 }
265}
266
267#[cfg(test)]
268mod tests {
269 use nonempty::nonempty;
270
271 use super::super::graph::SkelGraph;
272 use super::*;
273 use crate::zero::SkelFinSet;
274
275 #[test]
276 fn discrete_category() {
277 let cat = DiscreteCategory::from(SkelFinSet::from(3));
278 assert!(cat.has_ob(&2));
279 assert!(cat.has_mor(&2));
280 assert!(!cat.has_mor(&3));
281 assert_eq!(cat.dom(&1), 1);
282 assert_eq!(cat.cod(&1), 1);
283 assert_eq!(cat.compose(Path::Seq(nonempty![1, 1, 1])), 1);
284 }
285
286 #[test]
287 fn free_category() {
288 let cat = FreeCategory::from(SkelGraph::triangle());
289 assert!(cat.has_ob(&2));
290 assert_eq!(cat.ob_generators().count(), 3);
291 assert_eq!(cat.mor_generators().count(), 3);
292
293 let id = Path::Id(1);
294 assert!(cat.has_mor(&id));
295 assert_eq!(cat.dom(&id), 1);
296 assert_eq!(cat.cod(&id), 1);
297
298 let path = Path::pair(0, 1);
299 assert!(cat.has_mor(&path));
300 assert!(!cat.has_mor(&Path::pair(0, 2)));
301 assert_eq!(cat.dom(&path), 0);
302 assert_eq!(cat.cod(&path), 2);
303
304 let cat = FreeCategory::from(SkelGraph::path(5));
305 let path = Path::Seq(nonempty![
306 Path::Id(0),
307 Path::pair(0, 1),
308 Path::Id(2),
309 Path::pair(2, 3),
310 Path::Id(4),
311 ]);
312 let result = Path::Seq(nonempty![0, 1, 2, 3]);
313 assert_eq!(cat.compose(path), result);
314 assert_eq!(cat.compose2(Path::pair(0, 1), Path::pair(2, 3)), result);
315 }
316}