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