Chemical Abstract Machine Skill
"Computation as chemistry: molecules floating in solution, reacting when they meet."
Core Concept
The Chemical Abstract Machine (CHAM) models computation as:
- Solution — a multiset of molecules
- Reactions — rewrite rules on molecule patterns
- Heating/Cooling — structural rearrangement
- Parallel — reactions happen non-deterministically
Solution: {A, A, B, C, D}
Reaction: A + B → E
After reaction: {A, C, D, E} (one A, one B consumed)
Why It's Strange
- No sequential order — reactions fire when reactants meet
- Multiset semantics — quantities matter (2 A's ≠ 1 A)
- Non-deterministic — which reaction fires is random
- Massively parallel — all possible reactions can happen at once
- Spatial — extended to membranes (P systems)
Formal Definition
Solution S ::= ∅ | m | S, S (multiset of molecules)
Molecule m ::= ... (domain-specific)
Reaction: m₁, ..., mₙ ⟶ m'₁, ..., m'ₖ
Heating: S ⟷ S' (structural equivalence)
Example: Concurrent λ-Calculus
Molecules:
(λx.M) — abstraction
M N — application
Reaction (β-reduction):
(λx.M), N ⟶ M[N/x]
Solution: {(λx.x+1), 5, (λy.y*2), 3}
Possible reactions (parallel!):
{(λx.x+1), 5} ⟶ {6}
{(λy.y*2), 3} ⟶ {6}
Result: {6, 6}
Membrane Computing (P Systems)
Hierarchical compartments:
┌─────────────────────────────────┐
│ Skin membrane │
│ ┌─────────────┐ ┌───────────┐ │
│ │ {A, B, C} │ │ {D, E} │ │
│ │ membrane 1 │ │ membrane 2│ │
│ └─────────────┘ └───────────┘ │
│ │
│ {F, G} (in skin, outside 1&2) │
└─────────────────────────────────┘
Rules can:
- React within membrane
- Send molecules OUT (to parent)
- Send molecules IN (to child)
- Dissolve membrane
Implementation
from collections import Counter
import random
class CHAM:
def __init__(self):
self.solution = Counter() # Multiset
self.reactions = []
def add(self, molecule, count=1):
self.solution[molecule] += count
def add_reaction(self, reactants, products):
"""reactants and products are Counters"""
self.reactions.append((Counter(reactants), Counter(products)))
def step(self):
"""Fire one random applicable reaction."""
applicable = []
for reactants, products in self.reactions:
if all(self.solution[m] >= c for m, c in reactants.items()):
applicable.append((reactants, products))
if not applicable:
return False # No reaction possible
reactants, products = random.choice(applicable)
self.solution -= reactants
self.solution += products
return True
def run(self, max_steps=1000):
"""Run until no reactions possible."""
for _ in range(max_steps):
if not self.step():
break
return self.solution
# Example: A + B → C, A + C → D
cham = CHAM()
cham.add('A', 3)
cham.add('B', 2)
cham.add_reaction(['A', 'B'], ['C'])
cham.add_reaction(['A', 'C'], ['D'])
result = cham.run()
print(result) # e.g., Counter({'D': 2, 'C': 0, 'A': 0, 'B': 0})
Kappa Language (Systems Biology)
// Agents with sites
%agent: A(x, y)
%agent: B(z)
// Rules
A(x[.]), B(z[.]) -> A(x[1]), B(z[1]) // Binding
A(x[1]), B(z[1]) -> A(x[.]), B(z[.]) // Unbinding
// Rates
A(x[.]), B(z[.]) -> A(x[1]), B(z[1]) @ 0.1
Stochastic Simulation (Gillespie Algorithm)
import math
import random
def gillespie_step(solution, reactions, rates):
"""One step of Gillespie's stochastic simulation."""
# Calculate propensities
propensities = []
for (reactants, products), rate in zip(reactions, rates):
# Count ways to choose reactants
ways = 1
for mol, count in Counter(reactants).items():
ways *= math.comb(solution[mol], count)
propensities.append(rate * ways)
total = sum(propensities)
if total == 0:
return None, None
# Time until next reaction
tau = random.expovariate(total)
# Which reaction
r = random.uniform(0, total)
cumsum = 0
for i, prop in enumerate(propensities):
cumsum += prop
if r <= cumsum:
return tau, i
return tau, len(reactions) - 1
Applications
| Domain | Use Case | |--------|----------| | Biology | Metabolic networks, signaling | | Concurrency | Process calculi (π-calculus) | | Chemistry | Reaction kinetics | | Computing | DNA computing, molecular programming |
Relationship to Other Models
| Model | Relationship | |-------|--------------| | Petri Nets | CHAM is a textual Petri net | | π-calculus | Can be encoded in CHAM | | Ambient Calculus | Membrane = ambient | | CRN | Chemical Reaction Networks |
Literature
- Berry & Boudol (1992) - "The Chemical Abstract Machine"
- Păun (2000) - "Computing with Membranes" (P systems)
- Danos & Laneve (2004) - Kappa language
End-of-Skill Interface
GF(3) Integration
# Assign trits to molecule species
MOLECULE_TRITS = {
'A': 1,
'B': -1,
'C': 0,
}
# Conservation: reactions preserve GF(3) sum
def verify_reaction_gf3(reactants, products):
r_sum = sum(MOLECULE_TRITS[m] for m in reactants)
p_sum = sum(MOLECULE_TRITS[m] for m in products)
return r_sum % 3 == p_sum % 3
# A(+1) + B(-1) → C(0) ✓ (0 = 0 mod 3)
r2con Speaker Resources
| Speaker | Relevance | Repository/Talk | |---------|-----------|-----------------| | condret | ESIL multiset semantics | radare2 ESIL | | alkalinesec | ESILSolve reactions | esilsolve | | pancake | r2pipe chemistry | radare2 |
Related Skills
petri-nets- Graphical versionprocess-calculus- π-calculus connectionsystems-biology- Main application domainstochastic-simulation- Gillespie algorithm
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.