Initial Genotype Diversity
AgentFarm can seed each starting agent with a slightly different hyperparameter chromosome before the simulation loop begins. This produces a non-monoculture starting population so subsequent learning, reproduction, and selection have a richer search space to work with from step zero.
This is a platform-wide feature: every simulation can opt in via a single config block; the intrinsic-evolution runner installs a non-trivial mode by default. Off by default for ordinary simulations so existing baselines remain behaviorally identical.
Configuration
Driven by SimulationConfig.initial_diversity, which is an
InitialDiversityConfig.
from farm.config import SimulationConfig
from farm.core.initial_diversity import InitialDiversityConfig, SeedingMode
config = SimulationConfig.from_centralized_config(environment="development")
config.initial_diversity = InitialDiversityConfig(
mode=SeedingMode.UNIQUE,
mutation_rate=1.0,
mutation_scale=0.2,
max_retries_per_agent=32,
seed=42, # optional; defaults to the simulation seed
)
You can also set the same fields from the CLI when running
python run_simulation.py:
python run_simulation.py \
--initial-diversity-mode unique \
--initial-diversity-mutation-rate 1.0 \
--initial-diversity-mutation-scale 0.2 \
--initial-diversity-max-retries 32 \
--seed 42
Modes
| Mode | Behavior | Guarantees |
|---|---|---|
none |
Skip seeding; chromosomes stay at their config defaults. | Backwards compatible; zero-cost. |
independent_mutation |
Mutate every agent independently using mutation_rate / mutation_scale. |
Best-effort diversity; collisions possible at small populations. |
unique |
Independent mutation with bounded retries until each chromosome is novel at the gene encoding precision. | Distinct chromosomes when max_retries_per_agent allows; otherwise records fallbacks > 0. |
min_distance |
Independent mutation with bounded retries until each chromosome is at least min_distance away (normalized Euclidean over evolvable genes) from every previously accepted chromosome. |
Pairwise distance lower bound when satisfiable; otherwise records fallbacks > 0. |
Strict modes (unique, min_distance) always terminate: once
max_retries_per_agent candidates have been drawn for an agent, the latest
candidate is accepted and the metrics report a fallback. Choose
mutation_scale and min_distance together to keep fallbacks low.
Telemetry
Every seeding pass returns an
InitialDiversityMetrics instance,
attached to the environment as environment.initial_diversity_metrics:
| Field | Description |
|---|---|
mode |
Seeding mode that produced the report. |
agents_processed |
Number of agents whose chromosomes were considered. |
unique_count |
Distinct chromosome signatures observed (encoding precision). |
collision_count |
Accepted chromosomes whose signature matched a prior accepted one. |
retries_used |
Total failed candidate draws across all agents. |
fallbacks |
Number of agents accepted under fallback (retries exhausted). |
min_pairwise_distance |
Smallest normalized Euclidean distance between accepted chromosomes. |
mean_pairwise_distance |
Mean normalized Euclidean distance across all accepted pairs. |
notes |
Human-readable diagnostics surfaced during seeding. |
When mode != none, run_simulation also:
- Emits a structured
initial_diversity_seededlog event carrying the same fields. - Writes
<output_dir>/initial_diversity_metadata.jsonnext to the simulation database.
The intrinsic-evolution runner additionally embeds the metrics in
intrinsic_evolution_metadata.json under the initial_diversity_metrics key
and the resolved config under initial_diversity.
Determinism
Seeding uses random.Random(seed) with seed = cfg.seed if cfg.seed is not
None else simulation_seed. Two runs with the same simulation seed (and
unchanged config) produce identical seeded chromosomes and identical metrics.
Intrinsic evolution defaults
IntrinsicEvolutionExperiment.run() sets
base_config.initial_diversity = InitialDiversityConfig(mode=independent_mutation, mutation_rate=1.0, mutation_scale=0.2, ...)
when the caller leaves mode=none. Pass an explicit InitialDiversityConfig
on base_config to opt into a stricter mode (e.g. unique) for an
intrinsic-evolution run. See
docs/research/experiments/intrinsic_evolution/intrinsic_evolution.md
for runner-specific guidance.
Pluggable diversity sources
apply_initial_diversity(environment, cfg, rng, source=...) accepts any
implementation of the InitialDiversitySource
Protocol:
class InitialDiversitySource(Protocol):
def seed(
self,
environment: Any,
cfg: InitialDiversityConfig,
rng: random.Random,
) -> InitialDiversityMetrics: ...
The default implementation is ChromosomeDiversitySource, which mutates each
agent’s hyperparameter_chromosome. Future scopes (per-agent-type
parameters, decision-module weights, spatial layouts) can ship as additional
sources without changing the orchestration contract.