Monoidal Structures

Monoidal categories with tensor products, units, and coherence conditions.

monoidal

Monoidal structures on V-enriched FinSet.

A monoidal structure (C, ⊗, I) consists of a bifunctor ⊗, a unit object I, and coherence isomorphisms (associator, unitors, braiding).

This module provides:

MonoidalStructure (abstract)
├── CartesianMonoidal  — (FinSet, ×, 1)
└── CoproductMonoidal  — (FinSet, +, ∅)

MonoidalStructure

Bases: ABC

Abstract monoidal structure on a category.

Provides the monoidal product, unit object, and coherence isomorphisms that witness the monoidal laws.

unit abstractmethod property

unit: SetObject

The monoidal unit I.

product abstractmethod

product(a: SetObject, b: SetObject) -> SetObject

The monoidal product A ⊗ B.

PARAMETER DESCRIPTION
a

Left object.

TYPE: SetObject

b

Right object.

TYPE: SetObject

RETURNS DESCRIPTION
SetObject

The product object.

Source code in src/quivers/categorical/monoidal.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
@abstractmethod
def product(self, a: SetObject, b: SetObject) -> SetObject:
    """The monoidal product A ⊗ B.

    Parameters
    ----------
    a : SetObject
        Left object.
    b : SetObject
        Right object.

    Returns
    -------
    SetObject
        The product object.
    """
    ...

associator abstractmethod

associator(a: SetObject, b: SetObject, c: SetObject) -> ObservedMorphism

The associator (A ⊗ B) ⊗ C → A ⊗ (B ⊗ C).

PARAMETER DESCRIPTION
a

Three objects.

TYPE: SetObject

b

Three objects.

TYPE: SetObject

c

Three objects.

TYPE: SetObject

RETURNS DESCRIPTION
ObservedMorphism

The associator isomorphism.

Source code in src/quivers/categorical/monoidal.py
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
@abstractmethod
def associator(self, a: SetObject, b: SetObject, c: SetObject) -> ObservedMorphism:
    """The associator (A ⊗ B) ⊗ C → A ⊗ (B ⊗ C).

    Parameters
    ----------
    a, b, c : SetObject
        Three objects.

    Returns
    -------
    ObservedMorphism
        The associator isomorphism.
    """
    ...

left_unitor abstractmethod

left_unitor(a: SetObject) -> ObservedMorphism

The left unitor I ⊗ A → A.

PARAMETER DESCRIPTION
a

The object.

TYPE: SetObject

RETURNS DESCRIPTION
ObservedMorphism

The left unitor isomorphism.

Source code in src/quivers/categorical/monoidal.py
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
@abstractmethod
def left_unitor(self, a: SetObject) -> ObservedMorphism:
    """The left unitor I ⊗ A → A.

    Parameters
    ----------
    a : SetObject
        The object.

    Returns
    -------
    ObservedMorphism
        The left unitor isomorphism.
    """
    ...

right_unitor abstractmethod

right_unitor(a: SetObject) -> ObservedMorphism

The right unitor A ⊗ I → A.

PARAMETER DESCRIPTION
a

The object.

TYPE: SetObject

RETURNS DESCRIPTION
ObservedMorphism

The right unitor isomorphism.

Source code in src/quivers/categorical/monoidal.py
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
@abstractmethod
def right_unitor(self, a: SetObject) -> ObservedMorphism:
    """The right unitor A ⊗ I → A.

    Parameters
    ----------
    a : SetObject
        The object.

    Returns
    -------
    ObservedMorphism
        The right unitor isomorphism.
    """
    ...

braiding abstractmethod

braiding(a: SetObject, b: SetObject) -> ObservedMorphism

The braiding A ⊗ B → B ⊗ A.

PARAMETER DESCRIPTION
a

Two objects.

TYPE: SetObject

b

Two objects.

TYPE: SetObject

RETURNS DESCRIPTION
ObservedMorphism

The braiding (swap) isomorphism.

Source code in src/quivers/categorical/monoidal.py
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
@abstractmethod
def braiding(self, a: SetObject, b: SetObject) -> ObservedMorphism:
    """The braiding A ⊗ B → B ⊗ A.

    Parameters
    ----------
    a, b : SetObject
        Two objects.

    Returns
    -------
    ObservedMorphism
        The braiding (swap) isomorphism.
    """
    ...

CartesianMonoidal

CartesianMonoidal(quantale: Quantale | None = None)

Bases: MonoidalStructure

Cartesian monoidal structure: (FinSet, ×, 1).

The product is the cartesian product (ProductSet), the unit is the terminal object (Unit = FinSet(name="1", cardinality=1)).

Since ProductSet auto-flattens, the associator (A×B)×C → A×(B×C) is the identity (both sides flatten to ProductSet(A,B,C)). The braiding A×B → B×A is a permutation tensor.

PARAMETER DESCRIPTION
quantale

The enrichment algebra for coherence morphisms.

TYPE: Quantale or None DEFAULT: None

Source code in src/quivers/categorical/monoidal.py
135
136
def __init__(self, quantale: Quantale | None = None) -> None:
    self._quantale = quantale if quantale is not None else PRODUCT_FUZZY

unit property

unit: FinSet

Terminal object {*}.

product

product(a: SetObject, b: SetObject) -> ProductSet

Cartesian product A × B.

Source code in src/quivers/categorical/monoidal.py
138
139
140
def product(self, a: SetObject, b: SetObject) -> ProductSet:
    """Cartesian product A × B."""
    return ProductSet(components=(a, b))

associator

associator(a: SetObject, b: SetObject, c: SetObject) -> ObservedMorphism

(A × B) × C → A × (B × C).

Since ProductSet flattens, both sides are ProductSet(A,B,C), so this is the identity morphism.

Source code in src/quivers/categorical/monoidal.py
147
148
149
150
151
152
153
154
155
def associator(self, a: SetObject, b: SetObject, c: SetObject) -> ObservedMorphism:
    """(A × B) × C → A × (B × C).

    Since ProductSet flattens, both sides are ProductSet(A,B,C),
    so this is the identity morphism.
    """
    flat = ProductSet(components=(a, b, c))
    data = self._quantale.identity_tensor(flat.shape)
    return observed(flat, flat, data, quantale=self._quantale)

left_unitor

left_unitor(a: SetObject) -> ObservedMorphism

I × A → A (project out the unit component).

The tensor maps (1, a₁, ..., aₙ) → (a₁, ..., aₙ). Since Unit has size 1, this is a "squeeze" that drops the trivial dimension.

Source code in src/quivers/categorical/monoidal.py
157
158
159
160
161
162
163
164
165
166
167
168
169
170
def left_unitor(self, a: SetObject) -> ObservedMorphism:
    """I × A → A (project out the unit component).

    The tensor maps (1, a₁, ..., aₙ) → (a₁, ..., aₙ).
    Since Unit has size 1, this is a "squeeze" that drops
    the trivial dimension.
    """
    source = ProductSet(components=(Unit, a))
    target = a
    data = torch.zeros(*source.shape, *target.shape)
    for idx in itertools.product(*(range(s) for s in target.shape)):
        src = (0,) + idx
        data[src + idx] = self._quantale.unit
    return observed(source, target, data, quantale=self._quantale)

right_unitor

right_unitor(a: SetObject) -> ObservedMorphism

A × I → A (project out the unit component).

The tensor maps (a₁, ..., aₙ, 1) → (a₁, ..., aₙ).

Source code in src/quivers/categorical/monoidal.py
172
173
174
175
176
177
178
179
180
181
182
183
def right_unitor(self, a: SetObject) -> ObservedMorphism:
    """A × I → A (project out the unit component).

    The tensor maps (a₁, ..., aₙ, 1) → (a₁, ..., aₙ).
    """
    source = ProductSet(components=(a, Unit))
    target = a
    data = torch.zeros(*source.shape, *target.shape)
    for idx in itertools.product(*(range(s) for s in target.shape)):
        src = idx + (0,)
        data[src + idx] = self._quantale.unit
    return observed(source, target, data, quantale=self._quantale)

braiding

braiding(a: SetObject, b: SetObject) -> ObservedMorphism

A × B → B × A (swap permutation).

The tensor has shape (a.shape, b.shape, b.shape, a.shape) with unit on entries where the swap holds.

Source code in src/quivers/categorical/monoidal.py
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
def braiding(self, a: SetObject, b: SetObject) -> ObservedMorphism:
    """A × B → B × A (swap permutation).

    The tensor has shape (*a.shape, *b.shape, *b.shape, *a.shape)
    with unit on entries where the swap holds.
    """
    source = ProductSet(components=(a, b))
    target = ProductSet(components=(b, a))
    data = torch.full((*source.shape, *target.shape), self._quantale.zero)
    for a_idx in itertools.product(*(range(s) for s in a.shape)):
        for b_idx in itertools.product(*(range(s) for s in b.shape)):
            src = a_idx + b_idx
            tgt = b_idx + a_idx
            data[src + tgt] = self._quantale.unit
    return observed(source, target, data, quantale=self._quantale)

EmptySet

Bases: SetObject

The initial object (empty set) with cardinality 0.

Used as the unit for coproduct monoidal structure.

CoproductMonoidal

CoproductMonoidal(quantale: Quantale | None = None)

Bases: MonoidalStructure

Coproduct monoidal structure: (FinSet, +, ∅).

The product is the coproduct (CoproductSet), the unit is the initial object (EmptySet with cardinality 0).

PARAMETER DESCRIPTION
quantale

The enrichment algebra for coherence morphisms.

TYPE: Quantale or None DEFAULT: None

Source code in src/quivers/categorical/monoidal.py
240
241
def __init__(self, quantale: Quantale | None = None) -> None:
    self._quantale = quantale if quantale is not None else PRODUCT_FUZZY

unit property

unit: EmptySet

Initial object ∅.

product

product(a: SetObject, b: SetObject) -> CoproductSet

Coproduct A + B.

Source code in src/quivers/categorical/monoidal.py
243
244
245
def product(self, a: SetObject, b: SetObject) -> CoproductSet:
    """Coproduct A + B."""
    return CoproductSet(components=(a, b))

associator

associator(a: SetObject, b: SetObject, c: SetObject) -> ObservedMorphism

(A + B) + C → A + (B + C).

Since CoproductSet flattens, both sides are CoproductSet(A,B,C), so this is the identity.

Source code in src/quivers/categorical/monoidal.py
252
253
254
255
256
257
258
259
260
def associator(self, a: SetObject, b: SetObject, c: SetObject) -> ObservedMorphism:
    """(A + B) + C → A + (B + C).

    Since CoproductSet flattens, both sides are CoproductSet(A,B,C),
    so this is the identity.
    """
    flat = CoproductSet(components=(a, b, c))
    data = self._quantale.identity_tensor(flat.shape)
    return observed(flat, flat, data, quantale=self._quantale)

left_unitor

left_unitor(a: SetObject) -> ObservedMorphism

∅ + A → A.

Since ∅ has size 0, CoproductSet(∅, A) has the same size as A. The unitor is the identity (offset for A starts at 0).

Source code in src/quivers/categorical/monoidal.py
262
263
264
265
266
267
268
269
270
271
272
273
274
275
def left_unitor(self, a: SetObject) -> ObservedMorphism:
    """∅ + A → A.

    Since ∅ has size 0, CoproductSet(∅, A) has the same size as A.
    The unitor is the identity (offset for A starts at 0).
    """
    source = CoproductSet(components=(EMPTY, a))
    target = a
    n = target.size
    data = torch.zeros(n, *target.shape)
    for i in range(n):
        idx = (i,)
        data[idx + idx] = self._quantale.unit
    return observed(source, target, data, quantale=self._quantale)

right_unitor

right_unitor(a: SetObject) -> ObservedMorphism

A + ∅ → A.

Since ∅ has size 0, CoproductSet(A, ∅) has the same size as A.

Source code in src/quivers/categorical/monoidal.py
277
278
279
280
281
282
283
284
285
286
287
288
289
def right_unitor(self, a: SetObject) -> ObservedMorphism:
    """A + ∅ → A.

    Since ∅ has size 0, CoproductSet(A, ∅) has the same size as A.
    """
    source = CoproductSet(components=(a, EMPTY))
    target = a
    n = target.size
    data = torch.zeros(n, *target.shape)
    for i in range(n):
        idx = (i,)
        data[idx + idx] = self._quantale.unit
    return observed(source, target, data, quantale=self._quantale)

braiding

braiding(a: SetObject, b: SetObject) -> ObservedMorphism

A + B → B + A (block swap).

Swaps the two coproduct components.

Source code in src/quivers/categorical/monoidal.py
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
def braiding(self, a: SetObject, b: SetObject) -> ObservedMorphism:
    """A + B → B + A (block swap).

    Swaps the two coproduct components.
    """
    source = CoproductSet(components=(a, b))
    target = CoproductSet(components=(b, a))
    n_a = a.size
    n_b = b.size
    n = n_a + n_b
    data = torch.full((n, n), self._quantale.zero)
    for i in range(n_a):
        data[i, n_b + i] = self._quantale.unit
    for i in range(n_b):
        data[n_a + i, i] = self._quantale.unit
    return observed(source, target, data, quantale=self._quantale)