A typed PCFG over patch terms
The genome is a term in quiver's combinator algebra, generated by a probabilistic context-free grammar whose non-terminals are signal kinds.
The representation decision
The genome is a tree: a term in quiver's Layer-1 combinator algebra. It is not a raw patch graph and not a parameter vector, and the patch graph is the compilation target.
Everything follows from this. One representation covers what usually needs three:
| Level of evolution | In the term grammar |
|---|---|
| Node settings | Leaf parameter sites — an f64 or usize draw at each module node |
| Connectivity | Interior structure — chains, parallel branches, modulation attachments |
| Node set | Which productions fire — the module choice sites |
A parameter-vector genome cannot change topology. A raw-graph genome can, but most of its mutations produce invalid graphs, so it needs a repair step, which is a second, undocumented grammar. A typed term needs neither: every sampled term compiles to a valid, sound-making patch, because the type system constrains which productions can fire where.
The sorts are quiver's signal kinds: Audio, V/Oct, Gate, CV. Auracle's
PatchTree splits into AudioNode and ModNode, and the split is enforced by
Rust's own type system: an ill-sorted term is not rejected at runtime; it
cannot be constructed.
The grammar as a probabilistic program
PatchGrammarPrior is a fugue program. Every node at tree path emits real
probabilistic choices at path-keyed addresses:
| Site | Address | Distribution |
|---|---|---|
| source-vs-processor | <p>#leaf | , forced at max depth |
| source kind | <p>#src | , 6 kinds |
| processor kind | <p>#op | , 20 kinds |
| modulation kind | <p>/m#mod | , 8 kinds |
| CV-processor kind | <p>/m#modop | Uniform over ModOp::ALL |
| CV-combiner kind | <p>/m#pairop | Uniform over PairOp::ALL |
| discrete params | <p>#wave, #oct, #color, #fkind, #table, #dmode | Uniform categoricals |
| continuous params | <p>#cut, #res, #det, … |
The amplitude envelope is fixed at amp#attack … amp#release.
The three categorical orders (7 sources, 20 processors, 8 modulation kinds) are the persisted wire format, because the codec writes the chosen index into the trace. They are append-only.
Parsimony is the prior, not a penalty
Deeper terms pay more prior mass by construction: each additional level of
recursion multiplies in another #leaf Bernoulli that came out "processor",
and each processor node draws its own parameters. There is no size penalty term
anywhere.
Ad-hoc parsimony penalties are the norm in genetic programming and a persistent source of trouble: they need tuning, they interact badly with fitness scaling, and they leave the target distribution unwritten. Here the target is written down: , and is exactly the parsimony pressure.
Modulation is a recursive sort
A modulation input does not take "an LFO". It takes a modulation term, which can itself be built from modulation terms:
- Five leaves: LFO, envelope, random (sample-and-hold), envelope follower, Euclidean.
Opwraps one modulation term: quantize, slew, rectify, hold.Paircombines two.
So s&h rand → quantize → slew is a legal modulation term, and the rack draws
the whole chain. Subterms live at <p>/m/0 and <p>/m/1, the same child
convention the audio tree uses; it is unambiguous because every modulation key
sits below a /m.
Its parsimony pressure is max_mod_depth, and the renormalizations that
enforce it live in mod_weights_at: at maximum depth only leaves remain
available, and below a processor the "no modulation" option is removed so a
slot that must be filled is filled.
A modulation slot hangs off every module with somewhere to send it. The
exceptions are the ones without: Noise, whose only site is a colour switch,
and Mix / RingMod, whose two inputs are both audio and whose single knob is
the blend. Having two audio children is not itself an exception: the four
dynamics productions take two subterms and carry a slot as well.
The palette
Forty-two modules: 7 sources, 20 processors, 15 modulators.
sources Vco Supersaw NoiseGenerator Wavetable KarplusStrong FormantOsc
Silence
processors Mix Filter Fold Delay Chorus Reverb Distortion Bitcrush
Phaser RingMod Flanger Tremolo Vibrato Eq Granular Shift
Comp Duck Gate Vocoder
modulators Lfo Adsr SampleAndHold SlewLimiter EnvelopeFollower …
Six processors are binary:
| Production | Second input | |
|---|---|---|
Mix, RingMod | Audio | Merges two chains into one |
Comp, Duck, Gate, Vocoder | Control | Real sidechaining, in a typed tree |
A compressor's sidechain is not an audio input, and the type system makes wiring it as one impossible.
What is not in the grammar
Feedback. Terms are acyclic: there are no feedback combinator productions. Modules with internal feedback (delay, chorus, reverb) are fine, and there are plenty of them.
This is a v1 constraint rather than a principle. A tamed feedback production, with a mandatory attenuator and limiter in the loop path, is the intended v2 grammar extension. Until then cycles are unrepresentable, which is why cable dragging in the UI does not offer them.
Strict validation as an oracle
Grammar output is compiled with quiver's ValidationMode::Strict in the test
suite. Because the grammar is typed, a SignalMismatch is by construction a
bug in our grammar, so Strict doubles as a property-test oracle: sample
terms, compile all of them, and any error fails the test with quiver's
actionable message.
Patches are wired in Warn mode, though, with an allowlist test pinning the
warning classes. Strict rejects two warning-class pairings the compiler
deliberately uses, the clearest being a constant bipolar Offset feeding a
unipolar knob. The allowlist test is what keeps "we know about these two" from
quietly becoming "we ignore all warnings".
Where this comes from
The design mirrors fugue-evo's ArithmeticGrammarPrior, with quiver signal
sorts in place of arithmetic types. That is deliberate: Auracle's genome gets
subtree mutation, subtree-swap crossover, reversible-jump MH and tempered SMC
from fugue-evo unchanged, because they operate on traces and this genome's
trace encoding is faithful.