Release Notes
v1.3.2 - py 0.0.16
- 2026-09-27
- Release
A multi-objective quality release. Three operator bugs were fixed: polynomial mutation, simulated binary crossover, and NSGA-II crowding distance. Together with better-tuned examples and a documented recommended configuration, they take radiate from clearly trailing pymoo and DEAP on multi-objective hypervolume (DTLZ2 0.30 vs ~0.70) to on par with them: within ~0.01 of the best library on ZDT1, ZDT3, and DTLZ2, ahead of pymoo on both ZDT problems, while running roughly 7–35× faster. A new exact hypervolume indicator lets you measure front quality directly, and a new benchmarks page compares radiate against DEAP and pymoo across single- and multi-objective problems.
Changed
- Python: plotting moved from Matplotlib to Plotly. The
plotextra now installsplotlyinstead ofmatplotlib(uv add "radiate[plot]"), andMetricCollector.plot(...)renders an interactive Plotly figure. All Python examples and docs snippets were converted as well. Geneno longer requiresClone. The bound moved down toNumericGene, and the GP graph types (GraphNode,GraphChromosome,GraphMutator) no longer requirePartialEqon their value type. Generic code that relied onG: GeneimplyingCloneneeds an explicitG: Gene + Clonebound.BitFlipMutatoris implemented forBitChromosomeonly (breaking). It was implemented for anyContiguousChromosomewithGene = BitGene. A custom chromosome holdingBitGenes no longer getsBitFlipMutatorand needs its ownMutateimpl. The rate is documented as per bit: a chromosome ofnbits seesn * rateflips per generation on average.- Multi-objective examples and docs use a tuned NSGA-II/III configuration, and a new recommended configuration section explains it:
- Parent selection: tournament NSGA-II.
- Survivor selection: NSGA-II for 2 objectives, NSGA-III for 3 or more.
- Offspring fraction:
0.5. - Crossover: SBX, distribution index 20.
- Mutation: polynomial, distribution index 20.
The ZDT3 example's hypervolume goes from ~0.85 to ~1.32.
- random_provider::sample_indices only generates the indices it returns instead of shuffling the whole range, so sampling a few points from a long range is much cheaper (2 points from 1,000 indices: ~2,250 ns → ~33 ns). This speeds up MultiPointCrossover on long chromosomes.
- PMXCrossover is much faster. It now builds each child in place by swapping genes, using position lookup tables. This is O(n) instead of the previous quadratic search, and it doesn't clone genes. Each crossover is roughly 7× faster at 20 genes, 23× at 100, and 260× at 2,000. The output is unchanged (still standard PMX), and seeded runs produce the same results as before.
- Seeded runs produce different results than before. The new sampling in bernoulli_indices and sample_indices draws random numbers in a different order, so a given seed now gives a different (but statistically equivalent) run for operators that use them.
Added
- Hypervolume indicator.
pareto::hypervolume(scores, reference, objective)andFront::hypervolume(&reference)compute the exact hypervolume of a set of scores or of the Pareto front against a reference point. They handle any mix of minimized/maximized objectives and any number of objectives: anO(n log n)sweep for 2,O(n²)slicing for 3, and recursive slicing for 4+. random_provider::bernoulli_indices(p, input, f)callsffor each index ininput(a lengthnfor0..n, or aRange<usize>) selected independently with probabilityp, the same as a per-indexbool(p)check, but at lowpit jumps straight to the next selected index, so the cost scales with the number of selections rather than the range length.BitFlipMutatorandBlendCrossovernow use it. Rates<= 0orNaNselect nothing and rates>= 1select everything, instead of panicking.pareto::front_crowding_distanceandpareto::fronts_from_ranksare now public, so you can compute per-front crowding distance and group indices by Pareto rank directly.- Benchmarks page in the docs comparing
radiateagainst DEAP and pymoo on continuous, combinatorial, and multi-objective problems.
Fixed
PolynomialMutatorreturned values anchored at the lower bound instead of the current value. It computedmin + q·(max − min)instead of Deb'sx + δq·(max − min), so mutated genes landed near a bound or near the reflection of their current value. Higheretamade it worse, not more local. On DTLZ problems, where the optimum sits mid-range, this collapsed hypervolume (DTLZ1 went to 0). It now matches the reference NSGA-II / pymoo operator, with tests for locality, bounds, centering, andetabehavior.SimulatedBinaryCrossoverproduced the wrong children. The child was centered on half the parents' difference instead of their midpoint, and only the first parent was updated. It now writes both children symmetrically around the parents' midpoint, per the standard SBX definition.MultiPointCrossovercould lose a cut point. Cut points were sampled from0..length, and a cut at index 0 swaps nothing, so a 2-point crossover sometimes behaved as a 1-point one. Cut points are now sampled from1..length.- NSGA-II crowding distance is now computed per Pareto front instead of across the whole population. This affects
NSGA2SelectorandTournamentNSGA2Selector. Before, a truncated front could lose its own boundary points because they weren't extreme relative to other fronts.
For example and details please refer to the user guide and API docs.
v1.3.1 - py 0.0.15
- 2026-09-13
- Release
Rate is fully replaced by the expression DSL, events/checkpointing/stopping move onto the engine builder, and the Python operator API is reorganized into namespaces (Select.*/Cross.*/Mutate.*/Dist.*/Limit.*/Filter.*/Fitness.*). Also new: a population-filter stage for stagnation recovery, adaptive species-count targeting, a BitFlipMutator, f64 support for GP graphs/trees, and three new TUI dashboard tabs. Pareto front calculation's should be much faster now; buffers are cached & reused whenever possible, efficent sorting, and in-place crowding distance calculation.
Breaking
Rateis replaced byfloator Expr. (impl Into<Expr>is now used for conversion - minimal friction expected.) Every crossover/mutator now takes a plainfloatorExprinstead of aRate. Python:rd.Rateis deleted. This was implemented in order to support full dynamic rates for anything inradiate's ecosystem.- Events rewritten as typed pub/sub. Implement
Handler<E>for one event type (EpochComplete,Improvement,EngineStart/Stop,LimitTriggered,Warning,CheckpointSaved, ...) and register withGeneticEngine::subscribe::<E>(handler). Python: newrd.on_limit_triggered/on_log/on_checkpoint_saveddecorators;event.index/event.event_typeare now attributes, not methods. - Checkpointing moved onto the builder. Use
GeneticEngineBuilder::checkpoint(interval, path)instead ofrun()-time checkpointing. Python:Engine.write_checkpoint(path, interval, file_type="pkl")replacesrun(checkpoint=...). Checkpoint pickle format also changed — checkpoints written by 1.3.0 may not load. - Metric-predicate stopping removed — no more
Limit::Metric/Limit.metric(...). UseLimit::Expr/Limit.expr(...)instead. Expressions read directly from theMetricSetso this is functionally equivalent. - Custom
Chromosome/Geneimplementors need updates. Trait methods were re-split (bounds vs. init range, contiguous-storage methods moved to a newContiguousChromosomesub-trait). No impact if you only use the built-in gene types.
Changed
- GP ops/regression are generic over
f32/f64now. Calls likeOp::sigmoid()may needOp::<f32>::sigmoid()if the type can't be inferred. PythonGraphCodec/TreeCodecnow take adtypeparam. - Python: operators collapsed into namespaces.
TournamentSelector(k=3)→Select.tournament(k=3),BlendCrossover(...)→Cross.blend(...),UniformMutator(...)→Mutate.uniform(...),HammingDistance()→Dist.hamming(),ScoreLimit(...)→Limit.score(...). Old class names are no longer exported. - Python:
Engine.alters(...)renamedEngine.alter(...). - Python:
Engine.run()no longer takeslimits=See limits (set limits on the builder) andstep_next()is gone — iterate the engine directly (for epoch in engine:). - Python:
EngineConfig.max_species_agedefault changed 20 → 25 to match Rust. - Python: install extras regrouped.
[polars]/[pandas]/[numpy]/[matplotlib]→[data](numpy+pandas+polars) and[plot](matplotlib);[all]unchanged. - Metric names renamed see default metrics. Consistency across the engine and
radiate-gp(e.g.age.replace→replace.age,count.species→species.count). Seedocs/source/engine/metrics.mdfor the full mapping. - Python: free-threaded wheels now actually target 3.14t — CI had been building against 3.13t. This is out of
radiate's control and is a result of underlying maturin/pyo3 support.
Added
- Population filter pipeline stage — new
UniqueScoreFilterdetects score-diversity collapse and replaces duplicates.GeneticEngineBuilder::filter(...)/ Pythonrd.Filter.unique_score(...)+Engine.filter(...). - Adaptive species-count targeting — see target species. Set
target_species_countto drive the speciation threshold toward a target instead of a fixed value. Python:Engine.diversity(dist, threshold, target=...). BitFlipMutatorfor bit-string genomes. Python:Mutate.bit_flip(rate=0.1).HealthMonitorevent handler — auto-emitsWarningevents for stagnation, diversity collapse, and species collapse.- f64 support end-to-end for GP graphs/trees, plus new ops:
Op.weight2/sign/reciprocal/gaussian/tooth. - NumPy-native fitness & regression I/O — custom Python fitness functions can return numpy arrays directly; regression accepts numpy arrays or lists.
GraphMutator::target_size(size)— anti-bloat throttling once a graph reaches a target size.- Python:
Graph/Treepickle support (to_pickle/from_pickle) and anunchecked=Truefast path on.eval()that skips shape validation.Graph.eval/Tree.evalnow also accept numpy arrays directly. - Python:
Expr.select(...)methods —.mean()/.stddev()/.min()/.max()/.sum()/.slope()/etc., plusExpr.alias(name). - TUI: three new dashboard tabs — "Improvements", "Front" (Pareto-front tracking), and "Events", plus a richer status bar and better table navigation keys.
- New examples — Bevy-based
flappy-bird(Rust), CPPN image evolutiongraph_art.py(Python).
Fixed
GraphMutatorcould pick duplicate source-node indices for multi-arity ops — now deduplicated.- Fixed a few panics from misaligned indices in graph/tree crossover.
AnyValue's numeric →Durationcast now treats the sourcef32as seconds, not milliseconds — durations reported via metrics were previously 1000x off.- LARGE BUG WITH CROSSOVER PARENT SELECTION — previously, the engine could over select the same individual multiple times as a parent during crossover, leading to unexpected behavior and reduced genetic diversity. This has now been fixed to ensure a more even distribution of parent selection.
For example and details please refer to the user guide and API docs.
v1.3.0 - py 0.0.14
- 2026-06-20
- Release
Radiate has reached 1.3.0! This release includes a major refactor of the engine's iteration model, a new expression DSL pass and operators, a substantial NSGA III simplification and optimization, a NEAT implementation refactor, and various other improvements and cleanups across the codebase. The engine is now much more efficient, and the new expression DSL features should make it easier to implement complex adaptive behaviors without custom code. The user guide has been rebuilt around testable snippets, and a new guide on diversity and speciation has been added.
Check the changelog for a full list of changes.
v1.2.22 - py 0.0.13
- 2026-04-25
- Release
Breaking changes:
- Changed the checkpointing feature in python to use
.pklas a default extension instead of.json. It fits better within the python ecosystem. - Changed the metric names to use
.as a separator instead of_. This allows for better organization and grouping of metrics. For example,scores.bestinstead ofbest_scores.
Other
Speed improvements centered around engine steps.
Additions
Added a new crate radiate-expr which includes expressions (think polars) to extend the metric and rating systems. This greatly improves the flexibility of dynamic rates (mutation/crossover/species thresholds) and allows users to define their own rating systems. Along with the rate improvements, this extends into the engine itself by allowing users to define their own metrics and use them in the aforementioned dynamic rates - or simply just to track the engine.
Refactored radiate-ui to give much more insight into the engine and the metrics it produces. Included a new search bar and species panel to quickly find and visualize specific species and their members.
In python, radiate now supports optional features (check the user guide installation section for specific info). This lets users opt in to specific integrations within the python ecosystem (e.g. pandas, polars, matplotlib, torch, numpy) without needing to install a bunch of dependencies they may not need.
For checkpointing, new traits were added: CheckpointWriter & CheckpointReader to let users define their own ways of saving checkpoints.
v1.2.21 - py 0.0.11
- 2026-02-22
- Release
Breaking changes:
Changed the FloatGene<T> to take a generic f32 or f64 value.
- The above is a breaking change. Just add the generic type to your
FloatGene,FloatChromosome, orFloatCodecif needed.
Massive expansion of python's api - check the docs for usage. We moved towards a builder pattern for the engine and added better type hinting.
v1.2.20 - py 0.0.10
- 2025-12-15
- Release
Adding radiate-ui crate, bug fixes, & speed improvements.
I split up some functionality into a new crate radiate-utils and have added a new feature radiate-ui for a tui user interface through ratitui. Some small bug fixes, code simplifications, and some nice little speed improvements.
v1.2.19 - py 0.0.9
- 2025-11-11
- Release
Adding support for experimental PGM or Probabilistic graphical models through the GP feature (crate).
Note
PGM support was experimental and has since been removed; it is no longer part of Radiate.
Major cleanup or unused code and massive graph performance improvements through the use of smallvec as connections instead of BTreeSets.
Improving eventing system through cleaner code and removing redundant events.
Introducing radiate-error (RadiateError) into the core crates ad requiring its usage in certain traits (Problem mainly). We also use this error type in py-radiate and allow it to bubble up into python's type system too.
Brining metrics to the forefront in python.
v1.2.18 - py 0.0.8
- 2025-09-27
- Release
Fixing subtle bug in recurrent graphs where a random seed wasn't being respected, leading to non-deterministic behavior in some cases. This fix ensures that all random operations within recurrent graphs are consistent and reproducible when a seed is provided.
Added three new types of graphs:
- LSTM (Long Short-Term Memory) Graphs: These are a type of recurrent neural network (RNN) that can learn long-term dependencies.
- GRU (Gated Recurrent Unit) Graphs: Similar to LSTMs, GRUs are a type of RNN that are simpler and often more efficient.
- Mesh Graphs: Graphs structured in a mesh topology.
v1.2.17 - py 0.0.7
- 2025-09-04
- Release
In response to github issue #23.
Ensuring that FloatGenes/IntGene
Also adding new mutator: JitterMutator for FloatGenes. This mutator adds a small random value (jitter) to each gene, controlled by a magnitude parameter.
v1.2.16
- 2025-08-19
- Release
In response to github issue #22.
Adding support for batch fitness functions and batch engine problems through a new trait (BatchFitnessFn). Some small cleanup on other fitness functions and some chromosome operators.
v1.2.15 - py 0.0.6
- 2025-08-10
- Release
Adding Novelty Search to python and refactoring engine building across the rust/python bridge. Improving python's speed. Adding type checking to python and upgrading python package to >= python 3.12 to support new python generics. Improving docs to reference new functionality.
New alters:
- EdgeRecombinationCrossover for PermutationGenes
- PolynomialMutator for chromosomes with FloatGenes
Added code path in alters for dynamic mutation/crossover rates. This is in early dev, but an be seen in PolynomialMutator.
v1.2.14 - py 0.0.4
- 2025-07-05
- Release
Added support for novelty search, fitness-based novelty, and combined novelty and fitness search. Improved documentation and examples. Improved traits for Engine and introduced one for FitnessFn. Bug fixes for pareto fronts and engine iterators.