19次发布
新 0.9.0 | 2024年8月20日 |
---|---|
0.7.2 | 2024年7月27日 |
0.7.0 | 2023年5月25日 |
0.6.0 | 2022年10月14日 |
0.5.0 | 2022年7月7日 |
#131 in 算法
1,436 每月下载量
用于 genetic_algorithm_meta
265KB
5.5K SLoC
genetic-algorithm
Rust的遗传算法实现。灵感来自书籍 Genetic Algorithms in Elixir
该方法的三个主要元素
- 基因型(搜索空间)
- 适应度函数(搜索目标)
- 策略(搜索策略)
- 进化(进化策略)
- 排列(适用于小搜索空间,具有100%保证)
- 爬山法(当搜索空间是凸的,局部最优解少或交叉不可行/效率低时)
术语
- 种群:一个种群有
population_size
个个体(称为染色体)。 - 染色体:一个染色体有
genes_size
个基因 - 基因:基因是染色体中的位置和基因(等位基因)值的组合
- 等位基因:等位基因是基因的可能值
- 基因型:包含基因和等位基因,并知道如何高效地生成和变异染色体
- 适应度:知道如何确定染色体的适应度
文档
见 docs.rs
快速使用
use genetic_algorithm::strategy::evolve::prelude::*;
// the search space
let genotype = BinaryGenotype::builder() // boolean alleles
.with_genes_size(100) // 100 genes per chromosome
.build()
.unwrap();
println!("{}", genotype);
// the search goal to optimize towards (maximize or minimize)
#[derive(Clone, Debug)]
pub struct CountTrue;
impl Fitness for CountTrue {
type Allele = BinaryGenotype; // bool
fn calculate_for_chromosome(&mut self, chromosome: &Chromosome<Self::Allele>) -> Option<FitnessValue> {
Some(chromosome.genes.iter().filter(|&value| *value).count() as FitnessValue)
}
}
// the search strategy
let mut rng = rand::thread_rng(); // a randomness provider implementing Trait rand::Rng
let evolve = Evolve::builder()
.with_genotype(genotype)
.with_population_size(100) // evolve with 100 chromosomes
.with_target_fitness_score(100) // goal is 100 times true in the best chromosome
.with_fitness(CountTrue) // count the number of true values in the chromosomes
.with_crossover(CrossoverUniform::new(true)) // crossover all individual genes between 2 chromosomes for offspring
.with_mutate(MutateOnce::new(0.2)) // mutate a single gene with a 20% probability per chromosome
.with_compete(CompeteElite::new()) // sort the chromosomes by fitness to determine crossover order
.with_reporter(EvolveReporterSimple::new(100)) // optional builder step, report every 100 generations
.call(&mut rng);
.unwrap()
println!("{}", evolve);
示例
使用 cargo run --example [EXAMPLE_BASENAME] --release
- N皇后问题 https://en.wikipedia.org/wiki/Eight_queens_puzzle。
- 见 examples/evolve_nqueens
- 见 examples/hill_climb_nqueens
UniqueGenotype<u8>
使用64x64棋盘设置- 自定义
NQueensFitness
适应度
- 背包问题:https://zh.wikipedia.org/wiki/%E8%83%8C%E5%A4%B9%E9%97%AE%E9%A2%98
- 参见examples/evolve_knapsack
- 参见examples/permutate_knapsack
BinaryGenotype<Item(weight, value)>
每个基因编码背包中的存在- 自定义
KnapsackFitness(&items, weight_limit)
适应度
- 无限猴子定理:https://zh.wikipedia.org/wiki/%E6%97%A0%E9%99%90%E7%8C%AB%E5%AD%90%E5%AE%9A%E7%90%86
- 参见examples/evolve_monkeys
ListGenotype<char>
100只猴子在循环中随机输入字符- 使用汉明距离自定义适应度
- 对于小搜索空间,使用排列策略而不是进化策略,有100%的保证
- 当交叉不可行或不高效时,使用爬山策略代替进化策略
- 带有LRU缓存的自定义适应度函数
- 参见examples/evolve_binary_lru_cache_fitness
- 注意:在这种情况下对性能帮助不大...
- 自定义报告实现
测试
使用cargo test
运行测试
基准测试
使用 criterion 实现。使用 cargo bench
运行基准测试
性能分析
使用 criterion 和 pprof 实现。
在以下位置找到火焰图:./target/criterion/profile_evolve_binary/profile/flamegraph.svg
使用以下命令运行:cargo run --example profile_evolve_binary --release -- --bench --profile-time 5
待办事项
- 使持续时间统计返回 Duration,这样我们就可以之后选择 sec/milli/micro。
- 添加模拟退火策略
- 添加缩放排列?可以通过网格搜索实现,然后在新尺度内搜索最后一个网格
也许
- 添加带有和没有重复项的轮盘竞争(带有适应度排序)
- 为 UniqueGenotype 添加 OrderOne 交叉
- 为 RangeGenotype 添加 WholeArithmetic 交叉
- 添加缩放辅助函数
- 将 SteepestAscent 的 max_stale_generations 默认值设置为 1
问题
- 排列(以及可能的其他)在 gene_size 0 时崩溃。也许它应该只返回一个空染色体?
依赖项
~4MB
~70K SLoC