Radiate is a powerful Rust library designed for implementing genetic algorithms and artificial evolution techniques. It provides a flexible framework for creating, evolving, and optimizing solutions to complex problems using principles inspired by natural selection and genetics. This library is suitable for researchers, developers, and enthusiasts interested in evolutionary computation and optimization.
Large insperation for this library coming from other genetic algorithm libraries: Jenetics: A Java implementatino of GAs. genevo: Popular rust GA. radiate_legacy: Previous implemenation of this library with direct encoding.
Add to cargo.toml
[dependencies]
radiate = "1.2.2"
- Genetic Algorithms: Implement standard genetic algorithm operations such as selection, crossover, and mutation.
- Selectors:
- Boltzmann
- Elitism
- Rank
- Roulette
- Tournament
- Crossovers:
- Singlepoint
- Multipoint
- Uniform
- Mean (average between two numerical genes)
- Mutations:
- Mutator (random gene replacement)
- Swap
- Numeric
- Selectors:
- Customizable Codexes: Define how individuals are represented.
- Each
Genotype
can be thought of as a matrix ofGenes
. Each row being aChromosoome
. This means the decoding of aGenotype
reults in aVec<Vec<T>>
. For example, aGenotype
ofFloatGene
decodes toVec<Vec<f32>>
- Each
- Parallel Processing: The
GeneticEngine
has a thread pool it pushes work to when applicable. Simply define the number of desired threads. - Flexible Fitness Functions: Easily define and integrate custom fitness functions to evaluate individuals. Each evaluation of the fitness function if evalued in a thread pool.
The implemenation of the GeneticEngine
results in an extremely extensible and dynamic architecture. Mix and match any of these features together or add new features and algorithms with minimal effort. Check radiate-extensions for extensions to the core library.
Evolve a string of characters to match the target (Chicago, IL)
use radiate::*;
fn main() {
let target = "Chicago, IL";
let codex = CharCodex::new(1, target.len());
let engine = GeneticEngine::from_codex(&codex)
.offspring_selector(RouletteSelector::new())
.survivor_selector(TournamentSelector::new(3))
.alterer(vec![
Alterer::Mutator(0.01),
Alterer::UniformCrossover(0.5)
])
.fitness_fn(|genotype: String| {
Score::from_usize(genotype.chars().zip(target.chars()).fold(
0,
|acc, (geno, targ)| {
if geno == targ {
acc + 1
} else {
acc
}
},
))
})
.build();
let result = engine.run(|output| {
println!("[ {:?} ]: {:?}", output.index, output.best);
output.score().as_usize() == target.len()
});
println!("{:?}", result);
}
TODO - write out the general GA workflow provided by the library.
- Multi-objective optimization (pareto fronts)
- I have a plan and mental model of how to integrate this into the library - fundementals are already there. Will start when I have time probably within the next month or two (Dec 2024/Jan 2025)
- Genetic Programming through tree data structures?
- Graphs are already implemented and working well so in theory trees (expression trees) should be a (somewhat) light lift.
The radiate-examples directory contains several examples demonstrating the capabilities of the library, including:
- Min-Sum: An example of minimizing a sum of integers.
- N-Queens: A classic problem in which the goal is to place N queens on a chessboard such that no two queens threaten each other.
- Knapsack: Another classic problem for evolutionary algorithms.
- Regression Graph: Evolve a
Graph<f32>
(essentially a graph based neural network) for regression analysis. - Simple Memory Graph: Evolve a
Graph<f32>
(Neural Network) using recurrent connections for Neural Network based memory. - XOR Graph: Evolve a
Graph<f32>
to solve the classic XOR problem.