# Small populations that copy a composition label

Example for **Finite-count chemical inheritance with reversible interactions and bounded food supplies**, manuscript entry 32, SHA-256 `03705999826adddef5723e0bdc3c684f4d98a55cfcc85eac11fef4c1e6b4eb00`.

Two modules each contain residents and a finite food supply. A bit is stored by which of two resident species is present in each module, giving four possible words. Reversible growth amplifies the resident counts before a scheduled fair split. The cycle succeeds only if **both complementary daughters** retain a resident in both modules and return to the admitted restart region after food refill. Failed partitions remain in the probability denominator.

This is amplification and partition of disjoint species supports. It is not a bistable switch: the reactions cannot create an absent resident or remove the last molecule of a present one. That protects a pure label during the batch, but also makes contamination permanent.

## Run

Python 3.11 or newer:

```sh
python -m venv .venv
# Windows: .venv\Scripts\activate
# macOS/Linux: source .venv/bin/activate
python -m pip install -r requirements.txt
python -m unittest -v test_example.py
python example.py --output outputs
```

The default run takes seconds. It writes a complete literal batch path, one split/refill record, the selected-daughter restart matrix, lineage and family tables, an empty-daughter diagnostic, two figure pairs, structured results and provenance hashes. Seven scientific test groups check reaction aggregation, exact probability identities and certificates, numerical kernels, geometry, contamination and interruption handling. Matrix exponentials and sample paths are numerical diagnostics; the rational generator certificates are separate. Lean is not rerun.

## Editable model and protocol inputs

The top of `example.py` contains module capacity K=9, forward/reverse rates a=1000 and b=1, coupling gamma=1/10, deadline T=20, encoded word, selected resident counts, random seed, computational event budget, lineage length and family depth. Rational strings preserve exact model coefficients. The normalized volume and source time unit are hypothetical conventions, not experimental calibration; T=20 does not mean twenty seconds.

`Parameters` supports finite positive a,b and nonnegative gamma, with a dense-chain implementation limit K<=40. The paper's interacting nominal construction has gamma>0; gamma=0 is available as an uncoupled control. A larger K can be computationally expensive because the transition matrix has K^4 entries. The nearest-region decoder explicitly supports K<=20. New mechanisms or volume conventions require new analyses, not just changed plotting labels.

`MolecularState` uses the order **X0,Y0,X1,Y1,F0,F1**. Module i conserves Xi+Yi+Fi=K in a batch. `pure(K,word,selected)` constructs a state on one invariant face. A restart is admitted when each selected count is between 1 and K-1, the other resident species is absent, and both module totals are K. Food is excluded from normalized resident composition.

`FiniteFoodChemistry` builds all 24 directed channels from twelve reversible pairs:

    S + Fi <-> 2S                 coefficients a, b
    S + U + Fi <-> 2S + U         coefficients a*gamma, b*gamma

Here S is either resident of module i and U either resident of the other module. `Reaction.propensity` uses falling factorials without combinatorial divisors. For example, reverse autocatalysis is b*nS*(nS-1), and its cross-catalyzed version has the extra gamma*nU factor. All catalysts remain in reactant multiplicities and are returned unchanged. The nominal 24 coefficients are positive. Forward/reverse ratios all equal a/b, including catalyzed pairs.

The chemistry object can simulate mixed-support states as well as pure states. Its direct Gillespie simulation uses the literal channels. `MAX_SSA_EVENTS` is a computational guard, not a protocol event quota: an interrupted run returns `completed=False`, and a cycle then has `success=None` and no split. Unfinished simulation is neither successful copying nor a failed chemical cycle.

`ScheduledCycle` runs a closed batch to the deterministic deadline, then invokes `FairDivision`. Every resident **and food** molecule is independently assigned to daughter A with probability one half; daughter B receives the exact complement. Each daughter then receives K minus its module total in fresh food. The controller reads totals, not the species label. Across both daughters, exactly K food molecules per module are added, even for a failed split. The nominal cycle therefore adds 18 food molecules. Refill never changes resident counts or repairs missing residents.

The split, refill and volume reset are ideal instantaneous external operations. Solvent, membrane and controller molecules are not counted in the 18-molecule compartment budget. The model is not an autonomous protocell.

## Exact certificates and numerical probabilities

`CountChain` aggregates the literal chemistry on a pure face to states (n0,n1) in {1,...,K}^2. Module-i birth and death rates are

    a*ni*(K-ni)*(1+gamma*nj)
    b*ni*(ni-1)*(1+gamma*nj).

The tests compare these exact rates to sums of literal channel propensities for every nominal K=9 state and all four words. Module totals, absent-species invariance and last-copy protection are checked directly. The reduced chain applies to pure faces; it must not be used to erase contamination in a mixed state.

`FairDivision.empty_probability(n)` is exactly g(n)=2^(1-n), the chance that a module's residents all go to one daughter. Given parent counts, joint success is Q=(1-g(n0))*(1-g(n1)). The observable H=g(n0)+g(n1) bounds conditional failure above. Allocation of different molecules is independent; the two daughter populations are complementary, and the two module count processes interact.

`DriftCertificate.compute(chain,s)` evaluates Lg+s*g at every finite state using fractions and chooses its nonnegative maximum C. Thus Lg<=-s*g+C is an exact checked inequality. Summing modules, applying the finite-state expectation inequality, and using exp(-s*T)<=1/(1+s*T) gives the uniform bound

    joint success >= max(0, 1 - 2/(1+s*T) - 2*C/s).

For K=9, s=3900 gives C=2523/160 and the exact lower bound **8046297159/8112104000 >0.99188782**. For K=20, s=9000 gives C=2535/131072 and **7077818258231/7077927321600 >0.99998459**. These are uniform over admitted starts and all four words. The package separately reproduces these fixed manuscript cases even if editable study inputs change. For other inputs it computes a new finite-state certificate; a lower bound of zero is inconclusive.

The operating-box replay uses a in [500,1500], b in [1/2,2], gamma in [1/20,2/9], K=9 and s=1800. The generator expression is affine in each parameter separately, so its maximum on the rectangular box occurs at a vertex. Exact checks at every state and all eight vertices yield C=279/32 and **114080769/115203200 >0.99025694**. This is a compatible three-parameter family: catalytic rates stay a*gamma and b*gamma. It is not a box of 24 independently perturbed rate constants.

`transition_matrix(T)` evaluates exp(T*L) with SciPy and checks row sums and nonnegativity within a stated numerical tolerance. It does not clip negative entries or renormalize rows. The default numerical one-cycle minima are approximately **0.9921325119** at K=9 and **0.9999961088** at K=20. These are evaluations, not certified probability enclosures.

`stationary()` returns exact rational probabilities. One module has distribution proportional to binomial(K,n)*(a/b)^n for n=1,...,K; its normalizer is (1+a/b)^K-1. The joint stationary law is the product of these laws. Exact detailed balance is checked on every edge. Coupling cancels from stationary balance because it multiplies both directions equally; it still changes transient laws and sample paths. Stationary factorization does not imply transient independence.

## Repeated copying without discarding failures

`RestartKernel` constructs W(x,y), the probability of joint cycle success and daughter A restarting at y, by multiplying the batch transition matrix by the actual binomial allocation weights, with 1<=yi<ni in each module. Food allocation sums to one and is followed by the declared refill. W is substochastic: its row sum is joint-return probability and the missing mass is failure. The code checks this row-sum identity against the separate Q payoff. It never divides by the success probability.

The exported `restart_kernel.csv` has both rows and columns in lexicographic order (1,1),(1,2),...,(K-1,K-1); column names identify the daughter state. `lineage(N)` computes W^N*1, following daughter A but still inspecting both daughters each cycle. At nominal K=9, the numerical minimum after 200 cycles is approximately **0.206033**. Uniform bounds q^N and u^N, where u=Q(K,K), are saved alongside it. High one-cycle reliability is not indefinite retention: u<1 implies eventual failure with probability one under repeated cycling.

`family(depth)` computes the probability that every internal node's cycle succeeds. For each terminal parent n, it sums the successful split weights times V(y)*V(n-y), then averages over the batch transition. The two child counts remain complementary; only their subsequent separate compartment evolutions are independent given those restart states. This avoids replacing the family by independent samples from a marginal daughter law. The CSV also reports the paper's union lower bound max(0,1-(2^depth-1)*(1-q)) and upper bound u^(2^depth-1).

```python
from example import *
chain = CountChain(Parameters(9, F(750), F(1), F(1,10)))
certificate = DriftCertificate.compute(chain, 1800)
kernel = RestartKernel(chain, F(20))
survival_by_start = kernel.lineage(100)[-1]
all_descendants_by_start = kernel.family(4)[-1]
```

Each simulated cycle uses actual supplied food; these repeated-copying calculations assume fresh food, separate compartments and the declared volume reset at every generation. They are not closed-inventory lineage models.

## Budget, decoding and contamination

`budget_ceiling(total)` balances the two module counts to maximize fair-partition success. With at most 17 peak residents, the best ceiling is **32385/32768 =0.988311767578125**, below 99%. Eighteen suffice by the K=9 certificate. This sharp budget is restricted to two pure-species modules, independent fair allocation of individual molecules, immediate representation in both daughters and no resident repair. It is not a universal molecular-memory lower bound.

`CompositionRegions` explicitly constructs admitted normalized compositions and implements an L1 nearest-region decoder, returning no word on a tie. The global inter-label separation is exactly 2/K, attained by changing the low-count module's species when the counts are (1,K-1). Measurement error strictly below 1/K guarantees the same label. The decoder does not clamp or normalize a noisy reading, which would change its stated error. `MolecularState.word` is the exact support decoder and rejects empty or contaminated modules.

A single added alternative resident cannot be eliminated by the batch reactions. At division at least one daughter receives a contaminant, so both daughters cannot return to the original pure-label region. The tests explicitly check support protection and this allocation obstruction. Measurement robustness is not biochemical error correction.

The trimolecular catalytic channels are effective mass-action steps. Adding explicit binding complexes changes the state space, partition objects and generator bounds. The current numerical and exact certificates apply only to the specified table. Thermodynamic consistency of forward/reverse ratios does not quantify the work or feasibility of the external split, refill or reset.

## Provenance and license

The manuscript PDF is unchanged. The code independently implements its reaction table, protocol, finite generator and conventional restart/geometry constructions using public mathematical inputs; no proof workspace is needed. Output metadata records source and file hashes. Downloaded scientific JSON/CSV outputs are replayed from a clean package.

MIT is proposed for this original companion code, pending the owner's license decision. This README does not grant a license or alter manuscript/dependency rights.
