chemart / farmer-immune

View on GitHub

Bitstring immune system model (idiotypic network) — An immune system as a reaction network, and one of the few chemistries that fixes its own rate constants. Antibodies are bitstrings with two sites; when one antibody's paratope matches another's epitope, the recogniser i…

chemistry official · built in bio-inspired fidelity: book+decisions constructive #banzhaf-yamamoto

How it works

An immune system as a reaction network, and one of the few chemistries that fixes its own rate constants. Antibodies are bitstrings with two sites; when one antibody's paratope matches another's epitope, the recogniser is replicated and the recognised destroyed. The crucial move is that the reaction rate is computed from the *degree* of complementarity between the strings, over all alignments - structure determines kinetics. Species below a concentration threshold are periodically culled and new ones injected, so the species set turns over.

S
antibodies X_i as binary strings with two binding sites (epitope e, paratope p); antigens Y_j with an epitope · implicit
R
Recognition of an epitope by a paratope replicates the recogniser and destroys the recognised. Matching specificity: m_ij = sum_k G( sum_n [ e_i(n+k) XOR p_j(n) ] - s + 1 ), G(x)=x for x>0 else 0, over all alignments -l_p < k < l_e. · arity 1, 2
A
ode, ssa · metadynamics: periodically drop species below a concentration threshold and inject new ones

Parameters

namedefaultmeaning
N
int · population
10 number of antibody species
[1, 100]
M
int · population
2 number of foreign antigens
[0, 20]
l_e
int · structural
8 epitope length (bits)
[1, 64]
l_p
int · structural
8 paratope length (bits)
[1, 64]
s
int · structural
6 matching threshold: an alignment counts when at least s bits are complementary
[1, ∞]
c
float · kinetic
1.0 weight of the interactive part vs. spontaneous decay
[0, ∞]
k1
float · kinetic
1.0 suppression vs. stimulation weight, antibody-antibody
[0, ∞]
k2
float · kinetic
0.5 spontaneous antibody decay rate
[0, ∞]
k3
float · kinetic
1.0 suppression weight, antibody-antigen
[0, ∞]

Bitstring immune system model (idiotypic network)

One of the artificial chemistries of Banzhaf & Yamamoto, Artificial Chemistries (MIT Press, 2015), §11.2.2; first proposed by Farmer, Packard & Perelson, 1986.

Its generator ships with the chemart library, so loading it runs no code from the hub and needs no trust_remote_code.

import chemart

net = chemart.generate_network("chemart/farmer-immune", seed=0)   # same as "farmer-immune"
print(net.summary())

What to look for

  • clonal selection
  • idiotypic network memory
  • constructive dynamics via metadynamics

Implementation decisions

  • Strings are random bits from the seed. Each term of eqs. 11.5-11.6 is one mass-action reaction whose rate the matching strengths prescribe: stimulation X_i + X_j -> 2X_i + X_j (c m_ji), suppression X_i + X_j -> X_j (c k1 m_ij), antigen stimulation X_i + Y_j -> 2X_i + Y_j (c m), antigen removal Y_j + X_i -> X_i (k3 m), decay X_i -> (k2). A self-interaction i = j uses 2X_i on the left.
  • The book says strings bind when 's > min(l_e, l_p)', which contradicts its own definition of G. Here an alignment contributes when at least s bits are complementary, which is what eq. 11.4 computes.
  • The book gives no parameter values; defaults are N = 10, M = 2, 8-bit sites, s = 6, c = k1 = k3 = 1, k2 = 0.5. Metadynamics (mutation and replacement) acts between network snapshots and is not generated; mutation_ops is dropped.

Banzhaf & Yamamoto, Artificial Chemistries (2015), §11.2.2

Preview at default parameters

12 species · 88 reactions · status complete · seed 1

X1 + X2 -> 2 X1 + X2  [mass-action k=1.0]
X1 + X4 -> X4  [mass-action k=1.0]
X1 + X5 -> X5  [mass-action k=1.0]
X1 + X6 -> 2 X1 + X6  [mass-action k=1.0]
X1 + X7 -> 2 X1 + X7  [mass-action k=1.0]
X1 + X8 -> X8  [mass-action k=1.0]
X1 + X10 -> 2 X1 + X10  [mass-action k=1.0]
X2 + X1 -> X1  [mass-action k=1.0]
2 X2 -> 3 X2  [mass-action k=2.0]
2 X2 -> X2  [mass-action k=2.0]
X2 + X3 -> X3  [mass-action k=1.0]
X2 + X4 -> 2 X2 + X4  [mass-action k=1.0]
X2 + X5 -> X5  [mass-action k=3.0]
X2 + X7 -> 2 X2 + X7  [mass-action k=2.0]
X2 + X7 -> X7  [mass-action k=2.0]
X2 + X9 -> 2 X2 + X9  [mass-action k=1.0]
X2 + X10 -> 2 X2 + X10  [mass-action k=2.0]
X3 + X2 -> 2 X3 + X2  [mass-action k=1.0]
X3 + X5 -> 2 X3 + X5  [mass-action k=1.0]
X3 + X5 -> X5  [mass-action k=1.0]
X3 + X6 -> X6  [mass-action k=1.0]
X3 + X8 -> 2 X3 + X8  [mass-action k=2.0]
X3 + X10 -> X10  [mass-action k=2.0]
X4 + X1 -> 2 X4 + X1  [mass-action k=1.0]
X4 + X2 -> X2  [mass-action k=1.0]
2 X4 -> 3 X4  [mass-action k=2.0]
2 X4 -> X4  [mass-action k=2.0]
X4 + X5 -> 2 X4 + X5  [mass-action k=1.0]
X4 + X5 -> X5  [mass-action k=1.0]
X4 + X7 -> 2 X4 + X7  [mass-action k=1.0]
X4 + X8 -> X8  [mass-action k=1.0]
X4 + X9 -> 2 X4 + X9  [mass-action k=2.0]
X4 + X10 -> 2 X4 + X10  [mass-action k=1.0]
X5 + X1 -> 2 X5 + X1  [mass-action k=1.0]
X5 + X2 -> 2 X5 + X2  [mass-action k=3.0]
X5 + X3 -> 2 X5 + X3  [mass-action k=1.0]
X5 + X3 -> X3  [mass-action k=1.0]
X5 + X4 -> 2 X5 + X4  [mass-action k=1.0]
X5 + X4 -> X4  [mass-action k=1.0]
2 X5 -> 3 X5  [mass-action k=1.0]
… 48 more

Generated by the uploader with chemart push; the hub never runs uploaded code.