Skip to content

Instantly share code, notes, and snippets.

@rust-play
Created September 14, 2018 17:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rust-play/f6d8a2bc29676a463608c70eb18528ec to your computer and use it in GitHub Desktop.
Save rust-play/f6d8a2bc29676a463608c70eb18528ec to your computer and use it in GitHub Desktop.
Code shared from the Rust Playground
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