Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
pkalivas committed Feb 8, 2025
2 parents 97ea665 + b17b404 commit e4ea061
Show file tree
Hide file tree
Showing 15 changed files with 46 additions and 46 deletions.
Binary file added docs/assets/Genetic_Program_Tree.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/graph_gp.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 7 additions & 7 deletions docs/codex.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,14 +224,14 @@ ___
Genotype {
chromosomes: (0..self.num_chromosomes)
.map(|_| {
FloatChromosome::from_genes(
(0..self.num_genes)
FloatChromosome {
genes: (0..self.num_genes)
.map(|_| {
FloatGene::new(self.min, self.max)
.with_bounds(self.lower_bound, self.upper_bound)
})
.collect::<Vec<FloatGene>>(),
)
}
})
.collect::<Vec<FloatChromosome>>(),
}
Expand Down Expand Up @@ -307,11 +307,11 @@ ___
// The resulting codex type will be FnCodex<IntChromosome<i8>, Vec<i8>>.
let codex = FnCodex::new()
.with_encoder(|| {
Genotype::from_chromosomes(vec![IntChromosome::from_genes(
(0..N_QUEENS)
Genotype::from_chromosomes(vec![IntChromosome {
genes: (0..N_QUEENS)
.map(|_| IntGene::from_min_max(0, N_QUEENS as i8))
.collect(),
)])
}])
})
.with_decoder(|genotype| {
genotype.chromosomes[0]
Expand Down Expand Up @@ -350,7 +350,7 @@ ___
impl Codex<IntChromosome<i32>, NQueens> for NQueensCodex {
fn encode(&self) -> Genotype<IntChromosome<i32>> {
let genes = (0..self.size).map(|_| IntGene::from_min_max(0, self.size)).collect();
let chromosomes = vec![IntChromosome::from_genes(genes)];
let chromosomes = vec![IntChromosome { genes }];
Genotype::from_chromosomes(chromosomes)
}

Expand Down
17 changes: 7 additions & 10 deletions docs/gp.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@

# Extensions
# Genetic Programming

The radiate-gp provides genetic programming capabilities.
The `radiate-gp` crate provides the fundamental building blocks for [Genetic Programming](https://en.wikipedia.org/wiki/Genetic_programming) (GP). Mainly, it provides data structures and algorithms to build and evolve `Tree`s and `Graph`s. Traditionally, GP is a method of evolving 'programs' to solve problems. The idea is to represent a program as a `Tree` or a `Graph` and evolve it to solve a specific problem. These problems are typically some sort of regression problems, but can be used to solve any problem that can be represented as a `Tree` or a `Graph`. It can be easier to think of these as evolving Expression Trees/Random Forests/Decision Trees or Neural Networks.

The crate is not yet documented to the extent it should be, but you can refer to the [examples](https://github.com/pkalivas/radiate/tree/master/radiate-examples) for now.
!!! warning

## Nodes
As of 2/8/2024:

The `Node` is the `Gene` of both the `Graph` and the `Tree`. It `Allele` is an
enum, `Ops<T>`, that provides a number of different ways to represent the node's.
This crate is still being finalized and is not yet documented to the extent it should be. If you are interested in using it, please refer to the [examples](https://github.com/pkalivas/radiate/tree/master/examples) for now - they are current. The documentation will be added as functionality is finalized.

!!! note

This needs a lot more documentation.
Just for reassurance, this crate is pretty much done and ready for production use, I'm just not totally happy with a few very small details. This is just a personal preference and I want to make sure I'm happy with the general flow of the code before I fully document it (this stuff takes a lot of time to write).

## Graphs

Graphs are a powerful way to represent problems. They are used in many fields, such as neural networks, and can be used to solve complex problems. Radiate offers an extremely unique way to build any graph architecture you can think of though the
Graphs are a powerful way to represent problems. They are used in many fields, such as Neural Networks, and can be used to solve complex problems. Radiate offers an extremely unique way to build any graph architecture you can think of though the
`Architect<'a, C, T>` and integrate it seemlessly with the `GeneticEngine`.

The `Architect` is a builder pattern that allows you to layer, attach, and build any graph architecture you can think of. Currently it has pre-built functionality for building `Graph`s:
Expand Down
2 changes: 1 addition & 1 deletion examples/trees/regression-tree/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ fn main() {
(NodeType::Leaf, vec![Op::var(0)]),
];

let graph_codex = TreeCodex::single(3, store).constraint(|node| node.size() < 30);
let graph_codex = TreeCodex::single(3, store).constraint(|root| root.size() < 30);

let regression = Regression::new(get_dataset(), Loss::MSE);

Expand Down
2 changes: 1 addition & 1 deletion radiate-gp/src/collections/trees/chromosome.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{NodeStore, TreeNode};
use radiate::{Chromosome, Valid};
use std::sync::Arc;

type Constraint<N> = Arc<Box<dyn Fn(&N) -> bool>>;
type Constraint<N> = Arc<dyn Fn(&N) -> bool>;

#[derive(Clone, Default)]
pub struct TreeChromosome<T> {
Expand Down
14 changes: 7 additions & 7 deletions radiate-gp/src/collections/trees/codex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub struct TreeCodex<T: Clone> {
depth: usize,
num_trees: usize,
store: Option<NodeStore<T>>,
constraint: Option<Arc<Box<dyn Fn(&TreeNode<T>) -> bool>>>,
constraint: Option<Arc<dyn Fn(&TreeNode<T>) -> bool>>,
}

impl<T: Clone + Default> TreeCodex<T> {
Expand All @@ -33,7 +33,7 @@ impl<T: Clone + Default> TreeCodex<T> {
where
F: Fn(&TreeNode<T>) -> bool + 'static,
{
self.constraint = Some(Arc::new(Box::new(constraint)));
self.constraint = Some(Arc::new(constraint));
self
}
}
Expand All @@ -50,11 +50,11 @@ where
.map(|tree| TreeChromosome::new(tree, Some(store.clone()), self.constraint.clone()))
.collect::<Vec<TreeChromosome<T>>>();

for chromosome in &new_chromosomes {
if let Some(constraint) = &self.constraint {
for tree in chromosome.iter() {
if !constraint(tree) {
panic!("Root node does not meet constraint.");
if let Some(constraint) = &self.constraint {
for chromosome in &new_chromosomes {
for node in chromosome.iter() {
if !constraint(node) {
panic!("TreeCodex.encode() - Root node does not meet constraint.");
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions radiate/src/engines/alterers/invert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ impl InversionMutator {
/// Create a new instance of the `InversionMutator` with the given rate.
/// The rate must be between 0.0 and 1.0.
pub fn new(rate: f32) -> Self {
if rate < 0.0 || rate > 1.0 {
panic!("rate must be between 0.0 and 1.0");
}

InversionMutator { rate }
}
}
Expand Down
4 changes: 2 additions & 2 deletions radiate/src/engines/codexes/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ use crate::{Chromosome, Codex, Genotype};
/// });
///
/// // encode and decode
/// let genotype = codex.encode(); // Genotype<IntChromosome<i8>>
/// let decoded = codex.decode(&genotype); // Vec<i8>
/// let genotype: Genotype<IntChromosome<i8>> = codex.encode();
/// let decoded: Vec<i8> = codex.decode(&genotype);
/// }
/// ```
/// # Type Parameters
Expand Down
13 changes: 4 additions & 9 deletions radiate/src/engines/problem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,12 @@ pub trait Problem<C: Chromosome, T>: Send + Sync {
pub(crate) struct EngineProblem<C, T>
where
C: Chromosome,
T: Clone,
{
pub codex: Arc<dyn Codex<C, T>>,
pub fitness_fn: Arc<dyn Fn(T) -> Score + Send + Sync>,
}

unsafe impl<C: Chromosome, T: Clone> Send for EngineProblem<C, T> {}
unsafe impl<C: Chromosome, T: Clone> Sync for EngineProblem<C, T> {}

impl<C, T> Problem<C, T> for EngineProblem<C, T>
where
C: Chromosome,
T: Clone,
{
impl<C: Chromosome, T> Problem<C, T> for EngineProblem<C, T> {
fn encode(&self) -> Genotype<C> {
self.codex.encode()
}
Expand All @@ -37,3 +29,6 @@ where
(self.fitness_fn)(phenotype)
}
}

unsafe impl<C: Chromosome, T> Send for EngineProblem<C, T> {}
unsafe impl<C: Chromosome, T> Sync for EngineProblem<C, T> {}
3 changes: 2 additions & 1 deletion radiate/src/engines/selectors/linear_rank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ impl<C: Chromosome> Select<C> for LinearRankSelector {
) -> Population<C> {
let mut fitness_values = population
.iter()
.map(|individual| individual.score().unwrap().as_f32())
.filter_map(|individual| individual.score())
.map(|score| score.as_f32())
.collect::<Vec<f32>>();

let total_rank: f32 = (1..=fitness_values.len()).map(|i| i as f32).sum();
Expand Down
7 changes: 4 additions & 3 deletions radiate/src/engines/selectors/nsga2.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::objectives::{pareto, Objective};
use crate::{Chromosome, EngineCompoment, Population, Select};
use crate::{Chromosome, EngineCompoment, Population, Score, Select};

/// NSGA2 Selector. Selects individuals based on the NSGA2 algorithm.
/// This algorithm ranks individuals based on their dominance relationships
Expand Down Expand Up @@ -33,8 +33,9 @@ impl<C: Chromosome> Select<C> for NSGA2Selector {
) -> Population<C> {
let scores = population
.iter()
.map(|individual| individual.score().unwrap().clone())
.collect::<Vec<_>>();
.filter_map(|individual| individual.score())
.map(|score| score.clone())
.collect::<Vec<Score>>();

let ranks = pareto::rank(population, objective);
let distances = pareto::crowding_distance(&scores, objective);
Expand Down
3 changes: 2 additions & 1 deletion radiate/src/engines/selectors/roulette.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ impl<C: Chromosome> Select<C> for RouletteSelector {
let mut fitness_values = Vec::with_capacity(population.len());
let scores = population
.iter()
.map(|individual| individual.score().as_ref().unwrap().as_f32())
.filter_map(|individual| individual.score())
.map(|score| score.as_f32())
.collect::<Vec<f32>>();

// scale the fitness values so that they sum to 1
Expand Down
2 changes: 1 addition & 1 deletion radiate/src/engines/selectors/steady_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ impl EngineCompoment for SteadyStateSelector {
impl<C: Chromosome> Select<C> for SteadyStateSelector {
fn select(&self, population: &Population<C>, _: &Objective, count: usize) -> Population<C> {
let mut selected_population = population.clone();
let slice = population.iter().as_slice();
let slice = population.as_ref();

for _ in 0..self.replacement_count {
let new_individual = random_provider::choose(slice).clone();
Expand Down
7 changes: 4 additions & 3 deletions radiate/src/engines/selectors/stochastic_sampling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ impl<C: Chromosome> Select<C> for StochasticUniversalSamplingSelector {
) -> Population<C> {
let mut fitness_values = Vec::with_capacity(population.len());

let total_fitness: f32 = population
let total_fitness = population
.iter()
.map(|ind| ind.score().as_ref().unwrap().as_f32())
.sum();
.filter_map(|ind| ind.score())
.map(|score| score.as_f32())
.sum::<f32>();

for individual in population.iter() {
let score = individual.score().as_ref().unwrap().as_f32();
Expand Down

0 comments on commit e4ea061

Please sign in to comment.