Functors

Functors between enriched categories preserving categorical structure and composition.

functors

Endofunctors on V-enriched FinSet.

A functor F maps objects to objects and morphisms to morphisms, preserving composition and identities. This module provides:

Functor (abstract)
├── IdentityFunctor  — Id: A ↦ A, f ↦ f
├── ComposedFunctor  — F ∘ G: applies G then F
└── FreeMonoidFunctor — A ↦ A*, f ↦ f* (block-diagonal, componentwise)

Functor

Bases: ABC

Abstract endofunctor on V-enriched FinSet.

Subclasses must implement map_object, map_morphism, and map_tensor.

map_object abstractmethod

map_object(obj: SetObject) -> SetObject

Apply the functor to an object.

PARAMETER DESCRIPTION
obj

Source object.

TYPE: SetObject

RETURNS DESCRIPTION
SetObject

Image object.

Source code in src/quivers/categorical/functors.py
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
@abstractmethod
def map_object(self, obj: SetObject) -> SetObject:
    """Apply the functor to an object.

    Parameters
    ----------
    obj : SetObject
        Source object.

    Returns
    -------
    SetObject
        Image object.
    """
    ...

map_morphism abstractmethod

map_morphism(morph: Morphism) -> FunctorMorphism

Apply the functor to a morphism.

Returns a lazy FunctorMorphism that recomputes its tensor from the inner morphism, preserving gradient flow.

PARAMETER DESCRIPTION
morph

Source morphism.

TYPE: Morphism

RETURNS DESCRIPTION
FunctorMorphism

Image morphism.

Source code in src/quivers/categorical/functors.py
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
@abstractmethod
def map_morphism(self, morph: Morphism) -> FunctorMorphism:
    """Apply the functor to a morphism.

    Returns a lazy FunctorMorphism that recomputes its tensor
    from the inner morphism, preserving gradient flow.

    Parameters
    ----------
    morph : Morphism
        Source morphism.

    Returns
    -------
    FunctorMorphism
        Image morphism.
    """
    ...

map_tensor abstractmethod

map_tensor(tensor: Tensor, quantale: Quantale) -> Tensor

Apply the functor's action on the raw tensor level.

This is the computational core used by FunctorMorphism.tensor.

PARAMETER DESCRIPTION
tensor

The inner morphism's tensor.

TYPE: Tensor

quantale

The enrichment algebra.

TYPE: Quantale

RETURNS DESCRIPTION
Tensor

The image tensor.

Source code in src/quivers/categorical/functors.py
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
@abstractmethod
def map_tensor(self, tensor: torch.Tensor, quantale: Quantale) -> torch.Tensor:
    """Apply the functor's action on the raw tensor level.

    This is the computational core used by FunctorMorphism.tensor.

    Parameters
    ----------
    tensor : torch.Tensor
        The inner morphism's tensor.
    quantale : Quantale
        The enrichment algebra.

    Returns
    -------
    torch.Tensor
        The image tensor.
    """
    ...

IdentityFunctor

Bases: Functor

The identity endofunctor Id: C → C.

Maps every object and morphism to itself. Needed as the source or target of natural transformations (e.g., monad unit η: Id ⇒ T).

map_object

map_object(obj: SetObject) -> SetObject

Identity on objects: A ↦ A.

Source code in src/quivers/categorical/functors.py
92
93
94
def map_object(self, obj: SetObject) -> SetObject:
    """Identity on objects: A ↦ A."""
    return obj

map_morphism

map_morphism(morph: Morphism) -> FunctorMorphism

Identity on morphisms: f ↦ f (wrapped as FunctorMorphism).

Source code in src/quivers/categorical/functors.py
96
97
98
def map_morphism(self, morph: Morphism) -> FunctorMorphism:
    """Identity on morphisms: f ↦ f (wrapped as FunctorMorphism)."""
    return FunctorMorphism(self, morph, morph.domain, morph.codomain)

map_tensor

map_tensor(tensor: Tensor, quantale: Quantale) -> Tensor

Identity on tensors.

Source code in src/quivers/categorical/functors.py
100
101
102
def map_tensor(self, tensor: torch.Tensor, quantale: Quantale) -> torch.Tensor:
    """Identity on tensors."""
    return tensor

ComposedFunctor

ComposedFunctor(outer: Functor, inner: Functor)

Bases: Functor

Composition of two endofunctors: F ∘ G.

Applies G first, then F. Preserves functoriality: (F ∘ G)(f) = F(G(f)).

PARAMETER DESCRIPTION
outer

The functor applied second (F).

TYPE: Functor

inner

The functor applied first (G).

TYPE: Functor

Source code in src/quivers/categorical/functors.py
122
123
124
def __init__(self, outer: Functor, inner: Functor) -> None:
    self._outer = outer
    self._inner = inner

outer property

outer: Functor

The outer (second-applied) functor F.

inner property

inner: Functor

The inner (first-applied) functor G.

map_object

map_object(obj: SetObject) -> SetObject

F(G(A)).

Source code in src/quivers/categorical/functors.py
136
137
138
def map_object(self, obj: SetObject) -> SetObject:
    """F(G(A))."""
    return self._outer.map_object(self._inner.map_object(obj))

map_morphism

map_morphism(morph: Morphism) -> FunctorMorphism

F(G(f)) as a lazy FunctorMorphism.

Source code in src/quivers/categorical/functors.py
140
141
142
143
144
def map_morphism(self, morph: Morphism) -> FunctorMorphism:
    """F(G(f)) as a lazy FunctorMorphism."""
    domain = self.map_object(morph.domain)
    codomain = self.map_object(morph.codomain)
    return FunctorMorphism(self, morph, domain, codomain)

map_tensor

map_tensor(tensor: Tensor, quantale: Quantale) -> Tensor

F's tensor action applied to G's tensor action.

Source code in src/quivers/categorical/functors.py
146
147
148
149
def map_tensor(self, tensor: torch.Tensor, quantale: Quantale) -> torch.Tensor:
    """F's tensor action applied to G's tensor action."""
    inner_result = self._inner.map_tensor(tensor, quantale)
    return self._outer.map_tensor(inner_result, quantale)

FreeMonoidFunctor

FreeMonoidFunctor(max_length: int)

Bases: Functor

The free monoid endofunctor, truncated to max_length.

On objects: A ↦ FreeMonoid(generators=A, max_length=max_length) On morphisms: f ↦ f* (block-diagonal, componentwise on each stratum)

The morphism action assembles a block-diagonal tensor where the k-th block is componentwise_lift(f, k) reshaped to 2D. This means strings of length k map to strings of length k via componentwise application of the underlying morphism.

PARAMETER DESCRIPTION
max_length

Maximum string length for the truncated free monoid.

TYPE: int

Source code in src/quivers/categorical/functors.py
172
173
174
175
176
def __init__(self, max_length: int) -> None:
    if max_length < 0:
        raise ValueError(f"max_length must be >= 0, got {max_length}")

    self._max_length = max_length

max_length property

max_length: int

Maximum string length.

map_object

map_object(obj: SetObject) -> FreeMonoid

Apply functor to an object: A ↦ FreeMonoid(generators=A, max_length=max_length).

For FinSet inputs, uses obj directly as generators. For other SetObject types (e.g., FreeMonoid, CoproductSet), creates a proxy FinSet with the same cardinality — this is needed for iterated application (e.g., the triangle identities of an adjunction require F(F(A)) = (A)).

PARAMETER DESCRIPTION
obj

The generator set. Typically a FinSet, but any SetObject is accepted by treating it as a flat set.

TYPE: SetObject

RETURNS DESCRIPTION
FreeMonoid

The free monoid on obj.

Source code in src/quivers/categorical/functors.py
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
def map_object(self, obj: SetObject) -> FreeMonoid:
    """Apply functor to an object: A ↦ FreeMonoid(generators=A, max_length=max_length).

    For FinSet inputs, uses obj directly as generators. For other
    SetObject types (e.g., FreeMonoid, CoproductSet), creates a
    proxy FinSet with the same cardinality — this is needed for
    iterated application (e.g., the triangle identities of an
    adjunction require F(F(A)) = (A*)*).

    Parameters
    ----------
    obj : SetObject
        The generator set. Typically a FinSet, but any SetObject
        is accepted by treating it as a flat set.

    Returns
    -------
    FreeMonoid
        The free monoid on obj.
    """
    if not isinstance(obj, FinSet):
        # treat any SetObject as a flat set with its total cardinality
        obj = FinSet(name=getattr(obj, "name", repr(obj)), cardinality=obj.size)

    return FreeMonoid(generators=obj, max_length=self._max_length)

map_morphism

map_morphism(morph: Morphism) -> FunctorMorphism

Apply functor to a morphism: f ↦ f* (block-diagonal).

PARAMETER DESCRIPTION
morph

A morphism between FinSets.

TYPE: Morphism

RETURNS DESCRIPTION
FunctorMorphism

Lazy image preserving gradient flow.

Source code in src/quivers/categorical/functors.py
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
def map_morphism(self, morph: Morphism) -> FunctorMorphism:
    """Apply functor to a morphism: f ↦ f* (block-diagonal).

    Parameters
    ----------
    morph : Morphism
        A morphism between FinSets.

    Returns
    -------
    FunctorMorphism
        Lazy image preserving gradient flow.
    """
    domain = self.map_object(morph.domain)
    codomain = self.map_object(morph.codomain)

    return FunctorMorphism(self, morph, domain, codomain)

map_tensor

map_tensor(tensor: Tensor, quantale: Quantale) -> Tensor

Build the block-diagonal tensor for the free monoid action.

For each k=0..max_length, computes componentwise_lift(f, k), reshapes the result to 2D (n_a^k × n_b^k), and assembles all blocks via torch.block_diag.

PARAMETER DESCRIPTION
tensor

The inner morphism's 2D tensor of shape (n_a, n_b).

TYPE: Tensor

quantale

The enrichment algebra (passed to componentwise_lift).

TYPE: Quantale

RETURNS DESCRIPTION
Tensor

Block-diagonal tensor of shape (total_a, total_b).

Source code in src/quivers/categorical/functors.py
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
def map_tensor(self, tensor: torch.Tensor, quantale: Quantale) -> torch.Tensor:
    """Build the block-diagonal tensor for the free monoid action.

    For each k=0..max_length, computes componentwise_lift(f, k),
    reshapes the result to 2D (n_a^k × n_b^k), and assembles all
    blocks via torch.block_diag.

    Parameters
    ----------
    tensor : torch.Tensor
        The inner morphism's 2D tensor of shape (n_a, n_b).
    quantale : Quantale
        The enrichment algebra (passed to componentwise_lift).

    Returns
    -------
    torch.Tensor
        Block-diagonal tensor of shape (total_a, total_b).
    """
    n_a, n_b = tensor.shape
    blocks: list[torch.Tensor] = []

    for k in range(self._max_length + 1):
        lifted = componentwise_lift(tensor, k, quantale=quantale)

        # reshape from (n_a,)*k + (n_b,)*k to (n_a^k, n_b^k)
        rows = n_a**k if k > 0 else 1
        cols = n_b**k if k > 0 else 1
        blocks.append(lifted.reshape(rows, cols))

    return torch.block_diag(*blocks)