Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
96fbcf8
First commit
A-lamo May 14, 2026
cf20922
Some examples work now.
A-lamo May 14, 2026
4ed7e5d
Migration started.
A-lamo May 18, 2026
8554ef1
Removing redundant examples.
A-lamo May 18, 2026
895ac58
Fix video and remove redundant examples.
A-lamo May 18, 2026
01bbd63
Remove wiki from global
A-lamo May 18, 2026
80469e3
Blueprint updates.
A-lamo May 21, 2026
5143840
Integrated EA for drones.
A-lamo May 21, 2026
23267de
Add blueprint_to_urdf stub.
itokeiic May 24, 2026
8a0f1de
Derive arm and motor physical params from blueprint nodes.
itokeiic May 24, 2026
3a7c1a3
Implement blueprint_to_urdf for rigid-drone Isaac Lab path.
itokeiic May 24, 2026
1c1fc1b
Add Blueprint → URDF → USD pipeline scripts.
itokeiic May 25, 2026
c2823e1
Add example 16: blueprint_to_urdf demo with cross-section dispatch.
itokeiic May 25, 2026
b6b8845
Record Phase 3 progress and end-of-session state.
itokeiic May 25, 2026
7f678f3
Make ariel importable on Python 3.11.
itokeiic May 26, 2026
784ca13
Record unified-env achievement on python-311-compat.
itokeiic May 26, 2026
fb6c94e
Expand §6 entry 15 with the EA-inner-loop motivation.
itokeiic May 26, 2026
57592d4
Add pluggable simulator backend Protocol + tutorial.
itokeiic May 26, 2026
47a1af7
Phase 2: Isaac Lab backend env constructs and runs end-to-end.
itokeiic May 27, 2026
53d5fb0
Phase 2.5: dependency-ownership split + lazy imports + parts/ pkg.
itokeiic May 27, 2026
7dfaea4
Phase 2.5 polish: vendor Isaac Lab env spec + add binary guardrail.
itokeiic May 27, 2026
2613bef
Tutorial README: add §3 Environment setup with conda recipe.
itokeiic May 27, 2026
4b68081
Phase 2.5 wrap-up: lazy __init__.py + recipe fixes + execution log.
itokeiic May 27, 2026
1041e18
Phase 2.5 complete: re-enable rl_games PPO training in train.py.
itokeiic May 27, 2026
64c4d1c
Tutorial: add EA-loop guide + subprocess evolve.py reference
itokeiic May 27, 2026
2f55573
docs: update pluggable simulator README
itokeiic May 28, 2026
2f1ae7b
docs: fix make_blueprint_usd sketch to use keyword args
itokeiic May 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions .claude/wiki/NEAT_Algorithm.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
---
type: algorithm_reference
tags: [neat, neuroevolution, cppn, ga, algorithm]
source: https://gwern.net/doc/reinforcement-learning/exploration/2002-stanley.pdf
date_ingested: 2026-05-14
---

# NEAT_Algorithm

NEAT (NeuroEvolution of Augmenting Topologies) simultaneously evolves the weights *and* topology of neural networks using a genetic algorithm with historical gene markings, speciation, and incremental complexification. It is the algorithm underlying ARIEL's CPPN genome evolution (`src/ariel/body_phenotypes/robogen_lite/cppn_neat/`).

## Formulation

### Genome encoding

Two gene lists per individual:

```
Node gene: node_id | type ∈ {input, hidden, output}

Connection: in_node | out_node | weight | enabled | innovation_number
```

`enabled=False` silences a connection without removing it (used after add-node mutations).

### Innovation numbers (historical markings)

Every structural mutation receives a globally unique, permanent **innovation number** from a shared counter. If the same structural event occurs in two individuals within one generation, both receive the **same** number.

Innovation numbers align heterogeneous topologies for crossover without needing explicit topology normalization.

### Crossover (align by innovation number)

```
For each innovation ID in union(parent_A, parent_B):
matching gene → inherit randomly from A or B
disjoint gene → inherit from fitter parent
excess gene → inherit from fitter parent
(equal fitness → inherit from both, randomly)
```

### Structural mutations

| Mutation | Action | New innovation IDs |
|---|---|---|
| Add connection | New enabled edge between two unconnected nodes | 1 |
| Add node | Disable existing edge; insert hidden node; add two new edges (weight=1 in, original weight out) | 2 |

### Complexification from minimal topology

All genomes start with direct input→output connections only (no hidden nodes). Hidden structure grows exclusively via add-node mutation.

## Parameters

| Name | Default | Role |
|---|---|---|
| `node_add_rate` | 0.2 (ARIEL) | Probability of add-node mutation per call |
| `conn_add_rate` | 0.3 (ARIEL) | Probability of add-connection mutation per call |
| `c1`, `c2`, `c3` | problem-dependent | Coefficients for [[neat_speciation]] compatibility distance |
| `δ_t` | problem-dependent | Speciation compatibility threshold |

## Implementation Notes

- **Feed-forward ordering**: use Kahn's topological sort (BFS with in-degree tracking). Raise on cycle detection. See `get_node_ordering()` in [[cppn_neat_genome]].
- **Recurrent fallback**: if a cycle is detected, fall back to iterative relaxation for `len(nodes) + 1` steps.
- **Cache activation topology**: `incoming_map`, topological order, and input/output ID lists should be cached per genome and invalidated only on structural mutation or connection disable.
- **Innovation ID collisions in parallel runs**: the shared counter assumes single-threaded access; parallelism requires a lock or per-island counters.
- **Fitness in crossover**: the fitter-parent weighting requires that `genome.fitness` is synced from the EA individual's fitness before calling `crossover()`.

## When to Use

- When network topology is unknown and should be discovered by evolution rather than fixed by design.
- When starting from a small, fast-to-evaluate network and growing complexity incrementally is preferable to searching a large fixed topology space.
- When meaningful crossover between heterogeneous topologies is required — NEAT's innovation numbers solve the [[competing_conventions]] problem that defeats position-based crossover.

Prefer fixed-topology neuroevolution (e.g., CMA-ES on weight vectors) when: topology is well-understood, population is large enough to make speciation overhead costly, or strict inference-time constraints make variable graph size problematic.

## See Also

- [[neat_speciation]] — speciation mechanics, compatibility distance formula, fitness sharing
- [[competing_conventions]] — the problem NEAT's historical markings solve
- [[cppn_neat_genome]] — ARIEL implementation of this algorithm
- [[CMA-ES_Algorithm]] — alternative optimizer for fixed-topology neuroevolution
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
type: source_summary
tags: [source, neat, neuroevolution, cppn, algorithm]
source: https://gwern.net/doc/reinforcement-learning/exploration/2002-stanley.pdf
author: Stanley, K.O. & Miikkulainen, R.
date_ingested: 2026-05-14
---

# Source - Evolving Neural Networks through Augmenting Topologies

Foundational 2002 paper introducing NEAT — the algorithm used by ARIEL's CPPN genome evolution. Covers genome encoding with innovation numbers, speciation, fitness sharing, and incremental complexification from minimal topologies.

## Entity Pages Created

- [[NEAT_Algorithm]] — full algorithm reference: genome encoding, crossover by innovation number, structural mutations, complexification strategy, implementation notes for ARIEL
- [[neat_speciation]] — concept page: compatibility distance formula, fitness sharing, niche pressure, note that ARIEL's current CPPN loop does not implement speciation
- [[competing_conventions]] — concept page: why position-based crossover fails for variable-topology networks, and how innovation numbers resolve it
37 changes: 37 additions & 0 deletions .claude/wiki/competing_conventions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
type: concept_reference
tags: [neat, neuroevolution, ga, concept, algorithm]
source: https://gwern.net/doc/reinforcement-learning/exploration/2002-stanley.pdf
date_ingested: 2026-05-14
---

# competing_conventions

The competing conventions problem occurs when crossover is applied to two genomes that encode the same function via *different* network topologies or node orderings. Recombining them produces offspring with contradictory or disrupted weight assignments, making crossover harmful rather than beneficial.

## Theory

In a fixed-topology network, position-based crossover works because node i in parent A corresponds to node i in parent B. When topology evolves, two networks may use the same nodes in different roles — there is no consistent positional correspondence. Crossing them at the weight level mixes incompatible representations.

Example: parent A uses node 3 as a hidden feature detector; parent B uses node 3 as a pass-through. Their offspring inherits node 3's weights from both parents, destroying both parents' solutions.

This is structurally analogous to the permutation invariance problem in neural network weight space.

## In Ariel

[[NEAT_Algorithm]] resolves this via **innovation numbers**: each structural gene (connection or node) carries a globally unique ID assigned at creation time. Crossover aligns genes by innovation number rather than by position, so matching genes always correspond to the same historical structural event.

Two genes with the same innovation number represent the same structural addition (same edge between the same two conceptual roles), regardless of what other mutations have occurred in each lineage. Genes with no matching partner (disjoint/excess) are inherited from the fitter parent, avoiding destructive mixing from non-corresponding genes.

This is implemented in `Genome.crossover()` at `src/ariel/body_phenotypes/robogen_lite/cppn_neat/genome.py`.

## Practical Notes

- Competing conventions are only a problem when crossover is used *and* topology is variable. If you only mutate (no crossover), the problem does not arise.
- Even with innovation numbers, crossover between very dissimilar topologies (large δ) tends to produce unfit offspring. [[neat_speciation]] addresses this by restricting crossover to individuals within the same species.
- Alternative: abandon crossover entirely for topology-evolving systems and rely on mutation only. Faster per-generation but slower to combine building blocks across lineages.

## See Also

- [[NEAT_Algorithm]] — how innovation numbers resolve this problem
- [[neat_speciation]] — species restrict crossover to genetically similar individuals, reducing competing-convention disruption
5 changes: 5 additions & 0 deletions .claude/wiki/log.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## [2026-05-14] Ingest | Evolving Neural Networks through Augmenting Topologies
- Files created: NEAT_Algorithm.md, neat_speciation.md, competing_conventions.md, Source - Evolving Neural Networks through Augmenting Topologies.md
- Files updated: (none)
- Model: Claude (subscription)

## [2026-04-13] Ingest | MuJoCo Model Editing
- Files created: mujoco_model_editing_c_api.md, mjsBody.md, mjsGeom.md, mjsJoint.md, mjsActuator.md, mjsSensor.md, mujoco_mjspec_enums.md, Source - MuJoCo Model Editing.md
- Files updated: MjSpec.md
Expand Down
69 changes: 69 additions & 0 deletions .claude/wiki/neat_speciation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
type: concept_reference
tags: [neat, neuroevolution, ga, algorithm, concept]
source: https://gwern.net/doc/reinforcement-learning/exploration/2002-stanley.pdf
date_ingested: 2026-05-14
---

# neat_speciation

Speciation in NEAT groups individuals into species by genetic similarity so that new structural mutations are protected from elimination before their weights can be optimized. Each species competes only internally; the global population is partitioned into niches.

## Theory

### Compatibility distance

Two genomes `i` and `j` are assigned to the same species if their compatibility distance δ < δ_t:

```
δ = (c1 * E / N) + (c2 * D / N) + (c3 * W̄)

E = number of excess genes (beyond the range of the shorter genome)
D = number of disjoint genes (gaps within the shared range)
N = number of genes in the larger genome (size normalization)
W̄ = mean weight difference of matching genes
c1, c2, c3 = importance coefficients (problem-dependent)
```

For small genomes (N < 20) the paper recommends N = 1 (no normalization).

### Fitness sharing (niche pressure)

Each individual's fitness is divided by the number of species-mates to prevent any one species from dominating offspring allocation:

```
f'_i = f_i / Σ_j sh(δ(i, j))

sh(δ) = 1 if δ < δ_t
sh(δ) = 0 otherwise
```

Species are allocated offspring in proportion to their **total adjusted fitness** (sum of `f'_i` within the species).

### Representative-based assignment

Each species keeps one **representative** genome (typically the previous generation's champion). New genomes are assigned to the first species whose representative is within δ_t; if none match, a new species is created.

## In Ariel

ARIEL's current CPPN evolution (`src/ariel/body_phenotypes/robogen_lite/cppn_neat/`, `examples/c_genotypes/5_body_evolution_cppn.py`) does **not** implement speciation. The `CPPNEvolution` class uses a flat tournament-style parent selection (top 50% by fitness) with no niche protection.

This means new structural mutations in ARIEL are not shielded from selection pressure — a known limitation. Adding speciation would require:
1. A compatibility distance function over `Genome` objects.
2. A species registry with representatives.
3. Per-species offspring quotas in `reproduction()`.

See [[NEAT_Algorithm]] for the crossover mechanics that speciation coordinates with.

## Practical Notes

- δ_t typically requires hand-tuning: too low → too many micro-species (slows convergence), too high → no protection for innovations.
- c1 = c2 = 1.0, c3 = 0.4 is a common starting point from the original paper; W̄ carries less signal than topology differences.
- Species with stagnating max fitness for N generations are typically culled (not part of the original paper formulation but standard in practice).
- Fitness sharing reduces effective selection pressure — compensate by raising raw population size or number of generations.

## See Also

- [[NEAT_Algorithm]] — full algorithm including crossover and mutation operators
- [[competing_conventions]] — the problem speciation + historical markings jointly solve
- [[cppn_neat_genome]] — ARIEL genome class where speciation would be added
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ eggs/
lib/
lib64/
parts/
# Don't let the buildout-style `parts/` rule above silently swallow
# source-tree `parts/` packages (e.g.
# src/ariel/body_phenotypes/drone/phenotype_assembly/parts/).
!src/**/parts/
# rl_games auto-creates ./runs/<experiment>/nn/ when training launches
# from the repo root (tutorials/pluggable_simulator/train.py --mode train).
runs/
sdist/
var/
wheels/
Expand Down
Loading