Skip to main content

linear-gp

Active

A production-grade Rust framework for Linear Genetic Programming research, featuring modular architecture, Q-Learning integration, automated hyperparameter optimization, and support for reinforcement learning and classification tasks.

Rust 3Updated Apr 20, 2026
evolutionary-algorithmsgenetic-algorithmgenetic-programminglinear-genetic-programmingmachine-learningoptimizationparallel-computingreinforcement-learningrustshowcase

linear-gp

A Rust framework for solving reinforcement learning and classification tasks using Linear Genetic Programming (LGP).

Download · Report Bug · Experiments

CI   License

Showcase

lgp list
Available Experiments
lgp run
Running an Experiment

Iris Classification — Operator Comparison

Comparison of four experiments (population 100, 200 generations, seed 42), each isolating a different genetic operator.

Fitness over generations for all four Iris experiments

Final best accuracy by experiment

ExperimentOperatorsFinal AccuracyDescription
iris_baselineNone33.3%Pure elitism — population converges to a single individual
iris_mutationMutation66.7%Random instruction perturbation explores nearby program space
iris_crossoverCrossover97.3%Two-point crossover recombines instruction sequences from fit parents
iris_fullBoth90.7%Full GP with mutation + crossover

Crossover dominates on this problem: recombining proven instruction subsequences is more effective than random perturbation. The shaded regions show the spread between worst and best fitness in each generation.

How It Works
┌─────────────────────────────────────────────────────────┐
│                    LGP Execution Model                  │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  Input Features          Registers (r0..r3)             │
│  ┌──────────────┐        ┌─────┬─────┬─────┬─────┐     │
│  │ sepal_length │        │ r0  │ r1  │ r2  │ r3  │     │
│  │ sepal_width  │───────▶│Set. │Ver. │Vir. │Scr. │     │
│  │ petal_length │        └──┬──┴──┬──┴──┬──┴──┬──┘     │
│  │ petal_width  │           │     │     │     │         │
│  └──────────────┘           ▼     ▼     ▼     ▼         │
│                          ┌─────────────────────┐        │
│                          │  Execute N instrs   │        │
│                          │  r[s] = r[s] op x   │        │
│                          └─────────┬───────────┘        │
│                                    │                    │
│                                    ▼                    │
│                          ┌─────────────────────┐        │
│                          │  argmax(r0, r1, r2) │        │
│                          │  → predicted class   │        │
│                          └─────────────────────┘        │
│                                                         │
│  Instruction Modes:                                     │
│    Internal: r[src] = r[src] op r[tgt]                  │
│    External: r[src] = r[src] op (factor × input[tgt])   │
│                                                         │
└─────────────────────────────────────────────────────────┘

Each individual is a sequence of register-machine instructions. Programs operate on 4 registers (r0-r2 map to Iris classes, r3 is scratch). After execution, the class with the highest action register value is the prediction. Programs are evolved through elitist selection, crossover, and mutation over generations.

Regenerate showcase
# Terminal GIFs (requires teasr: cargo install teasr-cli)
teasr showme

# Plotters charts (run all four experiments first)
lgp run iris_baseline --override hyperparameters.seed=42
lgp run iris_mutation --override hyperparameters.seed=42
lgp run iris_crossover --override hyperparameters.seed=42
lgp run iris_full --override hyperparameters.seed=42
cargo run -p lgp --example generate_showcase --features plot

Contents

Overview

Linear Genetic Programming (LGP) is a variant of genetic programming that evolves sequences of instructions operating on registers, similar to machine code. This framework provides:

  • Modular architecture - Trait-based design for easy extension to new problem domains
  • Multiple problem types - Built-in support for OpenAI Gym environments and classification tasks
  • Q-Learning integration - Hybrid LGP + Q-Learning for enhanced reinforcement learning
  • Hyperparameter search - Built-in random search with parallel evaluation
  • Parallel evaluation - Rayon-powered parallel fitness evaluation
  • Experiment automation - Full pipeline: search, run, and analyze from a single CLI
  • Optional plotting - PNG chart generation via plotters (behind --features plot)

Supported Environments

EnvironmentTypeInputsActionsDescription
CartPoleRL42Balance a pole on a moving cart
MountainCarRL23Drive a car up a steep mountain
IrisClassification43Classify iris flower species

Install

Prebuilt binary (recommended):

curl -fsSL https://raw.githubusercontent.com/urmzd/linear-gp/main/install.sh | sh

You can pin a version or change the install directory:

LGP_VERSION=v1.0.0 LGP_INSTALL_DIR=~/.local/bin \
  curl -fsSL https://raw.githubusercontent.com/urmzd/linear-gp/main/install.sh | sh

From source:

git clone https://github.com/urmzd/linear-gp.git && cd linear-gp
cargo install --path crates/lgp-cli

Quick Start

# List available experiments
lgp list

# Run CartPole with pure LGP
lgp run cart_pole_lgp

# Run Iris classification
lgp run iris_baseline

Examples

Run the standalone Rust examples directly with cargo:

cargo run -p lgp-core --example cart_pole --features gym
cargo run -p lgp-core --example iris_classification

CLI Reference

# Run experiment with default config
lgp run iris_baseline

# Run with optimal config (after search)
lgp run iris_baseline --config optimal

# Run with parameter overrides
lgp run iris_baseline --override hyperparameters.program.max_instructions=50

# Q-learning parameter overrides
lgp run cart_pole_with_q --override operations.q_learning.alpha=0.5

# Preview config (dry-run)
lgp run iris_baseline --dry-run

# Search hyperparameters
lgp search iris_baseline
lgp search iris_baseline --n-trials 20 --n-threads 8

# Analyze results (generates CSV tables + optional PNG plots)
lgp analyze
lgp analyze --input outputs --output outputs

# Run full experiment pipeline (search -> run -> analyze)
lgp experiment iris_baseline
lgp experiment iris_baseline --iterations 20
lgp experiment --skip-search

Available Experiments

ExperimentDescriptionMedian run
iris_baselineIris baseline (no mutation, no crossover)0.21s
iris_mutationIris with mutation only0.37s
iris_crossoverIris with crossover only1.19s
iris_fullIris full (mutation + crossover)0.43s
cart_pole_lgpCartPole with pure LGP0.15s
cart_pole_with_qCartPole with Q-Learning0.16s
mountain_car_lgpMountainCar with pure LGP2.06s
mountain_car_with_qMountainCar with Q-Learning2.23s

Performance

Wall-clock times for lgp run <experiment> --override hyperparameters.seed=42 with the bundled default configs, built with cargo build --release. Fitness evaluation is parallelized across the population via rayon, so numbers scale with core count.

Hardware: Apple M4 Pro (12 cores), 24 GB RAM, macOS. Samples: n=100 per experiment.

Experimentminmedianmeanp95max
iris_baseline0.15s0.21s0.21s0.24s0.25s
iris_mutation0.10s0.37s0.34s0.48s0.57s
iris_crossover0.20s1.19s1.28s2.51s3.56s
iris_full0.13s0.43s0.41s0.66s0.84s
cart_pole_lgp0.14s0.15s0.16s0.16s0.49s
cart_pole_with_q0.16s0.16s0.16s0.17s0.18s
mountain_car_lgp1.54s2.06s2.20s2.92s4.54s
mountain_car_with_q1.69s2.23s2.40s3.30s4.78s

Running all 8 experiments sequentially takes ≈ 7s at the medians. iris_crossover has the widest spread — recombining variable-length programs produces runs with meaningfully more instructions to execute. MountainCar dominates wall-clock time because episodes run the full 200-step default, while CartPole episodes terminate early when the pole falls.

The framework includes built-in hyperparameter search with parallel evaluation via rayon.

# Search for a specific config
lgp search cart_pole_lgp

# Search all configs (LGP first, then Q-Learning)
lgp search

# Search with custom options
lgp search cart_pole_with_q --n-trials 100 --n-threads 8 --median-trials 15

Parameters Searched

ParameterRange
max_instructions1-100
external_factor0.0-100.0
alpha (Q-Learning)0.0-1.0
gamma (Q-Learning)0.0-1.0
epsilon (Q-Learning)0.0-1.0
alpha_decay (Q-Learning)0.0-1.0
epsilon_decay (Q-Learning)0.0-1.0

Results are saved to:

  • outputs/parameters/<config>.json
  • configs/<config>/optimal.toml

Visualizations

# Analyze results (generates CSV tables)
lgp analyze

# Build with plot feature for PNG chart generation
cargo install --path crates/lgp-cli --features plot
lgp analyze

Output Structure

outputs/
├── parameters/                 # Optimized hyperparameters (JSON)
│   ├── cart_pole_lgp.json
│   └── ...
├── <experiment>/               # Experiment outputs (timestamped runs)
│   └── <timestamp>/
│       ├── config/
│       │   └── config.toml     # Resolved config with seed/timestamp
│       ├── outputs/
│       │   ├── best.json       # Best individual from final generation
│       │   ├── median.json     # Median individual
│       │   ├── worst.json      # Worst individual
│       │   ├── population.json # Full population history
│       │   └── params.json     # Hyperparameters used
│       └── post_process/       # Post-processing outputs
├── tables/                     # Generated CSV statistics
│   └── <experiment>.csv
└── figures/                    # Generated PNG plots (with --features plot)
    └── <experiment>.png

Logging

# Default (info level, pretty format)
lgp run iris_baseline

# Verbose mode (debug level)
lgp -v run iris_baseline

# JSON format for log aggregation
lgp --log-format json run iris_baseline

# Fine-grained control via RUST_LOG
RUST_LOG=lgp=debug lgp run iris_baseline
RUST_LOG=lgp::core=trace,lgp=info lgp run iris_baseline
LevelUse Case
errorFatal issues only
warnPotential problems
infoProgress updates (default)
debugDetailed diagnostics
traceInstruction-by-instruction execution

Packages

PackageDescription
lgp-coreCore library — traits, evolutionary engine, built-in problems
lgpCLI binary for running experiments, search, and analysis

Extending the Framework

The framework is built around these key traits:

  • State - Represents an environment state with value access and action execution
  • RlState - Extends State for RL environments with terminal state detection
  • Core - Main trait defining the genetic algorithm components
  • Fitness - Evaluates individual performance on states
  • Breed - Two-point crossover for creating offspring
  • Mutate - Mutation operators for genetic variation

You can add new classification problems, RL environments, genetic operators, and fitness functions. See skills/lgp-experiment/SKILL.md for the complete guide.

Thesis & References

The accompanying thesis, Reinforced Linear Genetic Programming, and full references are maintained in a separate repository.

Agent Skill

This repo’s conventions are available as portable agent skills in skills/.

License

Apache-2.0