catlog/dbl/
theory.rs

1/*! Double theories.
2
3A double theory specifies a categorical structure, meaning a category (or
4categories) equipped with extra structure. The spirit of the formalism is that a
5double theory is "just" a [virtual double category](super::category),
6categorifying Lawvere's idea that a theory is "just" a category. Thus, a double
7theory is a [concept with an
8attitude](https://ncatlab.org/nlab/show/concept+with+an+attitude). To bring out
9these intuitions, the interface for double theories, [`DblTheory`], introduces
10new terminology compared to the references cited below.
11
12# Terminology
13
14A double theory comprises four kinds of things:
15
161. **Object type**, interpreted in models as a set of objects.
17
182. **Morphism type**, having a source and a target object type and interpreted
19   in models as a span of morphisms (or
20   [heteromorphisms](https://ncatlab.org/nlab/show/heteromorphism)) between sets
21   of objects.
22
233. **Object operation**, interpreted in models as a function between sets of
24   objects.
25
264. **Morphism operation**, having a source and target object operation and
27   interpreted in models as map between spans of morphisms.
28
29The dictionary between the type-theoretic and double-categorical terminology is
30summarized by the table:
31
32| Associated type                 | Double theory      | Double category           | Interpreted as |
33|---------------------------------|--------------------|---------------------------|----------------|
34| [`ObType`](DblTheory::ObType)   | Object type        | Object                    | Set            |
35| [`MorType`](DblTheory::MorType) | Morphism type      | Proarrow (loose morphism) | Span           |
36| [`ObOp`](DblTheory::ObOp)       | Object operation   | Arrow (tight morphism)    | Function       |
37| [`MorOp`](DblTheory::MorOp)     | Morphism operation | Cell                      | Map of spans   |
38
39Models of a double theory are *categorical* structures, rather than merely
40*set-theoretical* ones, because each object type is assigned not just a set of
41objects but also a span of morphisms between those objects, constituting a
42category. The morphisms come from a distinguished "Hom" morphism type for each
43object type in the double theory. Similarly, each object operation is not just a
44function but a functor because it comes with an "Hom" operation between the Hom
45types. Moreover, morphism types can be composed to give new ones, as summarized
46by the table:
47
48| Method                                      | Double theory          | Double category        |
49|---------------------------------------------|------------------------|------------------------|
50| [`hom_type`](DblTheory::hom_type)           | Hom type               | Identity proarrow      |
51| [`hom_op`](DblTheory::hom_op)               | Hom operation          | Identity cell on arrow |
52| [`compose_types`](DblTheory::compose_types) | Compose morphism types | Compose proarrows      |
53
54Finally, operations on both objects and morphisms have identities and can be
55composed:
56
57| Method                                          | Double theory                       | Double category           |
58|-------------------------------------------------|-------------------------------------|---------------------------|
59| [`id_ob_op`](DblTheory::id_ob_op)               | Identity operation on object type   | Identity arrow            |
60| [`id_mor_op`](DblTheory::id_mor_op)             | Identity operation on morphism type | Identity cell on proarrow |
61| [`compose_ob_ops`](DblTheory::compose_ob_ops)   | Compose object operations           | Compose arrows            |
62| [`compose_mor_ops`](DblTheory::compose_mor_ops) | Compose morphism operations         | Compose cells             |
63
64# References
65
66- [Lambert & Patterson, 2024](crate::refs::CartDblTheories)
67- [Patterson, 2024](crate::refs::DblProducts),
68  Section 10: Finite-product double theories
69*/
70
71use super::{category::*, tree::*};
72use crate::one::{Path, tree::OpenTree};
73
74pub use super::discrete::theory::*;
75pub use super::discrete_tabulator::theory::*;
76
77/** A double theory.
78
79A double theory is "just" a virtual double category (VDC) assumed to have units.
80Reflecting this, this trait has a blanket implementation for any
81[`VDblCategory`]. It is not recommended to implement this trait directly.
82
83See the [module-level docs](super::theory) for background on the terminology.
84 */
85pub trait DblTheory {
86    /** Rust type of object types in the theory.
87
88    Viewing the double theory as a virtual double category, this is the type of
89    objects.
90    */
91    type ObType: Eq + Clone;
92
93    /** Rust type of morphism types in the theory.
94
95    Viewing the double theory as a virtual double category, this is the type of
96    proarrows.
97    */
98    type MorType: Eq + Clone;
99
100    /** Rust type of operations on objects in the double theory.
101
102    Viewing the double theory as a virtual double category, this is the type of
103    arrows.
104    */
105    type ObOp: Eq + Clone;
106
107    /** Rust type of operations on morphisms in the double theory.
108
109    Viewing the double theory as a virtual double category, this is the type of
110    cells.
111    */
112    type MorOp: Eq + Clone;
113
114    /// Does the object type belong to the theory?
115    fn has_ob_type(&self, x: &Self::ObType) -> bool;
116
117    /// Does the morphism type belong to the theory?
118    fn has_mor_type(&self, m: &Self::MorType) -> bool;
119
120    /// Does the object operation belong to the theory?
121    fn has_ob_op(&self, f: &Self::ObOp) -> bool;
122
123    /// Does the morphism operation belong to the theory?
124    fn has_mor_op(&self, α: &Self::MorOp) -> bool;
125
126    /// Source of a morphism type.
127    fn src_type(&self, m: &Self::MorType) -> Self::ObType;
128
129    /// Target of a morphism type.
130    fn tgt_type(&self, m: &Self::MorType) -> Self::ObType;
131
132    /// Domain of an operation on objects.
133    fn ob_op_dom(&self, f: &Self::ObOp) -> Self::ObType;
134
135    /// Codomain of an operation on objects.
136    fn ob_op_cod(&self, f: &Self::ObOp) -> Self::ObType;
137
138    /// Source operation of an operation on morphisms.
139    fn src_op(&self, α: &Self::MorOp) -> Self::ObOp;
140
141    /// Target operation of an operation on morphisms.
142    fn tgt_op(&self, α: &Self::MorOp) -> Self::ObOp;
143
144    /// Domain of an operation on morphisms, a path of morphism types.
145    fn mor_op_dom(&self, α: &Self::MorOp) -> Path<Self::ObType, Self::MorType>;
146
147    /// Codomain of an operation on morphisms, a single morphism type.
148    fn mor_op_cod(&self, α: &Self::MorOp) -> Self::MorType;
149
150    /// Composes a sequence of morphism types, if they have a composite.
151    fn compose_types(&self, path: Path<Self::ObType, Self::MorType>) -> Option<Self::MorType>;
152
153    /** Hom morphism type on an object type.
154
155    Viewing the double theory as a virtual double category, this is the unit
156    proarrow on an object.
157    */
158    fn hom_type(&self, x: Self::ObType) -> Self::MorType {
159        self.compose_types(Path::Id(x))
160            .expect("A double theory should have a hom type for each object type")
161    }
162
163    /// Compose a sequence of operations on objects.
164    fn compose_ob_ops(&self, path: Path<Self::ObType, Self::ObOp>) -> Self::ObOp;
165
166    /** Identity operation on an object type.
167
168    View the double theory as a virtual double category, this is the identity
169    arrow on an object.
170    */
171    fn id_ob_op(&self, x: Self::ObType) -> Self::ObOp {
172        self.compose_ob_ops(Path::Id(x))
173    }
174
175    /** Hom morphism operation on an object operation.
176
177    Viewing the double theory as a virtual double category, this is the unit
178    cell on an arrow.
179     */
180    fn hom_op(&self, f: Self::ObOp) -> Self::MorOp;
181
182    /// Compose operations on morphisms.
183    fn compose_mor_ops(&self, tree: DblTree<Self::ObOp, Self::MorType, Self::MorOp>)
184    -> Self::MorOp;
185
186    /** Identity operation on a morphism type.
187
188    Viewing the double theory as a virtual double category, this is the identity
189    cell on a proarrow.
190    */
191    fn id_mor_op(&self, m: Self::MorType) -> Self::MorOp {
192        self.compose_mor_ops(DblTree::empty(m))
193    }
194}
195
196impl<VDC: VDCWithComposites> DblTheory for VDC {
197    type ObType = VDC::Ob;
198    type MorType = VDC::Pro;
199    type ObOp = VDC::Arr;
200    type MorOp = VDC::Cell;
201
202    fn has_ob_type(&self, x: &Self::ObType) -> bool {
203        self.has_ob(x)
204    }
205    fn has_mor_type(&self, m: &Self::MorType) -> bool {
206        self.has_proarrow(m)
207    }
208    fn has_ob_op(&self, f: &Self::ObOp) -> bool {
209        self.has_arrow(f)
210    }
211    fn has_mor_op(&self, α: &Self::MorOp) -> bool {
212        self.has_cell(α)
213    }
214
215    fn src_type(&self, m: &Self::MorType) -> Self::ObType {
216        self.src(m)
217    }
218    fn tgt_type(&self, m: &Self::MorType) -> Self::ObType {
219        self.tgt(m)
220    }
221    fn ob_op_dom(&self, f: &Self::ObOp) -> Self::ObType {
222        self.dom(f)
223    }
224    fn ob_op_cod(&self, f: &Self::ObOp) -> Self::ObType {
225        self.cod(f)
226    }
227
228    fn src_op(&self, α: &Self::MorOp) -> Self::ObOp {
229        self.cell_src(α)
230    }
231    fn tgt_op(&self, α: &Self::MorOp) -> Self::ObOp {
232        self.cell_tgt(α)
233    }
234    fn mor_op_dom(&self, α: &Self::MorOp) -> Path<Self::ObType, Self::MorType> {
235        self.cell_dom(α)
236    }
237    fn mor_op_cod(&self, α: &Self::MorOp) -> Self::MorType {
238        self.cell_cod(α)
239    }
240
241    fn compose_types(&self, path: Path<Self::ObType, Self::MorType>) -> Option<Self::MorType> {
242        self.composite(path)
243    }
244    fn hom_type(&self, x: Self::ObType) -> Self::MorType {
245        self.unit(x).expect("A double theory should have all hom types")
246    }
247    fn hom_op(&self, f: Self::ObOp) -> Self::MorOp {
248        let y = self.cod(&f);
249        let y_ext = self.unit_ext(y).expect("Codomain of arrow should have hom type");
250        let cell = self.compose_cells(DblTree(
251            OpenTree::linear(vec![DblNode::Spine(f), DblNode::Cell(y_ext)]).unwrap(),
252        ));
253        self.through_unit(cell, 0).expect("Domain of arrow should have hom type")
254    }
255
256    fn compose_ob_ops(&self, path: Path<Self::ObType, Self::ObOp>) -> Self::ObOp {
257        self.compose(path)
258    }
259    fn id_ob_op(&self, x: Self::ObType) -> Self::ObOp {
260        self.id(x)
261    }
262
263    fn compose_mor_ops(
264        &self,
265        tree: DblTree<Self::ObOp, Self::MorType, Self::MorOp>,
266    ) -> Self::MorOp {
267        self.compose_cells(tree)
268    }
269    fn id_mor_op(&self, m: Self::MorType) -> Self::MorOp {
270        self.id_cell(m)
271    }
272}