Adjunctions

Adjoint functor pairs and adjoint relationships between categories.

adjunctions

Adjunctions between endofunctors.

An adjunction F ⊣ G consists of functors F (left adjoint) and G (right adjoint), together with natural transformations:

η: Id ⇒ G ∘ F    (unit)
ε: F ∘ G ⇒ Id    (counit)

satisfying the triangle identities:

ε_{F(A)} ∘ F(η_A) = id_{F(A)}
G(ε_A) ∘ η_{G(A)} = id_{G(A)}

Every adjunction induces a monad T = G ∘ F with η as unit and μ = G(ε_F) as multiplication.

This module provides:

Adjunction (abstract)
└── FreeForgetfulAdjunction — Free monoid ⊣ Forgetful

ForgetfulFunctor

Bases: Functor

The forgetful functor from FreeMonoid-algebras to FinSet.

On objects: A ↦ A (the underlying set). Since FreeMonoid is already a CoproductSet (hence a SetObject), the forgetful functor is the identity on the set level. On morphisms: identity on tensors.

In the adjunction Free ⊣ Forget, "Forget" maps A back to A as a bare set (no monoid structure). Since we represent everything as bare sets already, this is the identity functor.

map_object

map_object(obj: SetObject) -> SetObject

Identity on objects.

Source code in src/quivers/categorical/adjunctions.py
50
51
52
def map_object(self, obj: SetObject) -> SetObject:
    """Identity on objects."""
    return obj

map_morphism

map_morphism(morph: Morphism) -> FunctorMorphism

Identity on morphisms.

Source code in src/quivers/categorical/adjunctions.py
54
55
56
57
58
def map_morphism(self, morph: Morphism) -> FunctorMorphism:
    """Identity on morphisms."""
    from quivers.core.morphisms import FunctorMorphism

    return FunctorMorphism(self, morph, morph.domain, morph.codomain)

map_tensor

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

Identity on tensors.

Source code in src/quivers/categorical/adjunctions.py
60
61
62
def map_tensor(self, tensor: torch.Tensor, quantale: object) -> torch.Tensor:
    """Identity on tensors."""
    return tensor

Adjunction

Bases: ABC

Abstract adjunction F ⊣ G.

Subclasses must implement left, right, unit_component, and counit_component.

left abstractmethod property

left: Functor

The left adjoint F.

right abstractmethod property

right: Functor

The right adjoint G.

unit_component abstractmethod

unit_component(obj: SetObject) -> Morphism

The unit component η_A: A → G(F(A)).

PARAMETER DESCRIPTION
obj

The object A.

TYPE: SetObject

RETURNS DESCRIPTION
Morphism

The unit morphism η_A.

Source code in src/quivers/categorical/adjunctions.py
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
@abstractmethod
def unit_component(self, obj: SetObject) -> Morphism:
    """The unit component η_A: A → G(F(A)).

    Parameters
    ----------
    obj : SetObject
        The object A.

    Returns
    -------
    Morphism
        The unit morphism η_A.
    """
    ...

counit_component abstractmethod

counit_component(obj: SetObject) -> Morphism

The counit component ε_A: F(G(A)) → A.

PARAMETER DESCRIPTION
obj

The object A.

TYPE: SetObject

RETURNS DESCRIPTION
Morphism

The counit morphism ε_A.

Source code in src/quivers/categorical/adjunctions.py
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
@abstractmethod
def counit_component(self, obj: SetObject) -> Morphism:
    """The counit component ε_A: F(G(A)) → A.

    Parameters
    ----------
    obj : SetObject
        The object A.

    Returns
    -------
    Morphism
        The counit morphism ε_A.
    """
    ...

verify_triangle_left

verify_triangle_left(obj: SetObject, atol: float = 1e-05) -> bool

Verify left triangle identity: ε_{F(A)} ∘ F(η_A) ≈ id_{F(A)}.

PARAMETER DESCRIPTION
obj

The object A.

TYPE: SetObject

atol

Absolute tolerance.

TYPE: float DEFAULT: 1e-05

RETURNS DESCRIPTION
bool

True if the identity holds within tolerance.

Source code in src/quivers/categorical/adjunctions.py
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
def verify_triangle_left(self, obj: SetObject, atol: float = 1e-5) -> bool:
    """Verify left triangle identity: ε_{F(A)} ∘ F(η_A) ≈ id_{F(A)}.

    Parameters
    ----------
    obj : SetObject
        The object A.
    atol : float
        Absolute tolerance.

    Returns
    -------
    bool
        True if the identity holds within tolerance.
    """
    fa = self.left.map_object(obj)
    eta_a = self.unit_component(obj)
    f_eta = self.left.map_morphism(eta_a)
    eps_fa = self.counit_component(fa)
    result = (f_eta >> eps_fa).tensor
    expected = identity(fa).tensor

    return torch.allclose(result, expected, atol=atol)

verify_triangle_right

verify_triangle_right(obj: SetObject, atol: float = 1e-05) -> bool

Verify right triangle identity: G(ε_A) ∘ η_{G(A)} ≈ id_{G(A)}.

PARAMETER DESCRIPTION
obj

The object A.

TYPE: SetObject

atol

Absolute tolerance.

TYPE: float DEFAULT: 1e-05

RETURNS DESCRIPTION
bool

True if the identity holds within tolerance.

Source code in src/quivers/categorical/adjunctions.py
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
def verify_triangle_right(self, obj: SetObject, atol: float = 1e-5) -> bool:
    """Verify right triangle identity: G(ε_A) ∘ η_{G(A)} ≈ id_{G(A)}.

    Parameters
    ----------
    obj : SetObject
        The object A.
    atol : float
        Absolute tolerance.

    Returns
    -------
    bool
        True if the identity holds within tolerance.
    """
    ga = self.right.map_object(obj)
    eps_a = self.counit_component(obj)
    g_eps = self.right.map_morphism(eps_a)
    eta_ga = self.unit_component(ga)
    result = (eta_ga >> g_eps).tensor
    expected = identity(ga).tensor

    return torch.allclose(result, expected, atol=atol)

FreeForgetfulAdjunction

FreeForgetfulAdjunction(max_length: int)

Bases: Adjunction

The free-forgetful adjunction: Free ⊣ Forget.

Free: FinSet → FinSet via FreeMonoidFunctor (A ↦ A) Forget: identity at set level (A ↦ A* as bare set)

η_A: A → A embeds each element as a length-1 word. ε_A: A → A projects onto length-1 words (for A a FinSet).

PARAMETER DESCRIPTION
max_length

Maximum string length for the free monoid.

TYPE: int

Source code in src/quivers/categorical/adjunctions.py
187
188
189
190
def __init__(self, max_length: int) -> None:
    self._max_length = max_length
    self._free = FreeMonoidFunctor(max_length)
    self._forget = ForgetfulFunctor()

left property

left: Functor

The free functor.

right property

right: Functor

The forgetful functor.

unit_component

unit_component(obj: SetObject) -> Morphism

η_A: A → A* embeds as length-1 words.

PARAMETER DESCRIPTION
obj

Must be a FinSet.

TYPE: SetObject

RETURNS DESCRIPTION
Morphism

The embedding morphism.

Source code in src/quivers/categorical/adjunctions.py
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
def unit_component(self, obj: SetObject) -> Morphism:
    """η_A: A → A* embeds as length-1 words.

    Parameters
    ----------
    obj : SetObject
        Must be a FinSet.

    Returns
    -------
    Morphism
        The embedding morphism.
    """
    if not isinstance(obj, FinSet):
        obj = FinSet(name=getattr(obj, "name", repr(obj)), cardinality=obj.size)

    fm = FreeMonoid(generators=obj, max_length=self._max_length)
    n = obj.cardinality
    data = torch.zeros(n, fm.size)
    offset = fm.offset(1)

    for a in range(n):
        data[a, offset + a] = 1.0

    return observed(obj, fm, data)

counit_component

counit_component(obj: SetObject) -> Morphism

ε_A: Free(Forget(A)) → A.

For a FinSet A, this projects A* onto A by extracting the length-1 stratum. Length-1 words map to their element; all others (empty string, longer words) map to zero.

For a FreeMonoid A (needed by the left triangle identity), this is the monoid evaluation map (A) → A that concatenates formal words of words into single words.

PARAMETER DESCRIPTION
obj

The object A.

TYPE: SetObject

RETURNS DESCRIPTION
Morphism

The counit morphism.

Source code in src/quivers/categorical/adjunctions.py
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
258
259
260
261
262
263
264
def counit_component(self, obj: SetObject) -> Morphism:
    """ε_A: Free(Forget(A)) → A.

    For a FinSet A, this projects A* onto A by extracting the
    length-1 stratum. Length-1 words map to their element; all
    others (empty string, longer words) map to zero.

    For a FreeMonoid A* (needed by the left triangle identity),
    this is the monoid evaluation map (A*)* → A* that
    concatenates formal words of words into single words.

    Parameters
    ----------
    obj : SetObject
        The object A.

    Returns
    -------
    Morphism
        The counit morphism.
    """
    if isinstance(obj, FreeMonoid):
        return self._counit_at_free_monoid(obj)

    if not isinstance(obj, FinSet):
        obj = FinSet(name=getattr(obj, "name", repr(obj)), cardinality=obj.size)

    fm = FreeMonoid(generators=obj, max_length=self._max_length)
    data = torch.zeros(fm.size, obj.cardinality)

    # length-1 words: project to the corresponding element
    offset = fm.offset(1)

    for a in range(obj.cardinality):
        data[offset + a, a] = 1.0

    return observed(fm, obj, data)