Skip to content

Commit c3e5ee2

Browse files
author
tslil-topos
committed
feature: allow non-unital theories to be meaningfully non-unital
Before this change the blanket impl `impl<Kind: DblTheoryKind> VDCWithComposites for ModalDblTheory<Kind>` would always give a unit pro-arrow to every object, which is semantically too powerful. In order to allow _particular_ modal double theories to specify which objects ("types") are unital ("categorical" in their semantics) we need to track some state on the struct. The approach taken in this change is to extend the API of DblTheoryKind minimally with `type TypesWithUnits<X>: Default;` and ```rust fn has_unit<Ob: Eq + Hash>( unitful_types: &Self::TypesWithUnits<Ob>, ob: &Ob, ) -> bool; ``` In the case of Unital theories TypesWithUnits is `()`, but for NonUnital it's `HashSet`. In the latter case ModalDblTheory grows `pub fn add_unit(&mut self, ob_type: ModalObType)`.
1 parent 7c4408a commit c3e5ee2

4 files changed

Lines changed: 60 additions & 13 deletions

File tree

packages/catlog/src/dbl/modal/model.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl MorListData {
7474

7575
/// A model of a modal double theory.
7676
#[derive(Clone)]
77-
pub struct ModalDblModel<Kind> {
77+
pub struct ModalDblModel<Kind: DblTheoryKind> {
7878
theory: Rc<ModalDblTheory<Kind>>,
7979
ob_generators: HashFinSet<QualifiedName>,
8080
mor_generators: ComputadTop<ModalOb, QualifiedName>,
@@ -104,7 +104,7 @@ impl<Kind: DblTheoryKind> ModalDblModel<Kind> {
104104

105105
#[derive(RefCast)]
106106
#[repr(transparent)]
107-
struct ModalDblModelObs<Kind>(ModalDblModel<Kind>);
107+
struct ModalDblModelObs<Kind: DblTheoryKind>(ModalDblModel<Kind>);
108108

109109
impl<Kind: DblTheoryKind> Set for ModalDblModelObs<Kind> {
110110
type Elem = ModalOb;

packages/catlog/src/dbl/modal/theory.rs

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use indexmap::IndexMap;
2929
use ref_cast::RefCast;
3030

3131
use crate::dbl::computad::{AVDCComputad, AVDCComputadTop};
32-
use crate::dbl::theory::{DblTheoryKind, InvalidDblTheory};
32+
use crate::dbl::theory::{DblTheoryKind, InvalidDblTheory, NonUnital};
3333
use crate::dbl::{DblTree, InvalidVDblGraph, VDCWithComposites, VDblCategory, VDblGraph};
3434
use crate::one::computad::{Computad, ComputadTop};
3535
use crate::validate::{self, Validate};
@@ -258,21 +258,22 @@ pub type ModalMorOp = DblTree<ModalObOp, ModalMorType, ModalNode>;
258258
/// A modal double theory.
259259
#[derive(Debug, Derivative)]
260260
#[derivative(Default(new = "true"))]
261-
pub struct ModalDblTheory<Kind> {
261+
pub struct ModalDblTheory<Kind: DblTheoryKind> {
262262
_kind: PhantomData<Kind>,
263263
ob_generators: HashFinSet<QualifiedName>,
264264
arr_generators: ComputadTop<ModalObType, QualifiedName>,
265265
pro_generators: ComputadTop<ModalObType, QualifiedName>,
266266
cell_generators: AVDCComputadTop<ModalObType, ModalObOp, ModalMorType, QualifiedName>,
267267
arr_equations: Vec<PathEq<ModalObType, ModeApp<ModalOp>>>,
268268
pro_composites: IndexMap<(ModalType, ModalType), ModalMorType>,
269+
_unitful_types: Kind::TypesWithUnits<ModalObType>,
269270
// TODO: Cell equations
270271
}
271272

272273
/// Set of object types in a modal double theory.
273274
#[derive(RefCast)]
274275
#[repr(transparent)]
275-
pub(super) struct ModalObTypes<Kind>(ModalDblTheory<Kind>);
276+
pub(super) struct ModalObTypes<Kind: DblTheoryKind>(ModalDblTheory<Kind>);
276277

277278
impl<Kind: DblTheoryKind> Set for ModalObTypes<Kind> {
278279
type Elem = ModalObType;
@@ -285,7 +286,7 @@ impl<Kind: DblTheoryKind> Set for ModalObTypes<Kind> {
285286
/// Graph of object types and *basic* morphism types in a modal double theory.
286287
#[derive(RefCast)]
287288
#[repr(transparent)]
288-
struct ModalProedgeGraph<Kind>(ModalDblTheory<Kind>);
289+
struct ModalProedgeGraph<Kind: DblTheoryKind>(ModalDblTheory<Kind>);
289290

290291
impl<Kind: DblTheoryKind> Graph for ModalProedgeGraph<Kind> {
291292
type V = ModalObType;
@@ -308,7 +309,7 @@ impl<Kind: DblTheoryKind> Graph for ModalProedgeGraph<Kind> {
308309
/// Graph of object/morphism types in a modal double theory.
309310
#[derive(RefCast)]
310311
#[repr(transparent)]
311-
pub(super) struct ModalMorTypeGraph<Kind>(ModalDblTheory<Kind>);
312+
pub(super) struct ModalMorTypeGraph<Kind: DblTheoryKind>(ModalDblTheory<Kind>);
312313

313314
impl<Kind: DblTheoryKind> Graph for ModalMorTypeGraph<Kind> {
314315
type V = ModalObType;
@@ -337,7 +338,7 @@ impl<Kind: DblTheoryKind> ReflexiveGraph for ModalMorTypeGraph<Kind> {
337338
/// Graph of object types and *basic* object operations in a modal theory.
338339
#[derive(RefCast)]
339340
#[repr(transparent)]
340-
struct ModalEdgeGraph<Kind>(ModalDblTheory<Kind>);
341+
struct ModalEdgeGraph<Kind: DblTheoryKind>(ModalDblTheory<Kind>);
341342

342343
impl<Kind: DblTheoryKind> Graph for ModalEdgeGraph<Kind> {
343344
type V = ModalObType;
@@ -371,7 +372,7 @@ impl<Kind: DblTheoryKind> Graph for ModalEdgeGraph<Kind> {
371372
/// Category of object types/operations in a modal double theory.
372373
#[derive(RefCast)]
373374
#[repr(transparent)]
374-
pub(super) struct ModalOneTheory<Kind>(ModalDblTheory<Kind>);
375+
pub(super) struct ModalOneTheory<Kind: DblTheoryKind>(ModalDblTheory<Kind>);
375376

376377
impl<Kind: DblTheoryKind> Category for ModalOneTheory<Kind> {
377378
type Ob = ModalObType;
@@ -397,7 +398,7 @@ impl<Kind: DblTheoryKind> Category for ModalOneTheory<Kind> {
397398
/// Virtual double graph of *basic* cells in a modal double theory.
398399
#[derive(RefCast)]
399400
#[repr(transparent)]
400-
struct ModalVDblGraph<Kind>(ModalDblTheory<Kind>);
401+
struct ModalVDblGraph<Kind: DblTheoryKind>(ModalDblTheory<Kind>);
401402

402403
type ModalVDblComputad<'a, Kind> = AVDCComputad<
403404
'a,
@@ -626,7 +627,13 @@ impl<Kind: DblTheoryKind> VDCWithComposites for ModalDblTheory<Kind> {
626627

627628
fn composite(&self, path: Path<Self::Ob, Self::Pro>) -> Option<Self::Pro> {
628629
match path {
629-
Path::Id(x) => Some(ShortPath::Zero(x)),
630+
Path::Id(x) => {
631+
if Kind::has_unit(&self._unitful_types, &x) {
632+
Some(ShortPath::Zero(x))
633+
} else {
634+
None
635+
}
636+
}
630637
Path::Seq(ms) => {
631638
if ms.len() == 1 {
632639
Some(ms.head)
@@ -758,3 +765,13 @@ impl<Kind: DblTheoryKind> ModalDblTheory<Kind> {
758765
self.pro_composites.insert((fst, snd), composite);
759766
}
760767
}
768+
769+
impl ModalDblTheory<NonUnital> {
770+
/// Adds a unit proarrow for an object type in a non-unital theory.
771+
///
772+
/// In a non-unital theory, object types do not automatically have unit
773+
/// proarrows (hom types). This method explicitly grants one.
774+
pub fn add_unit(&mut self, ob_type: ModalObType) {
775+
self._unitful_types.insert(ob_type);
776+
}
777+
}

packages/catlog/src/dbl/theory.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@
6767
//! - [Patterson, 2024](crate::refs::DblProducts),
6868
//! Section 10: Finite-product double theories
6969
70-
use std::fmt;
70+
use std::collections::HashSet;
71+
use std::hash::Hash;
7172

7273
use nonempty::NonEmpty;
7374

@@ -98,18 +99,31 @@ mod private {
9899
/// This trait is [sealed] and cannot be implemented outside this crate.
99100
///
100101
/// [sealed]: https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed
101-
pub trait DblTheoryKind: fmt::Debug + private::Sealed {
102+
pub trait DblTheoryKind: private::Sealed {
102103
/// Wraps a type to reflect whether values are guaranteed to exist.
103104
///
104105
/// For [`Unital`], this is the identity (`T`).
105106
/// For [`NonUnital`], this is `Option<T>`.
106107
type Wrap<T>;
107108

109+
/// State tracking which object types have unit proarrows.
110+
///
111+
/// For [`Unital`], this is `()` (all object types have units).
112+
/// For [`NonUnital`], this is `HashSet<X>` (only explicitly
113+
/// registered object types have units).
114+
type TypesWithUnits<X>: Default;
115+
108116
/// Converts from an `Option` into a wrapped value.
109117
///
110118
/// For [`Unital`], this unwraps with the given message.
111119
/// For [`NonUnital`], this is the identity.
112120
fn from_option<T>(opt: Option<T>, msg: &str) -> Self::Wrap<T>;
121+
122+
/// Does the given object type have a unit proarrow?
123+
///
124+
/// For [`Unital`], this always returns `true`.
125+
/// For [`NonUnital`], this checks the provided set of unitful types.
126+
fn has_unit<Ob: Eq + Hash>(unitful_types: &Self::TypesWithUnits<Ob>, ob: &Ob) -> bool;
113127
}
114128

115129
/// Unital double theories guarantee that every object type has a hom type.
@@ -121,10 +135,15 @@ pub struct Unital;
121135

122136
impl DblTheoryKind for Unital {
123137
type Wrap<T> = T;
138+
type TypesWithUnits<X> = ();
124139

125140
fn from_option<T>(opt: Option<T>, msg: &str) -> T {
126141
opt.expect(msg)
127142
}
143+
144+
fn has_unit<Ob: Eq + Hash>(_unitful_types: &(), _ob: &Ob) -> bool {
145+
true
146+
}
128147
}
129148

130149
/// Set-theoretic double theories make no guarantee that hom types exist.
@@ -136,10 +155,15 @@ pub struct NonUnital;
136155

137156
impl DblTheoryKind for NonUnital {
138157
type Wrap<T> = Option<T>;
158+
type TypesWithUnits<X> = HashSet<X>;
139159

140160
fn from_option<T>(opt: Option<T>, _msg: &str) -> Option<T> {
141161
opt
142162
}
163+
164+
fn has_unit<Ob: Eq + Hash>(unitful_types: &HashSet<Ob>, ob: &Ob) -> bool {
165+
unitful_types.contains(ob)
166+
}
143167
}
144168

145169
/// A double theory.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
2+
3+
/**
4+
* The type/kind of a document, without any associated content.
5+
*/
6+
export type DocumentType = "model" | "diagram" | "analysis";

0 commit comments

Comments
 (0)