Created
September 14, 2018 17:36
-
-
Save rust-play/f6d8a2bc29676a463608c70eb18528ec to your computer and use it in GitHub Desktop.
Code shared from the Rust Playground
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extern crate rand; // 0.5.5 | |
use rand::{distributions::Uniform, Rng}; | |
#[derive(Debug, Clone)] | |
struct Individual { | |
score: Option<usize>, | |
value: String, | |
} | |
impl Individual { | |
fn evaluate(&mut self, target: &str) { | |
let score = self | |
.value | |
.chars() | |
.zip(target.chars()) | |
.filter(|(a, b)| a == b) | |
.count(); | |
self.score = Some(score); | |
} | |
fn crossover(&self, other: &Individual) -> Individual { | |
let mut rng = rand::thread_rng(); | |
let mut value = String::new(); | |
// uniform crossover | |
for (a, b) in self.value.chars().zip(other.value.chars()) { | |
value.push(if rng.gen_bool(0.5) { a } else { b }); | |
} | |
Individual { score: None, value } | |
} | |
fn mutate(&self) -> Individual { | |
let mut rng = rand::thread_rng(); | |
let mut value = self.value.chars().collect::<Vec<_>>(); | |
*rng.choose_mut(&mut value).unwrap() = rng.sample(&Uniform::<u8>::new(0x20, 0x7f)).into(); | |
let value = value.into_iter().collect(); | |
Individual { score: None, value } | |
} | |
} | |
#[derive(Debug, Clone)] | |
struct Population { | |
individuals: Vec<Individual>, | |
} | |
impl Population { | |
fn gen(count: usize, len: usize) -> Population { | |
let mut rng = rand::thread_rng(); | |
Population { | |
individuals: (0..count) | |
.map(|_| Individual { | |
score: None, | |
value: rng | |
.sample_iter(&Uniform::<u8>::new(0x20, 0x7f)) | |
.take(len) | |
.map(Into::<char>::into) | |
.collect(), | |
}).collect(), | |
} | |
} | |
fn evaluate(&mut self, target: &str) { | |
self.individuals.iter_mut().for_each(|i| i.evaluate(target)) | |
} | |
fn select(&self, tournament_size: usize) -> &Individual { | |
let mut rng = rand::thread_rng(); | |
// tournament selection | |
rand::seq::sample_slice_ref(&mut rng, &self.individuals, tournament_size) | |
.into_iter() | |
.max_by_key(|i| i.score) | |
.unwrap() | |
} | |
} | |
fn main() { | |
let tournament_size = 10; | |
let mutation_rate = 0.01; | |
let crossover_rate = 0.9; | |
let population_count = 10000; | |
let target = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."; | |
let mut rng = rand::thread_rng(); | |
let mut population = Population::gen(population_count, target.len()); | |
let mut nextgen; | |
for i in 0.. { | |
population.evaluate(target); | |
{ | |
let best = &population | |
.individuals | |
.iter() | |
.max_by_key(|i| i.score) | |
.unwrap(); | |
println!("{:4}\t{}\t{}", i, best.score.unwrap(), best.value); | |
if best.value == target { | |
break; | |
} | |
} | |
nextgen = Population { | |
individuals: Vec::new(), | |
}; | |
while nextgen.individuals.len() < population.individuals.len() { | |
let p = rng.gen::<f64>(); | |
nextgen.individuals.push(if p < mutation_rate { | |
population.select(tournament_size).mutate() | |
} else if p < crossover_rate { | |
population | |
.select(tournament_size) | |
.crossover(population.select(tournament_size)) | |
} else { | |
population.select(tournament_size).clone() | |
}); | |
} | |
population = nextgen; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment