use eviolite::prelude::*;
use ndarray::Array1;
use ndarray_rand::RandomExt;
use rand::distributions::Uniform;
use std::f64::consts::FRAC_PI_2;
lazy_static::lazy_static! {
static ref TEST_POINTS: Array1<f64> = Array1::range(0., FRAC_PI_2, FRAC_PI_2 / 100.);
}
#[derive(Clone)]
struct Polynomial(Array1<f64>);
impl Polynomial {
fn apply(&self, x: f64) -> f64 {
self.0[0]
+ self.0[1] * x
+ self.0[2] * x.powi(2)
+ self.0[3] * x.powi(3)
}
}
impl Solution for Polynomial {
type Fitness = f64;
fn generate() -> Self {
Polynomial(Array1::random_using(
4,
Uniform::new_inclusive(0.0, 1.0),
&mut thread_rng(),
))
}
fn evaluate(&self) -> Self::Fitness {
-TEST_POINTS.mapv(
|x| (self.apply(x) - x.sin()).abs()
).mean().unwrap()
}
fn crossover(a: &mut Self, b: &mut Self) {
crossover::one_point(&mut a.0, &mut b.0);
}
fn mutate(&mut self) {
mutation::gaussian(&mut self.0, 0.5, 0.1);
}
}
fn main() {
let evo: Evolution<Polynomial, _, _, ()> = Evolution::with_resets(
alg::MuPlusLambda::new(
1000,
1000,
0.5,
0.2,
select::Tournament::new(10),
),
hof::BestN::new(1),
25000,
);
let start = std::time::Instant::now();
let log = evo.run_until(
|gen| -gen.hall_of_fame[0].evaluate() < 0.001
);
let time = start.elapsed();
let (best, _) = log.hall_of_fame[0].clone().into_inner();
println!("found in {:.3} secs: sin(x) ≈ {:.3} + {:.3}x + {:.3}x² + {:.3}x³",
time.as_secs_f64(), best.0[0], best.0[1], best.0[2], best.0[3]
);
}