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 nonempty::NonEmpty;
72
73use super::{category::*, graph::InvalidVDblGraph, tree::*};
74use crate::one::{InvalidPathEq, Path, tree::OpenTree};
75use crate::zero::QualifiedName;
76
77pub use super::discrete::theory::*;
78pub use super::discrete_tabulator::theory::*;
79pub use super::modal::theory::*;
80
81/** A double theory.
82
83A double theory is "just" a virtual double category (VDC) assumed to have units.
84Reflecting this, this trait has a blanket implementation for any
85[`VDblCategory`]. It is not recommended to implement this trait directly.
86
87See the [module-level docs](super::theory) for background on the terminology.
88 */
89pub trait DblTheory {
90 /** Rust type of object types in the theory.
91
92 Viewing the double theory as a virtual double category, this is the type of
93 objects.
94 */
95 type ObType: Eq + Clone;
96
97 /** Rust type of morphism types in the theory.
98
99 Viewing the double theory as a virtual double category, this is the type of
100 proarrows.
101 */
102 type MorType: Eq + Clone;
103
104 /** Rust type of operations on objects in the double theory.
105
106 Viewing the double theory as a virtual double category, this is the type of
107 arrows.
108 */
109 type ObOp: Eq + Clone;
110
111 /** Rust type of operations on morphisms in the double theory.
112
113 Viewing the double theory as a virtual double category, this is the type of
114 cells.
115 */
116 type MorOp: Eq + Clone;
117
118 /// Does the object type belong to the theory?
119 fn has_ob_type(&self, x: &Self::ObType) -> bool;
120
121 /// Does the morphism type belong to the theory?
122 fn has_mor_type(&self, m: &Self::MorType) -> bool;
123
124 /// Does the object operation belong to the theory?
125 fn has_ob_op(&self, f: &Self::ObOp) -> bool;
126
127 /// Does the morphism operation belong to the theory?
128 fn has_mor_op(&self, α: &Self::MorOp) -> bool;
129
130 /// Source of a morphism type.
131 fn src_type(&self, m: &Self::MorType) -> Self::ObType;
132
133 /// Target of a morphism type.
134 fn tgt_type(&self, m: &Self::MorType) -> Self::ObType;
135
136 /// Domain of an operation on objects.
137 fn ob_op_dom(&self, f: &Self::ObOp) -> Self::ObType;
138
139 /// Codomain of an operation on objects.
140 fn ob_op_cod(&self, f: &Self::ObOp) -> Self::ObType;
141
142 /// Source operation of an operation on morphisms.
143 fn src_op(&self, α: &Self::MorOp) -> Self::ObOp;
144
145 /// Target operation of an operation on morphisms.
146 fn tgt_op(&self, α: &Self::MorOp) -> Self::ObOp;
147
148 /// Domain of an operation on morphisms, a path of morphism types.
149 fn mor_op_dom(&self, α: &Self::MorOp) -> Path<Self::ObType, Self::MorType>;
150
151 /// Codomain of an operation on morphisms, a single morphism type.
152 fn mor_op_cod(&self, α: &Self::MorOp) -> Self::MorType;
153
154 /// Composes a sequence of morphism types, if they have a composite.
155 fn compose_types(&self, path: Path<Self::ObType, Self::MorType>) -> Option<Self::MorType>;
156
157 /** Hom morphism type on an object type.
158
159 Viewing the double theory as a virtual double category, this is the unit
160 proarrow on an object.
161 */
162 fn hom_type(&self, x: Self::ObType) -> Self::MorType {
163 self.compose_types(Path::Id(x))
164 .expect("A double theory should have a hom type for each object type")
165 }
166
167 /// Compose a sequence of operations on objects.
168 fn compose_ob_ops(&self, path: Path<Self::ObType, Self::ObOp>) -> Self::ObOp;
169
170 /** Identity operation on an object type.
171
172 View the double theory as a virtual double category, this is the identity
173 arrow on an object.
174 */
175 fn id_ob_op(&self, x: Self::ObType) -> Self::ObOp {
176 self.compose_ob_ops(Path::Id(x))
177 }
178
179 /** Hom morphism operation on an object operation.
180
181 Viewing the double theory as a virtual double category, this is the unit
182 cell on an arrow.
183 */
184 fn hom_op(&self, f: Self::ObOp) -> Self::MorOp;
185
186 /// Compose operations on morphisms.
187 fn compose_mor_ops(&self, tree: DblTree<Self::ObOp, Self::MorType, Self::MorOp>)
188 -> Self::MorOp;
189
190 /** Identity operation on a morphism type.
191
192 Viewing the double theory as a virtual double category, this is the identity
193 cell on a proarrow.
194 */
195 fn id_mor_op(&self, m: Self::MorType) -> Self::MorOp {
196 self.compose_mor_ops(DblTree::empty(m))
197 }
198}
199
200impl<VDC: VDCWithComposites> DblTheory for VDC {
201 type ObType = VDC::Ob;
202 type MorType = VDC::Pro;
203 type ObOp = VDC::Arr;
204 type MorOp = VDC::Cell;
205
206 fn has_ob_type(&self, x: &Self::ObType) -> bool {
207 self.has_ob(x)
208 }
209 fn has_mor_type(&self, m: &Self::MorType) -> bool {
210 self.has_proarrow(m)
211 }
212 fn has_ob_op(&self, f: &Self::ObOp) -> bool {
213 self.has_arrow(f)
214 }
215 fn has_mor_op(&self, α: &Self::MorOp) -> bool {
216 self.has_cell(α)
217 }
218
219 fn src_type(&self, m: &Self::MorType) -> Self::ObType {
220 self.src(m)
221 }
222 fn tgt_type(&self, m: &Self::MorType) -> Self::ObType {
223 self.tgt(m)
224 }
225 fn ob_op_dom(&self, f: &Self::ObOp) -> Self::ObType {
226 self.dom(f)
227 }
228 fn ob_op_cod(&self, f: &Self::ObOp) -> Self::ObType {
229 self.cod(f)
230 }
231
232 fn src_op(&self, α: &Self::MorOp) -> Self::ObOp {
233 self.cell_src(α)
234 }
235 fn tgt_op(&self, α: &Self::MorOp) -> Self::ObOp {
236 self.cell_tgt(α)
237 }
238 fn mor_op_dom(&self, α: &Self::MorOp) -> Path<Self::ObType, Self::MorType> {
239 self.cell_dom(α)
240 }
241 fn mor_op_cod(&self, α: &Self::MorOp) -> Self::MorType {
242 self.cell_cod(α)
243 }
244
245 fn compose_types(&self, path: Path<Self::ObType, Self::MorType>) -> Option<Self::MorType> {
246 self.composite(path)
247 }
248 fn hom_type(&self, x: Self::ObType) -> Self::MorType {
249 self.unit(x).expect("A double theory should have all hom types")
250 }
251 fn hom_op(&self, f: Self::ObOp) -> Self::MorOp {
252 let y = self.cod(&f);
253 let y_ext = self.unit_ext(y).expect("Codomain of arrow should have hom type");
254 let cell = self.compose_cells(DblTree(
255 OpenTree::linear(vec![DblNode::Spine(f), DblNode::Cell(y_ext)]).unwrap(),
256 ));
257 self.through_unit(cell, 0).expect("Domain of arrow should have hom type")
258 }
259
260 fn compose_ob_ops(&self, path: Path<Self::ObType, Self::ObOp>) -> Self::ObOp {
261 self.compose(path)
262 }
263 fn id_ob_op(&self, x: Self::ObType) -> Self::ObOp {
264 self.id(x)
265 }
266
267 fn compose_mor_ops(
268 &self,
269 tree: DblTree<Self::ObOp, Self::MorType, Self::MorOp>,
270 ) -> Self::MorOp {
271 self.compose_cells(tree)
272 }
273 fn id_mor_op(&self, m: Self::MorType) -> Self::MorOp {
274 self.id_cell(m)
275 }
276}
277
278/// A failure of a double theory to be well defined.
279#[derive(Debug)]
280pub enum InvalidDblTheory {
281 /// Morphism type with an invalid source type.
282 SrcType(QualifiedName),
283
284 /// Morphism type with an invalid target type.
285 TgtType(QualifiedName),
286
287 /// Object operation with an invalid domain.
288 ObOpDom(QualifiedName),
289
290 /// Object operation with an invalid codomain.
291 ObOpCod(QualifiedName),
292
293 /// Morphism operation with an invalid domain.
294 MorOpDom(QualifiedName),
295
296 /// Morphism operation with an invalid codomain.
297 MorOpCod(QualifiedName),
298
299 /// Morphism operation with an invalid source operation.
300 SrcOp(QualifiedName),
301
302 /// Morphism operation with an invalid target operation.
303 TgtOp(QualifiedName),
304
305 /// Morphism operation having a boundary with incompatible corners.
306 MorOpBoundary(QualifiedName),
307
308 /// Equation between morphism types with one or more errors.
309 MorTypeEq(usize, NonEmpty<InvalidPathEq>),
310
311 /// Equation between object operations with one or more errors.
312 ObOpEq(usize, NonEmpty<InvalidPathEq>),
313}
314
315impl From<InvalidVDblGraph<QualifiedName, QualifiedName, QualifiedName>> for InvalidDblTheory {
316 fn from(err: InvalidVDblGraph<QualifiedName, QualifiedName, QualifiedName>) -> Self {
317 match err {
318 InvalidVDblGraph::Dom(id) => InvalidDblTheory::ObOpDom(id),
319 InvalidVDblGraph::Cod(id) => InvalidDblTheory::ObOpCod(id),
320 InvalidVDblGraph::Src(id) => InvalidDblTheory::SrcType(id),
321 InvalidVDblGraph::Tgt(id) => InvalidDblTheory::TgtType(id),
322 InvalidVDblGraph::SquareDom(id) => InvalidDblTheory::MorOpDom(id),
323 InvalidVDblGraph::SquareCod(id) => InvalidDblTheory::MorOpCod(id),
324 InvalidVDblGraph::SquareSrc(id) => InvalidDblTheory::SrcOp(id),
325 InvalidVDblGraph::SquareTgt(id) => InvalidDblTheory::TgtOp(id),
326 InvalidVDblGraph::NotSquare(id) => InvalidDblTheory::MorOpBoundary(id),
327 }
328 }
329}