name: neuro-symbolic-bridge description: 'High tension pairs (d ≈ 1.85):' metadata: interface_ports: - Commands
neuro-symbolic-bridge Skill
Bridge between symbolic (SICP, proofs) and subsymbolic (GFlowNets, neural) paradigms
The Gap
High tension pairs (d ≈ 1.85):
SYMBOLIC SUBSYMBOLIC
│ │
sicp gflownet
proofgeneral-narya forward-forward-learning
lispsyntax-acset sheaf-laplacian-coordination
dialectica cognitive-superposition
│ │
└──────────── d ≈ 1.85 ─────────────────┘
Resolution: DisCoPy String Diagrams
DisCoPy provides the bridge via string diagrams that are:
- Symbolic: Compositional, typed, algebraic
- Subsymbolic: Tensor network evaluation, differentiable
SYMBOLIC (SICP) DisCoPy SUBSYMBOLIC (Neural)
│ │ │
S-expressions ──→ String Diagrams ──→ Tensor Contractions
Pure functions Monoidal categories Differentiable
Type theory Wiring diagrams Gradient flow
│ │ │
└───────── d ≈ 0.9 ─────┴───────── d ≈ 0.9 ─────┘
Core Concept
String Diagrams as Interface
from discopy import rigid, tensor
from discopy.grammar import pregroup
# SYMBOLIC: Define types and morphisms compositionally
n = pregroup.Ty('n') # noun type
s = pregroup.Ty('s') # sentence type
# Words as morphisms (symbolic)
Alice = pregroup.Word('Alice', n)
loves = pregroup.Word('loves', n.r @ s @ n.l)
Bob = pregroup.Word('Bob', n)
# Compose symbolically
sentence = Alice @ loves @ Bob >> pregroup.Cup(n, n.r) @ s @ pregroup.Cup(n.l, n)
# SUBSYMBOLIC: Evaluate as tensor network
from discopy.quantum import Ket, Bra, CircuitFunctor
# Map types to vector spaces
F = CircuitFunctor(
ob={n: 2, s: 4}, # noun=2-dim, sentence=4-dim
ar={
Alice: tensor.Tensor([1, 0]), # One-hot
Bob: tensor.Tensor([0, 1]),
loves: tensor.Tensor.random(2, 4, 2), # Learned tensor
}
)
# Evaluate (differentiable!)
result = F(sentence) # Tensor contraction
Implementation
Symbolic to Subsymbolic Translation
from typing import Dict, Any, Callable
from discopy import Diagram, Ty, Box
import torch
import torch.nn as nn
class NeuroSymbolicBridge:
"""
Bridge between symbolic S-expressions and neural networks.
Resolves the sicp ↔ gflownet tension by:
1. Parsing S-expressions to DisCoPy diagrams (symbolic)
2. Assigning neural network semantics (subsymbolic)
3. Backprop through diagram evaluation
"""
def __init__(self):
self.type_dims: Dict[str, int] = {}
self.box_networks: Dict[str, nn.Module] = {}
def register_type(self, name: str, dim: int):
"""Register symbolic type with vector space dimension."""
self.type_dims[name] = dim
def register_function(self, name: str, network: nn.Module):
"""Register symbolic function with neural implementation."""
self.box_networks[name] = network
def parse_sexpr(self, sexpr: str) -> Diagram:
"""
Parse S-expression to DisCoPy diagram.
(f (g x) y) → f ∘ (g ⊗ id) ∘ ...
"""
from sexpdata import loads
tree = loads(sexpr)
return self._tree_to_diagram(tree)
def _tree_to_diagram(self, tree) -> Diagram:
"""Convert parse tree to diagram."""
if isinstance(tree, str):
# Atom: lookup or create generator
return Box(tree, Ty(), Ty(tree))
elif isinstance(tree, list):
# Application: compose diagrams
func = self._tree_to_diagram(tree[0])
args = [self._tree_to_diagram(a) for a in tree[1:]]
# Tensor args, then compose with function
if args:
tensored = args[0]
for a in args[1:]:
tensored = tensored @ a
return tensored >> func
return func
else:
return Box(str(tree), Ty(), Ty('const'))
def evaluate(self, diagram: Diagram) -> torch.Tensor:
"""
Evaluate diagram as tensor network (differentiable).
"""
# Create functor mapping boxes to tensors
def tensor_for_box(box: Box) -> torch.Tensor:
if box.name in self.box_networks:
# Neural network semantics
return self.box_networks[box.name]
else:
# Random initialization (learnable)
in_dim = self._dim_of_type(box.dom)
out_dim = self._dim_of_type(box.cod)
return nn.Linear(in_dim, out_dim)
# Contract tensors according to diagram structure
return self._contract(diagram, tensor_for_box)
def _dim_of_type(self, ty: Ty) -> int:
"""Compute dimension of type."""
if len(ty) == 0:
return 1
return sum(self.type_dims.get(str(t), 1) for t in ty)
def _contract(self, diagram: Diagram,
tensor_fn: Callable[[Box], torch.Tensor]) -> torch.Tensor:
"""Contract diagram as tensor network."""
# Simplified: use discopy's built-in evaluation
from discopy.tensor import TensorFunctor
F = TensorFunctor(
ob={str(t): self.type_dims.get(str(t), 2) for t in diagram.dom @ diagram.cod},
ar={box.name: tensor_fn(box) for box in diagram.boxes}
)
return F(diagram)
# Example: GFlowNet sampling as symbolic operation
class GFlowNetBox(nn.Module):
"""
Neural box that samples proportionally to reward.
Bridges symbolic composition with GFlowNet sampling.
"""
def __init__(self, in_dim: int, out_dim: int, hidden: int = 64):
super().__init__()
self.flow = nn.Sequential(
nn.Linear(in_dim, hidden),
nn.ReLU(),
nn.Linear(hidden, out_dim),
nn.Softplus() # Positive flows
)
self.partition = nn.Parameter(torch.ones(1))
def forward(self, x: torch.Tensor) -> torch.Tensor:
"""Forward flow (for training)."""
return self.flow(x)
def sample(self, x: torch.Tensor) -> int:
"""Sample action proportional to flow."""
flows = self.forward(x)
probs = flows / flows.sum()
return torch.multinomial(probs, 1).item()
Symbolic Proof → Neural Verifier
class ProofNeuralVerifier:
"""
Bridge between Narya/Agda proofs and neural verification.
Symbolic: Type derivation tree
Subsymbolic: Neural network that learns proof patterns
"""
def __init__(self, bridge: NeuroSymbolicBridge):
self.bridge = bridge
self.proof_encoder = nn.TransformerEncoder(
nn.TransformerEncoderLayer(d_model=256, nhead=8),
num_layers=6
)
def proof_to_diagram(self, proof_term: str) -> Diagram:
"""Convert proof term to DisCoPy diagram."""
# Proof terms are S-expressions
return self.bridge.parse_sexpr(proof_term)
def embed_proof(self, proof: Diagram) -> torch.Tensor:
"""Embed proof structure as vector."""
# Walk diagram, collect box embeddings
embeddings = []
for box in proof.boxes:
if box.name in self.bridge.box_networks:
embeddings.append(self.bridge.box_networks[box.name].weight)
if embeddings:
stacked = torch.stack(embeddings)
return self.proof_encoder(stacked.unsqueeze(0))
return torch.zeros(1, 256)
def verify_neural(self, proof: Diagram, claim: Diagram) -> float:
"""Neural verification score (subsymbolic)."""
proof_emb = self.embed_proof(proof)
claim_emb = self.embed_proof(claim)
# Cosine similarity as "proof correctness" score
return torch.cosine_similarity(proof_emb, claim_emb, dim=-1).item()
Gay.jl Color Integration
BRIDGE_COLORS = {
'symbolic': '#CF6971', # Stream 3 (SICP red)
'subsymbolic': '#63B6F0', # Stream 3 (neural blue)
'bridge': '#89DF91', # Stream 3 (DisCoPy green)
'hybrid': '#E6F463', # Stream 2 (integrated yellow)
}
def color_component(component_type: str) -> str:
"""Color based on paradigm."""
if component_type in ['sexpr', 'proof', 'type']:
return BRIDGE_COLORS['symbolic']
elif component_type in ['tensor', 'network', 'gradient']:
return BRIDGE_COLORS['subsymbolic']
elif component_type in ['diagram', 'functor', 'discopy']:
return BRIDGE_COLORS['bridge']
else:
return BRIDGE_COLORS['hybrid']
Triangle Inequality Restoration
With this bridge:
d(sicp, neuro-symbolic-bridge) ≈ 0.9
d(neuro-symbolic-bridge, gflownet) ≈ 0.9
Therefore:
d(sicp, gflownet) ≤ 0.9 + 0.9 = 1.8 ✓
(Original: 1.859, now satisfies triangle inequality)
Use Cases
1. Neural Program Synthesis
# Symbolic: program syntax
program_sexpr = "(lambda (x) (+ x 1))"
diagram = bridge.parse_sexpr(program_sexpr)
# Subsymbolic: learned semantics
output = bridge.evaluate(diagram) # Differentiable!
# Train to match examples
loss = mse(output, target)
loss.backward() # Gradients flow through symbolic structure
2. GFlowNet + Compositional Structure
# Symbolic composition of GFlowNet boxes
molecule_diagram = (
Box('atom_C', Ty(), Ty('atom')) @
Box('atom_O', Ty(), Ty('atom')) >>
Box('bond', Ty('atom', 'atom'), Ty('molecule'))
)
# Each box is a GFlowNet that samples proportionally
bridge.register_function('atom_C', GFlowNetBox(1, 6))
bridge.register_function('atom_O', GFlowNetBox(1, 8))
bridge.register_function('bond', GFlowNetBox(14, 32))
# Sample molecule via symbolic structure
molecule = bridge.evaluate(molecule_diagram)
3. SICP Interpreter with Neural Components
# Hybrid evaluator
class HybridEvaluator:
def eval(self, expr, env):
if self.is_symbolic(expr):
# Standard SICP evaluation
return self.eval_symbolic(expr, env)
elif self.is_neural(expr):
# DisCoPy diagram evaluation
return bridge.evaluate(expr)
else:
# Hybrid: symbolic structure, neural leaves
diagram = bridge.parse_sexpr(str(expr))
return bridge.evaluate(diagram)
Neighbor Skills
- sicp: Pure symbolic computation
- gflownet: Pure subsymbolic sampling
- discopy: String diagrams library
- lispsyntax-acset: S-expressions as data
- forward-forward-learning: Local neural learning
- proofgeneral-narya: Proof term manipulation
Resources
- DisCoPy Documentation
- Compositional Distributional Models of Meaning
- GFlowNets
- Neural Theorem Provers
- SICP
End-of-Skill Interface
Commands
# Parse S-expression to diagram
python neuro_symbolic_bridge.py --parse "(f (g x) y)"
# Evaluate with neural semantics
python neuro_symbolic_bridge.py --eval "(lambda (x) x)" --input "[1,2,3]"
# Train hybrid model
python neuro_symbolic_bridge.py --train examples.json --epochs 100
Autopoietic Marginalia
The interaction IS the skill improving itself.
Every use of this skill is an opportunity for worlding:
- MEMORY (-1): Record what was learned
- REMEMBERING (0): Connect patterns to other skills
- WORLDING (+1): Evolve the skill based on use
Add Interaction Exemplars here as the skill is used.