#meta #genetic #ga

genetic_algorithm_meta

A genetic algorithm implementation for optimizing genetic algorithm parameters

2 releases

0.7.2 Jul 27, 2024
0.7.1 Jul 27, 2024

#1029 in Algorithms

21 downloads per month

MIT/Apache

33KB
504 lines

genetic-algorithm-meta

This library was extracted from the crate genetic_algorithm and therefore depends on it. Version numbers are kept in-sync to indicate compatibility.

One cool thing to do with genotypes is to make a meta-genotype of all the Crossover/Mutate/Compete strategies and other Evolve parameters. This could be used to optimize the parameters of some other genetic algorithm. Yes, a simple nested for loop would also work, but where is the fun in that? But I wasn't able to find an elegant approach to creating such a heterogene setup. It was tried with Trait objects, Any and Enums, but all didn't work well:

  • Genotype wasn't allowed to become a Trait object due to it's other traits and generics.
  • Any worked, but you still need to know all possible Genotypes up front for downcasting, defeating the flexible purpose
  • Enum worked, but you still need to know all possible Genotypes up front for wrapping, defeating the flexible purpose

So, after some consideration I settled on using an nested index based Genotype MultiDiscreteGenotype<usize> indices of external vectors of arbitrary types, which should then be retrieved in the fitness function. Only one type is allowed per external vector, so the Crossover/Mutate/Compete strategies all have a Wrapper implementation forwarding to the underlying types (e.g. CompeteTournament::new(4).into())

Currently implemented as a permutation, but with caching an evolve strategy could also be used for larger search spaces.

Documentation

See docs.rs

Examples

Run with cargo run --example [EXAMPLE_BASENAME] --release

"Quick" Usage

use genetic_algorithm::fitness::placeholders::CountTrue;
use genetic_algorithm::strategy::evolve::prelude::*;
use genetic_algorithm_meta::prelude::*;

let rounds = 10;
let target_population_sizes = vec![2, 4, 8];
let max_stale_generations_options = vec![Some(10)];
let max_chromosome_age_options = vec![Some(10)];
let target_fitness_score_options = vec![Some(0)];
let mutates = vec![
    MutateOnce::new(0.05).into(),
    MutateOnce::new(0.2).into(),
    MutateOnce::new(0.4).into(),
];
let crossovers = vec![
    CrossoverClone::new(true).into(),
    CrossoverSingleGene::new(false).into(),
    CrossoverSingleGene::new(true).into(),
    CrossoverSinglePoint::new(true).into(),
    CrossoverUniform::new(true).into(),
];
let competes = vec![
    CompeteElite::new().into(),
    CompeteTournament::new(3).into(),
    CompeteTournament::new(4).into(),
];
let extensions = vec![
    ExtensionNoop::new().into(),
    ExtensionMassExtinction::new(0.9, 0.1).into(),
    ExtensionMassGenesis::new(0.9).into(),
    ExtensionMassInvasion::new(0.9, 0.1).into(),
    ExtensionMassDegeneration::new(0.9, 10).into(),
];

let genotype = BinaryGenotype::builder()
    .with_genes_size(10)
    .build()
    .unwrap();
let fitness = CountTrue;
let evolve_builder = EvolveBuilder::new()
    .with_genotype(genotype)
    .with_fitness(fitness)
    .with_fitness_ordering(FitnessOrdering::Minimize);
let evolve_fitness_to_micro_second_factor = 1_000_000;

let config = MetaConfig::builder()
    .with_evolve_builder(evolve_builder)
    .with_evolve_fitness_to_micro_second_factor(evolve_fitness_to_micro_second_factor)
    .with_rounds(rounds)
    .with_target_population_sizes(target_population_sizes)
    .with_max_stale_generations_options(max_stale_generations_options)
    .with_max_chromosome_age_options(max_chromosome_age_options)
    .with_target_fitness_score_options(target_fitness_score_options)
    .with_mutates(mutates)
    .with_crossovers(crossovers)
    .with_competes(competes)
    .with_extensions(extensions)
    .build()
    .unwrap();

let permutate = MetaPermutate::new(&config).call();
println!();
println!("{}", permutate);

// meta-permutate population_size: 270

// [...]

// meta-permutate:
//   best_target_population_size: 2
//   best_max_stale_generations: Some(10)
//   best_max_chromosome_age: Some(10)
//   best_target_fitness_score: Some(0)
//   best_mutate: Some(Once(Once { mutation_probability: 0.4 }))
//   best_crossover: Some(Clone(Clone { keep_parent: true }))
//   best_compete: Some(Elite(Elite))
//   best_extension: Some(Noop(Noop))

Tests

Run tests with cargo test

Issues

Dependencies

~3.5MB
~65K SLoC