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}