chemart / prime-number-chemistry

View on GitHub

Prime number (number-division) chemistry — The example that shows why a chemistry cannot always be a finite matrix. Molecules are integers; when a smaller number divides a larger one, the larger is replaced by the quotient while the divisor survives as a catalyst…

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

How it works

The example that shows why a chemistry cannot always be a finite matrix. Molecules are integers; when a smaller number divides a larger one, the larger is replaced by the quotient while the divisor survives as a catalyst. Nothing ever consumes a prime, so primes accumulate as the inert residue of the reaction - the sieve of Eratosthenes as a reactor. The species set is unbounded and only ever discovered by running the rule.

S
natural numbers >= 2; species id n<k>, structure the decimal integer k · implicit
R
s1 + s2 -> s1 + s2/s1 if s1 < s2 and s1 | s2; otherwise elastic (book eq. 2.43) · arity 2
A
well-stirred-multiset · none - the divisor acts as a catalyst, so the molecule count stays M

Parameters

namedefaultmeaning
method
enum · structural
"soup" soup: the book's stochastic run, observed reactions with counts; closure: every reaction reachable from the distinct seed numbers (Chemart addition)
soup | closure
M
int · population
100 number of molecules drawn for the initial soup (ignored when numbers is given)
[2, 100000]; book and paper: 100; paper fig. 6 scans 10-200
minn
int · structural
2 lower bound of the uniform initialisation interval (inclusive)
[2, ∞]
maxn
int · structural
1000 upper bound of the initialisation interval (inclusive); maxn >> M makes the run constructive
[2, ∞]; book 2.5.2 and appendix: 1000; paper [72] fig. 5: 10000
numbers
list · structural
[] explicit initial multiset of integers >= 2; overrides the random draw of M numbers from [minn, maxn]
book fig. 2.7: each of 2..101 once
iterations
int · population
10000 soup only: number of collisions, elastic ones included (M collisions = one generation)
[0, 1e+07]; appendix: 10000; figs. 2.8-2.9: 20000; paper [72]: 700 generations = 700 M
max_species
int · structural
1000 closure only: species budget; the closure is finite, so it is truncated only when this is exceeded
[1, ∞]

Prime number (number-division) chemistry

One of the artificial chemistries of Banzhaf & Yamamoto, Artificial Chemistries (MIT Press, 2015), §1 (eqs. 1.4-1.5), 2.5.2, appendix (NumberChem.py, NumberChemHO divrule); first proposed by Banzhaf, Dittrich & Rauhe, 1996.

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/prime-number-chemistry", seed=0)   # same as "prime-number-chemistry"
print(net.summary())

What to look for

  • primes emerge as the non-reactive set: no reaction consumes a prime, so the prime count never decreases
  • the prime concentration grows sigmoidally, reaching 1.0 when M is large enough (paper [72] fig. 5: M = 100, maxn = 10000)
  • initialising with each of 2..101 produces no new number types; initialising 100 numbers from [2, 1000] does (book 2.5.2, figs. 2.7-2.9)
  • no prime factorisation - divisors are catalysts, so copies are not produced and only a limited number of copies of each prime remains
  • phase transition in soup size: small soups (M < 40) end with non-primes left, large ones (M > 100) end all-prime, with strong run-to-run fluctuations in between (paper [72] fig. 6, 700 generations, 30 runs per M)

Implementation decisions

  • Collision algorithm follows the appendix code (NumberChem.py): two molecules are removed uniformly at random without replacement (Multiset.expelrnd twice, so they are distinct molecules), sorted, the larger replaced by larger/smaller if it is strictly larger and divisible, and both reinjected. chemart.soup.soup with dilution none does exactly this; the population stays M.
  • The three descriptions agree on what is replaced: book eq. 2.43 and the 2.5.2 pseudocode (whose two branches are the two orderings of the draw), NumberChem.py (only m2 is overwritten) and paper [72] eq. 18 with reactor algorithm II (only s1 is replaced by s3) all replace only the dividend; the divisor is a catalyst. No source consumes both reactants. The 2.5.2 pseudocode's draw(P) does not say whether the same molecule can be drawn twice; the appendix code resolves it (no).
  • Initial draw: M independent uniform integers in [minn, maxn], both ends inclusive (np.random.randint(minn, maxn+1) in NumberChem.py), so duplicates are possible. `numbers` gives an explicit multiset instead (book fig. 2.7 initialises with each of 2..101 once).
  • iterations counts every collision, elastic ones included (NumberChem.py loop; book 2.6.1: a generation is M collisions). The soup output is status observed: species are every number present at the start or produced, reactions carry firing counts, initial_state is the drawn multiset, extras.final_state the final one, extras.analysis.prime_fraction the prime fraction after each generation.
  • method closure is a Chemart addition, not in the book: chemart.expand.expand of the distinct seed numbers under the same rule. It is always finite (a quotient divides an existing number), so status is complete unless max_species cuts it.
  • Species ids are n<k> rather than bare integers so that stoichiometry text is unambiguous (2 + 4 -> 2 + 2 reads n2 + n4 -> 2 n2); structure holds the integer. No rate constants: the book gives none.
  • The v1 seed parameter is dropped (the seed is an argument of generate_network); the v1 phenomenon 'sigmoidal growth of prime concentration to 1.0' is qualified: a composite whose divisors are all absent from the soup is never divided, so the final prime fraction reaches 1.0 only for large enough soups (paper [72] fig. 6: M < 40 mostly ends in dead ends, M > 100 nearly always reaches 100%).
  • Book ref [113] (Berry & Boudol, the chemical abstract machine) is cited in 2.5.2 as a previous study of the number-division chemistry; it is kept as the book gives it, but it is about CHAM, not this chemistry. The algorithm and numbers come from [72] and the appendix.

Sources

  • Banzhaf, W., Dittrich, P. & Rauhe, H. (1996). Emergent computation by catalytic reactions. Nanotechnology 7:307-314. Section 4.4, eq. 18, reactor algorithm II, figs. 5-6. https://www.cs.mun.ca/~banzhaf/papers/nanotechnology7.pdf
  • PyCellChemistry src/NumberChem.py and src/artchem/Multiset.py (Yamamoto, 2013). https://github.com/laryamamoto/PyCellChemistry

Banzhaf & Yamamoto, Artificial Chemistries (2015), §1 (eqs. 1.4-1.5), 2.5.2, appendix (NumberChem.py, NumberChemHO divrule)

Preview at default parameters

201 species · 159 reactions · status observed · seed 1

n261 + n29 -> n29 + n9  (x1)
n162 + n324 -> n162 + n2  (x1)
n530 + n2 -> n2 + n265  (x1)
n2 + n364 -> n2 + n182  (x1)
n250 + n750 -> n250 + n3  (x1)
n2 + n56 -> n2 + n28  (x1)
n756 + n2 -> n2 + n378  (x1)
n162 + n2 -> n2 + n81  (x1)
n774 + n3 -> n3 + n258  (x1)
n542 + n2 -> n2 + n271  (x1)
n3 + n828 -> n3 + n276  (x1)
n2 + n970 -> n2 + n485  (x1)
n2 + n582 -> n2 + n291  (x1)
n29 + n551 -> n29 + n19  (x1)
n3 + n870 -> n3 + n290  (x1)
n512 + n64 -> n64 + n8  (x1)
n546 + n21 -> n21 + n26  (x1)
n29 + n754 -> n29 + n26  (x1)
n264 + n8 -> n8 + n33  (x1)
n2 + n118 -> n2 + n59  (x1)
n81 + n486 -> n81 + n6  (x1)
n9 + n81 -> 2 n9  (x1)
n8 + n624 -> n8 + n78  (x1)
n26 + n2 -> n2 + n13  (x2)
n9 + n3 -> 2 n3  (x6)
n36 + n3 -> n3 + n12  (x1)
n2 + n422 -> n2 + n211  (x1)
n21 + n378 -> n21 + n18  (x1)
n9 + n369 -> n9 + n41  (x1)
n3 + n258 -> n3 + n86  (x1)
n274 + n2 -> n2 + n137  (x1)
n410 + n205 -> n205 + n2  (x1)
n642 + n2 -> n2 + n321  (x1)
n291 + n3 -> n3 + n97  (x1)
n3 + n771 -> n3 + n257  (x1)
n321 + n3 -> n3 + n107  (x1)
n474 + n3 -> n3 + n158  (x1)
n294 + n2 -> n2 + n147  (x1)
n981 + n3 -> n3 + n327  (x1)
n327 + n3 -> n3 + n109  (x1)
… 119 more

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