Skip to content

Commit

Permalink
added benchmark enum
Browse files Browse the repository at this point in the history
  • Loading branch information
samyhaff committed Apr 19, 2024
1 parent 0bc540f commit 4dcbfe2
Show file tree
Hide file tree
Showing 13 changed files with 146 additions and 123 deletions.
59 changes: 37 additions & 22 deletions src/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,43 @@ pub enum ClassificationProblem {
Xor,
}

#[derive(Debug)]
pub enum Benchmark {
PoleBalancing,
Classification(ClassificationProblem),
}

pub trait ClassificationProblemEval {
fn get_points(&self) -> LabeledPoints;
fn evaluate(&self, alg: &Algorithm) -> f64 {
match alg {
Algorithm::Neat(neat) => {
neat.get_best_individual_fitness()
}
_ => {
let points = self.get_points();
let distances_sum = points
.iter()
.map(|(point, label)| {
let output = alg.evaluate(point);
(output - *label).abs()
})
.sum::<f64>();
(points.len() as f64 - distances_sum) / points.len() as f64
}
}
}
}

impl Benchmark {
pub fn evaluate(&self, alg: &Algorithm) -> f64 {
match self {
Benchmark::PoleBalancing => pole_balancing(alg),
Benchmark::Classification(problem) => problem.evaluate(alg),
}
}
}

fn pole_balancing(alg: &Algorithm) -> f64 {
let mut state = State::new(
0.,
Expand Down Expand Up @@ -49,28 +86,6 @@ fn pole_balancing(alg: &Algorithm) -> f64 {
count as f64 / POLE_BALANCING_STEPS as f64
}

pub trait ClassificationProblemEval {
fn get_points(&self) -> LabeledPoints;
fn evaluate(&self, alg: &Algorithm) -> f64 {
match alg {
Algorithm::Neat(neat) => {
neat.get_best_individual_fitness()
}
_ => {
let points = self.get_points();
let distances_sum = points
.iter()
.map(|(point, label)| {
let output = alg.evaluate(point);
(output - *label).abs()
})
.sum::<f64>();
(points.len() as f64 - distances_sum) / points.len() as f64
}
}
}
}

impl ClassificationProblemEval for ClassificationProblem {
fn get_points(&self) -> LabeledPoints {
match self {
Expand Down
6 changes: 3 additions & 3 deletions src/bin/bna.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ use neuroevolution::neuroevolution_algorithm::*;
use neuroevolution::constants::*;

fn main() {
let half = ClassificationProblem::SphereProblem(SphereClassificationProblem::Half(UNIT_CIRCLE_STEPS));
let quarter = ClassificationProblem::SphereProblem(SphereClassificationProblem::Quarter(UNIT_CIRCLE_STEPS));
let two_quarters = ClassificationProblem::SphereProblem(SphereClassificationProblem::TwoQuarters(UNIT_CIRCLE_STEPS));
let half = Benchmark::Classification(ClassificationProblem::SphereProblem(SphereClassificationProblem::Half(UNIT_CIRCLE_STEPS)));
let quarter = Benchmark::Classification(ClassificationProblem::SphereProblem(SphereClassificationProblem::Quarter(UNIT_CIRCLE_STEPS)));
let two_quarters = Benchmark::Classification(ClassificationProblem::SphereProblem(SphereClassificationProblem::TwoQuarters(UNIT_CIRCLE_STEPS)));

let vneuron = VNeuron::new(2);
let mut alg = Algorithm::ContinuousBNA(vneuron);
Expand Down
2 changes: 1 addition & 1 deletion src/bin/gui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ fn main() {
let vneuron = DiscreteVNeuron::new(RESOLUTION, 2);
let alg = Algorithm::DiscreteBNA(vneuron);

let quarter = ClassificationProblem::SphereProblem(SphereClassificationProblem::Quarter(UNIT_CIRCLE_STEPS));
let quarter = Benchmark::Classification(ClassificationProblem::SphereProblem(SphereClassificationProblem::Quarter(UNIT_CIRCLE_STEPS)));

let state = State::new(alg, quarter, N_ITERATIONS);

Expand Down
8 changes: 4 additions & 4 deletions src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ fn main() {
let dim = 2;

let problem = match cli.problem {
Problem::Half => ClassificationProblem::SphereProblem(SphereClassificationProblem::Half(UNIT_CIRCLE_STEPS)),
Problem::Quarter => ClassificationProblem::SphereProblem(SphereClassificationProblem::Quarter(UNIT_CIRCLE_STEPS)),
Problem::TwoQuarters => ClassificationProblem::SphereProblem(SphereClassificationProblem::TwoQuarters(UNIT_CIRCLE_STEPS)),
Problem::Xor => ClassificationProblem::Xor,
Problem::Half => Benchmark::Classification(ClassificationProblem::SphereProblem(SphereClassificationProblem::Half(UNIT_CIRCLE_STEPS))),
Problem::Quarter => Benchmark::Classification(ClassificationProblem::SphereProblem(SphereClassificationProblem::Quarter(UNIT_CIRCLE_STEPS))),
Problem::TwoQuarters => Benchmark::Classification(ClassificationProblem::SphereProblem(SphereClassificationProblem::TwoQuarters(UNIT_CIRCLE_STEPS))),
Problem::Xor => Benchmark::Classification(ClassificationProblem::Xor),
};

match cli.algorithm {
Expand Down
4 changes: 2 additions & 2 deletions src/bin/neat.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use neuroevolution::neat::*;
use neuroevolution::benchmarks::ClassificationProblem;
use neuroevolution::benchmarks::{Benchmark, ClassificationProblem};
use neuroevolution::neuroevolution_algorithm::*;

fn main() {
Expand All @@ -25,6 +25,6 @@ fn main() {
};

let mut neat = Neat::new(config);
neat.optimize(&ClassificationProblem::Xor, 1500);
neat.optimize(&Benchmark::Classification(ClassificationProblem::Xor), 1500);
println!("Fitness: {:.2}", neat.get_best_individual_fitness());
}
10 changes: 5 additions & 5 deletions src/bin/oneplusone_na.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ use neuroevolution::neuroevolution_algorithm::*;
use neuroevolution::constants::*;

fn main() {
let half = ClassificationProblem::SphereProblem(SphereClassificationProblem::Half(UNIT_CIRCLE_STEPS));
let quarter = ClassificationProblem::SphereProblem(SphereClassificationProblem::Quarter(UNIT_CIRCLE_STEPS));
let two_quarters = ClassificationProblem::SphereProblem(SphereClassificationProblem::TwoQuarters(UNIT_CIRCLE_STEPS));
let square = ClassificationProblem::SphereProblem(SphereClassificationProblem::Square);
let cube = ClassificationProblem::SphereProblem(SphereClassificationProblem::Cube);
let half = Benchmark::Classification(ClassificationProblem::SphereProblem(SphereClassificationProblem::Half(UNIT_CIRCLE_STEPS)));
let quarter = Benchmark::Classification(ClassificationProblem::SphereProblem(SphereClassificationProblem::Quarter(UNIT_CIRCLE_STEPS)));
let two_quarters = Benchmark::Classification(ClassificationProblem::SphereProblem(SphereClassificationProblem::TwoQuarters(UNIT_CIRCLE_STEPS)));
let square = Benchmark::Classification(ClassificationProblem::SphereProblem(SphereClassificationProblem::Square));
let cube = Benchmark::Classification(ClassificationProblem::SphereProblem(SphereClassificationProblem::Cube));

let network = Network::new(2, 2);
let mut alg = Algorithm::ContinuousOneplusoneNA(network);
Expand Down
7 changes: 3 additions & 4 deletions src/discrete_network.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use std::fmt;
use std::f64::consts::PI;
use rand::prelude::*;
use crate::benchmarks::ClassificationProblemEval;
use crate::utils::*;
use crate::neuroevolution_algorithm::*;
use crate::benchmarks::ClassificationProblem;
use crate::benchmarks::Benchmark;

#[derive(Debug, Clone)]
pub struct DiscreteNetwork {
Expand Down Expand Up @@ -95,7 +94,7 @@ impl DiscreteNetwork {
}

impl NeuroevolutionAlgorithm for DiscreteNetwork {
fn optimization_step(&mut self, problem: &ClassificationProblem) {
fn optimization_step(&mut self, problem: &Benchmark) {
let mut new_network = self.clone();
for i in 0..self.n_neurons {
new_network.biases[i] = DiscreteNetwork::mutate_component(self.biases[i], self.resolution + 1);
Expand All @@ -110,7 +109,7 @@ impl NeuroevolutionAlgorithm for DiscreteNetwork {
}

#[allow(unused_variables)]
fn optimize_cmaes(&mut self, problem: &ClassificationProblem) {
fn optimize_cmaes(&mut self, problem: &Benchmark) {
unimplemented!()
}

Expand Down
7 changes: 3 additions & 4 deletions src/discrete_vneuron.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use std::fmt;
use std::f64::consts::PI;
use rand::prelude::*;
use crate::benchmarks::ClassificationProblemEval;
use crate::benchmarks::Benchmark;
use crate::utils::*;
use crate::neuroevolution_algorithm::*;
use crate::benchmarks::ClassificationProblem;

#[derive(Debug, Clone)]
pub struct DiscreteVNeuron {
Expand Down Expand Up @@ -88,7 +87,7 @@ impl DiscreteVNeuron {
}

impl NeuroevolutionAlgorithm for DiscreteVNeuron {
fn optimization_step(&mut self, problem: &ClassificationProblem) {
fn optimization_step(&mut self, problem: &Benchmark) {
let mut new_vneuron = self.clone();
if random::<f64>() < 1. / (self.dim + 1) as f64 {
new_vneuron.bend = DiscreteVNeuron::mutate_component(self.bend, self.resolution);
Expand All @@ -108,7 +107,7 @@ impl NeuroevolutionAlgorithm for DiscreteVNeuron {
}

#[allow(unused_variables)]
fn optimize_cmaes(&mut self, problem: &ClassificationProblem) {
fn optimize_cmaes(&mut self, problem: &Benchmark) {
unimplemented!()
}

Expand Down
116 changes: 64 additions & 52 deletions src/gui.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
use std::f64::consts::PI;
use ggez::*;
use crate::neuroevolution_algorithm::*;
use crate::benchmarks::{ClassificationProblem, ClassificationProblemEval};
use crate::benchmarks::{Benchmark, ClassificationProblem, ClassificationProblemEval};

pub struct State {
alg: Algorithm,
problem: ClassificationProblem,
problem: Benchmark,
n_iters: u32,
iteration: u32,
}

impl State {
pub fn new(alg: Algorithm, problem: ClassificationProblem, n_iters: u32) -> Self {
pub fn new(alg: Algorithm, problem: Benchmark, n_iters: u32) -> Self {
State {
alg,
problem,
Expand Down Expand Up @@ -128,39 +128,45 @@ impl State {
}

fn get_problem_points_mesh(&self, mesh: &mut graphics::MeshBuilder) -> GameResult {
match self.problem {
ClassificationProblem::Xor => {
for (point, label) in &self.problem.get_points() {
let label = *label == 1.;
let (x, y) = (point[0], point[1]);
let point = self.cartesian_to_canvas((x, y));
mesh.rectangle(
graphics::DrawMode::fill(),
graphics::Rect::new(point.x - 5., point.y - 5., 10.0, 10.0),
if label { graphics::Color::GREEN } else { graphics::Color::RED },
)?;
}
}
_ => {
// background circle for sphere classification problems
mesh.circle(
graphics::DrawMode::stroke(2.0),
mint::Point2{x: 400.0, y: 300.0},
250.0,
0.1,
graphics::Color::BLACK,
)?;

for (point, label) in &self.problem.get_points() {
let label = *label == 1.;
let point = self.polar_to_canvas(point);
mesh.rectangle(
graphics::DrawMode::fill(),
graphics::Rect::new(point.x - 5., point.y - 5., 10.0, 10.0),
if label { graphics::Color::GREEN } else { graphics::Color::RED },
)?;
match &self.problem {
Benchmark::Classification(problem) => {
match problem {
ClassificationProblem::Xor => {
for (point, label) in problem.get_points() {
let label = label == 1.;
let (x, y) = (point[0], point[1]);
let point = self.cartesian_to_canvas((x, y));
mesh.rectangle(
graphics::DrawMode::fill(),
graphics::Rect::new(point.x - 5., point.y - 5., 10.0, 10.0),
if label { graphics::Color::GREEN } else { graphics::Color::RED },
)?;
}
}
_ => {
// background circle for sphere classification problems
mesh.circle(
graphics::DrawMode::stroke(2.0),
mint::Point2{x: 400.0, y: 300.0},
250.0,
0.1,
graphics::Color::BLACK,
)?;

for (point, label) in problem.get_points() {
let label = label == 1.;
let point = self.polar_to_canvas(&point);
mesh.rectangle(
graphics::DrawMode::fill(),
graphics::Rect::new(point.x - 5., point.y - 5., 10.0, 10.0),
if label { graphics::Color::GREEN } else { graphics::Color::RED },
)?;
}
}
}
}

Benchmark::PoleBalancing => ()
}

Ok(())
Expand Down Expand Up @@ -203,25 +209,31 @@ impl State {
self.get_bend_decision_mesh(mesh, bias, angle, 0.1, 1., bend)?;
}

// for now, draw outputs
Algorithm::Neat(neat) => {
for (point, _) in &self.problem.get_points() {
let output = neat.evaluate(point);
// gradient from red to green
let color = graphics::Color::new(
1.0 - output as f32,
output as f32,
0.0,
1.0,
);
let point = self.cartesian_to_canvas((point[0], point[1]));
mesh.circle(
graphics::DrawMode::stroke(8.0),
point,
20.0,
0.1,
color,
)?;
match &self.problem {
Benchmark::Classification(problem) => {
// for now, draw outputs
for (point, _) in problem.get_points() {
let output = neat.evaluate(&point);
// gradient from red to green
let color = graphics::Color::new(
1.0 - output as f32,
output as f32,
0.0,
1.0,
);
let point = self.cartesian_to_canvas((point[0], point[1]));
mesh.circle(
graphics::DrawMode::stroke(8.0),
point,
20.0,
0.1,
color,
)?;
}
}

Benchmark::PoleBalancing => ()
}
}

Expand Down
Loading

0 comments on commit 4dcbfe2

Please sign in to comment.