from FunctorFlow import Diagram, build_macro, compile_to_callable, MACRO_LIBRARY
import jsonBlock Library (Python)
Introduction
FunctorFlow provides a library of pre-built block macros — parameterized diagram constructors that encode common architectural patterns from categorical AI. Each block returns a Diagram with named objects, operations, and ports. You can inspect their structure, bind concrete implementations, and compose them into larger pipelines.
This vignette mirrors the Julia block library vignette using the Python API.
Setup
The Macro Registry
All blocks are registered in MACRO_LIBRARY and can be built by name using build_macro:
print("Available macros:", list(MACRO_LIBRARY.keys()))Available macros: ['ket', 'completion', 'structured_lm_duality', 'db_square', 'gt_neighborhood', 'basket_workflow', 'rocket_repair', 'democritus_gluing', 'basket_rocket_pipeline']
KET Block
The KET (Kan Extension Template) block is the most fundamental pattern. It performs left-Kan aggregation over an incidence relation — the universal building block for attention, pooling, and message passing.
Categorically, the KET computes a left Kan extension \(\mathrm{Lan}_J F\) along an incidence functor \(J\), producing contextualized values by aggregating source values over the fibers of \(J\).
D_ket = build_macro('ket')
print(D_ket.summary())Diagram(KETBlock)
Objects: Values, Incidence, ContextualizedValues
Operations: aggregate
Losses: <none>
Ports: input, relation, output
Inspecting Structure
ir = D_ket.to_ir().as_dict()
print("Objects:", [obj['name'] for obj in ir['objects']])
print("Operations:", [op['name'] for op in ir['operations']])Objects: ['Values', 'Incidence', 'ContextualizedValues']
Operations: ['aggregate']
Binding and Running
The default KET block uses the built-in sum reducer. Compile and run with sample data:
D_ket2 = build_macro('ket')
compiled = compile_to_callable(D_ket2)
result = compiled.run({
'Values': {'a': 1.0, 'b': 2.0, 'c': 3.0},
'Incidence': {'x': ['a', 'b'], 'y': ['b', 'c']}
})
print("KET output:", result.values)KET output: {'Values': {'a': 1.0, 'b': 2.0, 'c': 3.0}, 'Incidence': {'x': ['a', 'b'], 'y': ['b', 'c']}, 'aggregate': {'x': 3.0, 'y': 5.0}}
Building with Options
Build a KET with a specific reducer by passing reducer= to build_macro:
D_mean = build_macro('ket', reducer='mean')
compiled_mean = compile_to_callable(D_mean)
result_mean = compiled_mean.run({
'Values': {'a': 10.0, 'b': 20.0},
'Incidence': {'x': ['a', 'b']}
})
print("KET with mean:", result_mean.values)KET with mean: {'Values': {'a': 10.0, 'b': 20.0}, 'Incidence': {'x': ['a', 'b']}, 'aggregate': {'x': 15.0}}
DB Square
The DB Square (Diagrammatic Backpropagation Square) measures the obstruction to commutativity of two morphisms. It computes paths \(f \circ g\) and \(g \circ f\) and reports the distance as a loss.
Categorically, a DB square tests whether a diagram commutes: given morphisms \(f\) and \(g\) on a state object, the obstruction loss measures \(\|p_1 - p_2\|\) where \(p_1 = f \circ g\) and \(p_2 = g \circ f\). The loss vanishes iff \(f\) and \(g\) commute.
D_db = build_macro('db_square')
print(D_db.summary())Diagram(DBSquare)
Objects: State
Operations: f, g, p1, p2
Losses: obstruction
Ports: input, left_path, right_path, loss
Inspecting Structure
The DB square has four morphisms (f, g, p1, p2) and an obstruction loss:
ir_db = D_db.to_ir().as_dict()
print("Objects:", [obj['name'] for obj in ir_db['objects']])
print("Operations:", [op['name'] for op in ir_db['operations']])
print("Losses:", ir_db.get('losses', []))Objects: ['State']
Operations: ['f', 'g', 'p1', 'p2']
Losses: [{'name': 'obstruction', 'paths': (('p1', 'p2'),), 'comparator': 'l2', 'weight': 1.0, 'description': 'Measure how far the square is from commuting.', 'metadata': {'macro': 'DBSquare'}}]
Binding and Running
D_db2 = build_macro('db_square')
D_db2.bind_morphism('f', lambda x: x + 1.0)
D_db2.bind_morphism('g', lambda x: x * 2.0)
D_db2.bind_morphism('p1', lambda x: (x + 1.0) * 2.0)
D_db2.bind_morphism('p2', lambda x: (x * 2.0) + 1.0)
D_db2.bind_comparator('obstruction', lambda a, b: abs(a - b))
compiled_db = compile_to_callable(D_db2)
result_db = compiled_db.run({'State': 5.0})
print("f∘g path (p1):", result_db.values.get('p1'))
print("g∘f path (p2):", result_db.values.get('p2'))
print("Obstruction loss:", result_db.losses.get('obstruction'))f∘g path (p1): 12.0
g∘f path (p2): 11.0
Obstruction loss: 1.0
The loss is zero only when \(f\) and \(g\) commute. Here, \((5+1) \times 2 = 12\) and \((5 \times 2) + 1 = 11\), so the obstruction is \(|12 - 11| = 1\).
GT Neighborhood
The GT Neighborhood (Graph Transformer Neighborhood) block first lifts tokens to edge messages via a morphism, then aggregates them with a left Kan extension. This is the standard two-step pattern in graph neural networks and graph transformers.
Categorically, this is a composite: first a morphism \(\mathrm{lift}: \mathrm{Tokens} \to \mathrm{Messages}\), then a left Kan extension \(\mathrm{Lan}_J(\mathrm{Messages})\) along the neighborhood incidence \(J\).
D_gt = build_macro('gt_neighborhood')
print(D_gt.summary())Diagram(GTNeighborhoodBlock)
Objects: Tokens, Messages, NeighborhoodIncidence, UpdatedTokens
Operations: lift_messages, kan_aggregate
Losses: <none>
Ports: input, relation, messages, output
Inspecting Structure
ir_gt = D_gt.to_ir().as_dict()
print("Objects:", [obj['name'] for obj in ir_gt['objects']])
print("Operations:", [op['name'] for op in ir_gt['operations']])Objects: ['Tokens', 'Messages', 'NeighborhoodIncidence', 'UpdatedTokens']
Operations: ['lift_messages', 'kan_aggregate']
The lift_messages morphism transforms tokens to messages, and kan_aggregate performs the Kan extension aggregation.
Completion Block
The Completion Block uses a right Kan extension for universal completion — filling in partial or missing data from compatible neighbors.
Categorically, this computes a right Kan extension \(\mathrm{Ran}_J F\), the universal construction dual to the left Kan. Where left Kan aggregates (colimit-like), right Kan completes (limit-like), selecting consistent values from the fibers of a compatibility relation.
D_comp = build_macro('completion')
print(D_comp.summary())Diagram(CompletionBlock)
Objects: PartialState, CompatibilityRelation, CompletedState
Operations: complete
Losses: <none>
Ports: input, relation, output
ir_comp = D_comp.to_ir().as_dict()
print("Objects:", [obj['name'] for obj in ir_comp['objects']])
print("Operations:", [op['name'] for op in ir_comp['operations']])Objects: ['PartialState', 'CompatibilityRelation', 'CompletedState']
Operations: ['complete']
BASKET Workflow
The BASKET (Bounded Aggregation via Sheaf-theoretic Kan Extension Templates) workflow block composes local plan fragments into a composed plan using left Kan with a :concat reducer.
Categorically, BASKET performs a left Kan extension of plan fragments along an observation-context incidence, with a monoidal concatenation reducer — assembling a global plan from local contributions.
D_basket = build_macro('basket_workflow')
print(D_basket.summary())Diagram(BASKETWorkflowBlock)
Objects: PlanFragments, ObservationContexts, PlanState
Operations: draft_plan
Losses: <none>
Ports: fragments, context, output
ir_basket = D_basket.to_ir().as_dict()
print("Objects:", [obj['name'] for obj in ir_basket['objects']])
print("Operations:", [op['name'] for op in ir_basket['operations']])Objects: ['PlanFragments', 'ObservationContexts', 'PlanState']
Operations: ['draft_plan']
ROCKET Repair
The ROCKET (Robust Obstruction-Corrected Kan Extension Transform) repair block uses a right Kan extension to repair candidates using edit neighborhoods.
Categorically, ROCKET applies a right Kan extension to candidate fragments along an edit-neighborhood relation, using a :first_non_null reducer — selecting the best available repair from local neighborhoods.
D_rocket = build_macro('rocket_repair')
print(D_rocket.summary())Diagram(ROCKETRepairBlock)
Objects: CandidateFragments, EditNeighborhood, RepairedPlan
Operations: repair
Losses: <none>
Ports: candidates, relation, output
ir_rocket = D_rocket.to_ir().as_dict()
print("Objects:", [obj['name'] for obj in ir_rocket['objects']])
print("Operations:", [op['name'] for op in ir_rocket['operations']])Objects: ['CandidateFragments', 'EditNeighborhood', 'RepairedPlan']
Operations: ['repair']
Democritus Gluing
The Democritus Gluing block implements sheaf-theoretic local-to-global assembly. It uses a right Kan extension to glue local causal claims over overlap regions into a global relational state.
Categorically, this is a sheaf-theoretic construction: local sections (claims on patches) are glued into a global section on the base space, mediated by overlap regions that enforce consistency.
D_demo = build_macro('democritus_gluing')
print(D_demo.summary())Diagram(DemocritusGluingBlock)
Objects: LocalClaims, OverlapRegions, GlobalManifold
Operations: glue
Losses: <none>
Ports: locals, relation, output
ir_demo = D_demo.to_ir().as_dict()
print("Objects:", [obj['name'] for obj in ir_demo['objects']])
print("Operations:", [op['name'] for op in ir_demo['operations']])Objects: ['LocalClaims', 'OverlapRegions', 'GlobalManifold']
Operations: ['glue']
Structured LM Duality
The Structured LM Duality block runs parallel left-Kan (prediction) and right-Kan (completion/repair) branches from a shared input. This captures the predict-then-repair duality central to structured language modeling.
Categorically, this encodes the duality between left and right Kan extensions as parallel functors from a shared domain — the prediction branch computes a colimit (aggregation), while the repair branch computes a limit (completion).
D_lm = build_macro('structured_lm_duality')
print(D_lm.summary())Diagram(StructuredLMDuality)
Objects: HiddenStates, CausalRelation, ContextualizedStates, NoisyBlock, DenoiseCondition, CompletedBlock
Operations: predict__aggregate_context, repair__complete_block
Losses: <none>
Ports: predict__input, predict__relation, predict__output, repair__input, repair__relation, repair__output, hidden, relation, context, noisy_block, condition, completed
ir_lm = D_lm.to_ir().as_dict()
print("Objects:", [obj['name'] for obj in ir_lm['objects']])
print("Operations:", [op['name'] for op in ir_lm['operations']])Objects: ['HiddenStates', 'CausalRelation', 'ContextualizedStates', 'NoisyBlock', 'DenoiseCondition', 'CompletedBlock']
Operations: ['predict__aggregate_context', 'repair__complete_block']
BASKET-ROCKET Pipeline
The BASKET-ROCKET Pipeline composes two stages: a BASKET draft phase (left Kan with :concat) followed by a ROCKET repair phase (right Kan with :first_non_null). This is a complete draft-then-repair workflow built via diagram inclusion.
Categorically, this is a sequential composite of two Kan extensions: the left Kan assembles a draft from local fragments, then the right Kan repairs defects by completing from edit neighborhoods. The composition is mediated by the port system and namespacing.
D_br = build_macro('basket_rocket_pipeline')
print(D_br.summary())Diagram(BASKETROCKETPipeline)
Objects: PlanFragments, ObservationContexts, draft__PlanState, EditNeighborhood, RepairedPlan
Operations: draft__draft_plan, repair__repair
Losses: <none>
Ports: draft__fragments, draft__context, draft__output, repair__candidates, repair__relation, repair__output, fragments, context, repair_relation, draft_output, output
ir_br = D_br.to_ir().as_dict()
print("Objects:", [obj['name'] for obj in ir_br['objects']])
print("Operations:", [op['name'] for op in ir_br['operations']])Objects: ['PlanFragments', 'ObservationContexts', 'draft__PlanState', 'EditNeighborhood', 'RepairedPlan']
Operations: ['draft__draft_plan', 'repair__repair']
Note the namespaced operations: draft__draft_plan and repair__repair reflect the included sub-diagrams.
Full IR Example
Here is the full intermediate representation of the KET block as JSON:
D_ir_example = build_macro('ket')
ir_full = D_ir_example.to_ir().as_dict()
print(json.dumps(ir_full, indent=2, default=str)){
"name": "KETBlock",
"objects": [
{
"name": "Values",
"kind": "messages",
"shape": null,
"description": "",
"metadata": {}
},
{
"name": "Incidence",
"kind": "relation",
"shape": null,
"description": "",
"metadata": {}
},
{
"name": "ContextualizedValues",
"kind": "contextualized_messages",
"shape": null,
"description": "",
"metadata": {}
}
],
"operations": [
{
"name": "aggregate",
"direction": "left",
"source": "Values",
"along": "Incidence",
"target": "ContextualizedValues",
"reducer": "sum",
"description": "Universal aggregation over an incidence structure.",
"metadata": {
"macro": "KETBlock"
},
"kind": "kanextension"
}
],
"losses": [],
"ports": [
{
"name": "input",
"ref": "Values",
"kind": "object",
"port_type": "messages",
"direction": "input",
"description": "",
"metadata": {}
},
{
"name": "relation",
"ref": "Incidence",
"kind": "object",
"port_type": "relation",
"direction": "input",
"description": "",
"metadata": {}
},
{
"name": "output",
"ref": "aggregate",
"kind": "operation",
"port_type": "contextualized_messages",
"direction": "output",
"description": "",
"metadata": {}
}
]
}
Summary
| Block | Pattern | Kan Type | Key Idea |
|---|---|---|---|
| KET | Aggregation | Left Kan | Universal attention/pooling |
| DB Square | Commutativity test | Loss | Obstruction to diagram commutativity |
| GT Neighborhood | Lift + Aggregate | Left Kan | Graph transformer message passing |
| Completion | Gap filling | Right Kan | Universal completion from neighbors |
| BASKET Workflow | Plan assembly | Left Kan | Sheaf-theoretic plan composition |
| ROCKET Repair | Defect correction | Right Kan | Obstruction-corrected repair |
| Democritus Gluing | Local→Global | Right Kan | Sheaf gluing of local claims |
| Structured LM Duality | Predict + Repair | Both | Left/right Kan duality |
| BASKET-ROCKET | Draft + Repair | Both | Composed pipeline via inclusion |