Reference
Configuration Reference
Every key a GET configuration accepts: what it does, what else it can be, what rejects it. This is the page to look something up in. The route pages show a whole document being written and run.
Top Level
| Key | Type | Default | What it does |
|---|---|---|---|
population_size | integer | required | Individuals in the population. |
network_size | integer | required | Nodes in every expressed graph. Fixed for the run; nothing adds or removes nodes. |
max_edge_multiplicity | integer | 1 |
Edge-weight cap. 1 is an unweighted simple graph; above 1 allows parallel
edges. Must be 1–255. Also sets the SDA alphabet, which is derived as
cap + 1, so every character the automaton can emit is a legal weight. |
crossover_rate | float | required | Probability a selected pair is recombined. Validated in [0, 1]. |
mutation_rate | float | required | Probability a child is mutated at all, not a per-gene rate. Validated in
[0, 1]. |
max_mutations | integer | 1 |
A mutating child takes a count drawn uniformly from 1..=max_mutations. Must
be at least 1. Read this and mutation_rate as one knob: whether a child
mutates, then how hard. |
[evolution]
Required. type selects the strategy, and the other keys belong to that strategy.
type | Key | Default | What it does |
|---|---|---|---|
"generational" |
num_generations | required | Whole-population replacements to run. |
elite_count | 1 |
Best individuals carried forward untouched each generation. Must be
less than population_size; equal would mean nothing ever
changes. | |
"steady_state" |
num_mating_events | required | Single breeding events to run. One event touches one scope, not the whole population. |
replacement | { type = "worst" } |
Who the children overwrite. See Add a Replacement
Policy for the axis. worst is what makes steady-state self-elitist;
random draws uniformly and gives that up. |
replacement lives inside [evolution] rather than in a section of its
own, because it belongs to whichever strategy displaces individuals, the same way
elite_count belongs to generational. Generational never asks who to overwrite.
[scope]
Required in every configuration, generational included. It names which slice of the population one breeding event may touch.
type | Key | What it does |
|---|---|---|
"global" | none | Every individual is a candidate. Consumes no randomness. |
"random_subset" | size |
size distinct individuals, drawn uniformly without replacement. At least 1
and at most population_size, and at least 4 under steady-state,
which needs two parents and two distinct individuals for them to replace. Generational
has no such floor. |
size lives here, not under [selection]. It is the scope's own
number; [selection] carries only the tournament's. A tournament may exceed the
population, because it samples with replacement, and the steady-state floor of four applies to
size rather than to tournament_size.
[selection]
Required. Who, within the scope, becomes a parent.
type | Key | What it does |
|---|---|---|
"best" | none | Takes the scope's fittest, in rank order. Consumes no randomness; the scope did the drawing. |
"tournament" | tournament_size |
Draws tournament_size members of the scope with replacement and takes
the best, once per parent. At least 1. |
[crossover]
Optional. Omitted means two-point, which is what every representation did before the operator became selectable, so an existing configuration keeps its behaviour by leaving this out.
type | What it does |
|---|---|
"two_point" |
Two cut points, the middle segment exchanged. The only operator that ships. |
Crossover is a shared section because both genomes' recombination is the same operation over a linear genome. Mutation is not; see below.
[genome]
Required. type selects the representation, and the keys under it are that representation's.
type = "edge_edit"
| Key | Default | What it does |
|---|---|---|
gene_length | required | Number of edit operations in the genome. The graph is what replaying them produces. |
base_graph | the empty graph | An edge-list file the edits are applied to. A relative path from the location of the
.toml file, not from your working directory. The file's
# nodes = N header must equal network_size. Read as
0-indexed. |
mutation | { type = "reroll_gene" } |
Which mutation operator applies. See Add a Mutation Operator. |
operation_weights | all 1.0 |
Sub-table, below. |
[genome.operation_weights]
Nine relative weights, one per edit operation:
toggle, add, delete, hop, swap,
local_toggle, local_add, local_delete, null.
The Nine Operations says what each one does to the graph.
They are weights, not probabilities: they are normalized, so they need not sum to anything. Each
must be finite and non-negative, at least one must be positive, and 0.0
disables its operation outright. Omit the table entirely, or any field in it, and that operation
weighs 1.0. Like [genome] itself, this sub-table rejects a key it
does not recognize.
type = "sda"
| Key | Default | What it does |
|---|---|---|
num_states | required | States in the automaton. Must be in 1..=65536. |
max_resp_len | required | Longest response string a transition may emit; must be at least 1. Responses are drawn from
1..=max_resp_len, never empty, which is what guarantees the automaton
terminates. |
init_state | 0 |
State the automaton starts in. Must be less than num_states. |
init_char_mutation_rate | 0.04 |
Chance a mutation targets the initial character rather than the tables. In
[0, 1]. |
transition_vs_response_rate | 0.5 |
Given the tables are targeted, the split between transitions and responses. In
[0, 1]. |
mutation | { type = "redraw_one" } |
Which mutation operator applies. |
num_chars. The alphabet is derived as
max_edge_multiplicity + 1, so every character the automaton can emit is a legal edge
weight and none is ever clamped away.
Mutation is per-genome; crossover is shared. mutation sits inside each
genome's own block rather than in a section of its own, because what counts as "one mutation"
differs entirely between a list of edit operations and an automaton, and a shared enum would let a
configuration name an operator meaningless for the genome actually selected.
[fitness]
Required. type selects the objective.
type | Direction | What it scores |
|---|---|---|
"epi_spread" | maximize | Total ever-infected, averaged over epidemics. |
"epi_length" | maximize | Timesteps for the outbreak to burn out. |
"epi_prof_match" | minimize | RMSE against a target infection profile. |
"struct_match" | minimize | Structural distance from a folder of reference graphs. Reads data from disk; requires
max_edge_multiplicity = 1. |
"python" | declared at registration | A Python callable registered on the evolver before the run. |
The SIR block: the three epi_* objectives
These keys sit directly under [fitness], not in a sub-table.
| Key | Default | What it does |
|---|---|---|
infection_rate | required | Per-contact transmission probability, in [0, 1]. |
num_epidemics | required | Epidemics averaged per evaluation. At least 1, since fitness is their mean. |
patient_zero | random each epidemic | Fix the seed node instead. When set, it must be less than network_size. |
min_epidemic_length | 3 |
Outbreaks shorter than this are re-simulated. Set to 1 to disable the re-roll. |
max_epidemic_retries | 5 |
How many re-simulations before accepting a short one. At least 1. |
epi_prof_match
target_profile is required, a non-empty array of finite numbers. Comparison covers the
target array's length: a shorter epidemic is padded with zeros, and a longer epidemic's tail is
ignored. Nothing is prepended or rescaled. Supplying it under another objective is rejected.
struct_match
| Key | Default | What it does |
|---|---|---|
reference_folder | required | Folder of reference graphs, one edge-list file each. Not checked when the config is parsed: validation does no I/O, so a missing or empty folder is reported when the run starts. |
degree_bins · clustering_bins · spectral_bins |
50 |
Histogram bins per statistic family. More bins resolve finer differences and need more reference graphs to fill them. Each bin count must be at least 1. |
degree_gamma · clustering_gamma · spectral_gamma |
1.0 |
RBF bandwidths. Must be finite and greater than zero, because the kernel divides by them. |
degree_weight · clustering_weight · spectral_weight |
1.0 |
How much each family counts. Finite and non-negative; they cannot all be zero, which would score every candidate identically. |
density_weight | 1.0 |
How much distance from the reference set's mean density counts. Must be finite and non-negative; zero switches the penalty off. |
exp(-gamma * d²) collapses to
zero for every candidate, the whole population scores about the same, and evolution stalls while
appearing to run normally. And a weight is only as live as the reference set makes it: rings and
paths have clustering coefficient 0 at every node, so a reference set drawn only from those leaves
clustering_weight set and the family it weights inert, with nothing reporting it.
What Is Not a Config Value
| Thing | Where it actually goes |
|---|---|
| The seed | One master seed is passed to the run call; the population, evolution, epidemics and
replicates all derive from it. Writing seed under [fitness]
is rejected by name rather than ignored, so a document carrying one fails loudly instead
of running with a seed nobody supplied. |
| A base graph in your own node numbering, or one supplied without a config file | [genome] base_graph covers the ordinary case, but it is 0-indexed and it
resolves against the config file, so a file numbered from 1, or a config assembled as
objects in Python, still needs set_base_graph_from_file and its
min_node_index. See
Python: Config Objects. |
| Replicate count, output folder | Arguments to the run, not the configuration. See the route pages. |
num_chars for SDA |
Derived from max_edge_multiplicity, above. |
Typos: Which Tables Catch Them
[genome] and [genome.operation_weights] reject any key they do not
recognize, under either type. Most other tables ignore one.
[fitness] cannot reject typos, and this is structural rather than an oversight.
Its variants flatten the shared SIR block into themselves, and flattening consumes unrecognized
keys into the flattened field, so the check that rejects them cannot fire there. Two names are
caught explicitly, because both are mistakes a reader makes rather than typos:
seed, which belongs to the run call, and target_profile under an
objective that never reads one. Anything else misspelled under
[fitness] is silently ignored, and your run uses the default.
When a Value Is Rejected
Most validation runs once, up front, so common bad configurations fail before evolution.
Some SDA dimension constraints and filesystem-dependent checks are reached only when a run
starts rather than when the file loads: max_resp_len = 0 is one. The error names the field and the
constraint. From Python it arrives as a ValueError naming the attribute path
you would have written (config.scope.size), not the TOML key, so the message matches
the code in front of you.
Validation deliberately does not touch the filesystem. A path-valued setting, today only
reference_folder, is checked when the run starts; the folder must exist and contain at
least one usable reference graph.