#[macro_use]
extern crate clap;
use clap::{App, Arg};
extern crate rand;
use rand::thread_rng;
extern crate petri;
use petri::algo::{Simple, EvolutionaryAlgorithm};
use petri::ops::select::Tournament;
use petri::ops::crossover::TwoPoint;
use petri::ops::mutate::FlipBit;
use std::process;
type Genome = Vec<Chromosome>;
type Chromosome = bool;
type Fitness = u32;
fn fitness_fn(g: &Genome) -> Fitness
{
g.iter().filter(|x| **x).count() as u32
}
fn main()
{
let matches = App::new("onemax")
.arg(
Arg::with_name("generations")
.long("generations")
.short("g")
.takes_value(true)
.help("Number of generations")
.default_value("100"),
)
.arg(
Arg::with_name("population")
.long("population")
.short("p")
.takes_value(true)
.help("Number of individuals in the population")
.default_value("100"),
)
.arg(
Arg::with_name("bits")
.long("bits")
.short("b")
.takes_value(true)
.help("Number of bits in each genome")
.default_value("65"),
)
.arg(
Arg::with_name("tournament-size")
.long("tournament-size")
.short("t")
.takes_value(true)
.help("Number of individuals in each round of tournament")
.default_value("5"),
)
.arg(
Arg::with_name("crossover-pb")
.long("crossover-pb")
.takes_value(true)
.help("Probability individuals in the population will mate")
.default_value("0.05"),
)
.arg(
Arg::with_name("mutate-pb")
.long("mutate-pb")
.takes_value(true)
.help("Probability individuals will mutate")
.default_value("0.02"),
)
.arg(
Arg::with_name("flip-pb")
.long("flip-pb")
.takes_value(true)
.help("Probability a chromsome will be flipped during mutation")
.default_value("0.02"),
)
.get_matches();
let n_generations = value_t!(matches, "generations", usize)
.unwrap_or_else(|_| {
eprintln!("Failed to parse argument: generations");
process::exit(1);
});
let n_population =
value_t!(matches, "population", usize).unwrap_or_else(|_| {
eprintln!("Failed to parse argument: population");
process::exit(1);
});
let n_bits = value_t!(matches, "bits", usize).unwrap_or_else(|_| {
eprintln!("Failed to parse argument: bits");
process::exit(1);
});
let tourn_size = value_t!(matches, "tournament-size", usize)
.unwrap_or_else(|_| {
eprintln!("Failed to parse argument: tourn-size");
process::exit(1);
});
let mut_pb = value_t!(matches, "mutate-pb", f32).unwrap_or_else(|_| {
eprintln!("Failed to parse argument: mutate-pb");
process::exit(1);
});
let cx_pb = value_t!(matches, "crossover-pb", f32).unwrap_or_else(|_| {
eprintln!("Failed to parse argument: crossover-pb");
process::exit(1);
});
let flip_pb = value_t!(matches, "flip-pb", f32).unwrap_or_else(|_| {
eprintln!("Failed to parse argument: flip-pb");
process::exit(1);
});
let rng = thread_rng();
let init_fn = {
move || vec![false; n_bits]
};
let mut ea = Simple::new(
Tournament::with_size(tourn_size), TwoPoint::default(), FlipBit::with_pb(flip_pb), fitness_fn, mut_pb,
cx_pb,
n_generations,
rng,
);
ea.initialize(n_population, init_fn);
while !ea.is_done()
{
let _ = ea.next();
}
let final_pop = ea.population();
let max = final_pop
.into_iter()
.map(|x| (fitness_fn(&x), x))
.max_by(|a, b| a.0.cmp(&b.0))
.unwrap();
let as_bit_str = max.1
.iter()
.map(|x| if *x { "1" } else { "0" })
.collect::<String>();
println!("BEST GENOME");
println!("Genome: [{}]", as_bit_str);
println!("Number of Ones -- Fitness: {:?}", max.0);
println!("Max Fitness: {}", n_bits);
}