(*
Demonstration of cascading:
Out = 1000 if (((#A >= 1) && (#B >= 1)) || (#C >= 1)) && (#D ~<~ 100) and otherwise 0
where ~<~ means roughly less than, i.e. we're OK if it doesn't work perfectly near 100.
In practice, the system below has a very low error rate even for #D = 99 and #D = 100.
Note that a few tweaks are used to make a few key reactions irreversible.
Also note that with “detailed” rather than “infinite” compilation semantics, the readout is clearer
if you look a <6 3^ 4> with reporter [6]{3^*} rather than plotting <4 5^2>, which is involved in temporary reactions.
Finally, note that with deterministic (bulk ODE) simulations, the system always goes on, regardless of input.
How can you modify it to work in bulk as well as it does with discrete counts?
*)
directive simulation { final=60000; points=1000; plots = [; **; ; ; < _ h^ X>; ; <4 5^ 2>] }
directive simulator stochastic
directive compilation infinite
( 0 * (* input A *)
| 0 * **** (* input B *)
| 1 * (* input C *)
| 99 * (* input D *)
(* translate A into Y and B into Z while keeping low copy numbers *)
| 1 * {a^*}[A i^]
| 1 * {b^*}[B j^]
(* our previous AND gate "from the refrigerator": X = Y AND Z *)
| 1 * {j^*}[Z i^]:[Y h^]
(* a "wire-OR" via translating C to X, taking three steps to match AND gate timing *)
| 1 * {c^*}[C f^]**__
| 1 * {f^*}[U g^]
| 1 * {g^*}[V h^]
(* a threshold to quickly absorb the first 100 of D and simultaneously deplete W *)
| 1000 * {d^*}[D k^]:[W]
| 100 *
| 1000 * [D]{k^*}
(* remaining W, if any, can enable X to transform into pre-autocatalyst *)
| 1 * {h^*}[X k^]:[W m^]
(* translate pre-autocatalyst to the input of an autocatalyst from our "refrigerator" *)
| 1 * <4>[5^ W]{m^*}
(* here is our autocatalyst <4 5^ 2> ; it can be triggered by any *)
| 1300 * <5^ 2 3^ 4>
| 1000 * <4>[5^ 2]:<6>[3^ 4]{5^*}
)
__