Adding implementation to binary

This commit is contained in:
vandomej 2021-10-06 00:54:51 -07:00
parent e5188ec02f
commit 2fdf4c2545
5 changed files with 44 additions and 39 deletions

View file

@ -3,7 +3,7 @@ version: "0.1"
autor: Jacob VanDomelen <jacob.vandome15@gmail.com> autor: Jacob VanDomelen <jacob.vandome15@gmail.com>
about: Uses a genetic algorithm to generate a machine learning algorithm. about: Uses a genetic algorithm to generate a machine learning algorithm.
args: args:
- DIRECTORY: - FILE:
help: Sets the input/output directory for the program. help: Sets the input/output file for the program.
required: true required: true
index: 1 index: 1

View file

@ -5,27 +5,27 @@ extern crate gemla;
mod test_state; mod test_state;
use clap::App; use clap::App;
use std::fs::metadata; use gemla::bracket::Gemla;
use std::path::PathBuf;
use test_state::TestState;
/// Runs a simluation of a genetic algorithm against a dataset. /// Runs a simluation of a genetic algorithm against a dataset.
/// ///
/// Use the -h, --h, or --help flag to see usage syntax. /// Use the -h, --h, or --help flag to see usage syntax.
/// TODO /// TODO
fn main() { fn main() -> anyhow::Result<()> {
// Command line arguments are parsed with the clap crate. And this program uses // Command line arguments are parsed with the clap crate. And this program uses
// the yaml method with clap. // the yaml method with clap.
let yaml = load_yaml!("../../cli.yml"); let yaml = load_yaml!("../../cli.yml");
let matches = App::from_yaml(yaml).get_matches(); let matches = App::from_yaml(yaml).get_matches();
// Checking that the first argument <DIRECTORY> is a valid directory // Checking that the first argument <DIRECTORY> is a valid directory
let directory = matches.value_of(gemla::constants::args::DIRECTORY).unwrap(); let file_path = matches.value_of(gemla::constants::args::FILE).unwrap();
let metadata = metadata(directory); let mut gemla = Gemla::<TestState>::new(&PathBuf::from(file_path), true)?;
match &metadata {
Ok(m) if m.is_dir() => { gemla.simulate(1)?;
println!("{} is a valid directory!", directory); gemla.simulate(1)?;
println!("Building tree for {}.", directory); gemla.simulate(1)?;
}
Ok(_) => println!("{} is not a valid directory!", directory), Ok(())
_ => println!("{} does not exist!", directory),
}
} }

View file

@ -1,39 +1,50 @@
use gemla::bracket::genetic_node::GeneticNode; use gemla::bracket::genetic_node::GeneticNode;
use gemla::error; use gemla::error;
use rand::prelude::*; use rand::prelude::*;
use rand::rngs::ThreadRng; use rand::{random, thread_rng};
use serde::{Deserialize, Serialize};
use std::convert::TryInto; use std::convert::TryInto;
const POPULATION_SIZE: u64 = 5; const POPULATION_SIZE: u64 = 5;
const POPULATION_REDUCTION_SIZE: u64 = 3; const POPULATION_REDUCTION_SIZE: u64 = 3;
struct TestState { #[derive(Serialize, Deserialize, Debug)]
pub struct TestState {
pub population: Vec<f64>, pub population: Vec<f64>,
thread_rng: ThreadRng, }
impl Default for TestState {
fn default() -> Self {
let mut population: Vec<f64> = vec![];
for _ in 0..POPULATION_SIZE {
population.push(random::<u64>() as f64)
}
TestState { population }
}
} }
impl GeneticNode for TestState { impl GeneticNode for TestState {
fn initialize() -> Result<Box<Self>, error::Error> { fn initialize() -> Result<Box<Self>, error::Error> {
let mut thread_rng = thread_rng();
let mut population: Vec<f64> = vec![]; let mut population: Vec<f64> = vec![];
for _ in 0..POPULATION_SIZE { for _ in 0..POPULATION_SIZE {
population.push(thread_rng.gen::<u64>() as f64) population.push(random::<u64>() as f64)
} }
Ok(Box::new(TestState { Ok(Box::new(TestState { population }))
population,
thread_rng,
}))
} }
fn simulate(&mut self, iterations: u64) -> Result<(), error::Error> { fn simulate(&mut self, iterations: u64) -> Result<(), error::Error> {
let mut rng = thread_rng();
for _ in 0..iterations { for _ in 0..iterations {
self.population = self self.population = self
.population .population
.clone() .clone()
.iter() .iter()
.map(|p| p + self.thread_rng.gen_range(-10.0..10.0)) .map(|p| p + rng.gen_range(-10.0..10.0))
.collect() .collect()
} }
@ -52,26 +63,27 @@ impl GeneticNode for TestState {
} }
fn mutate(&mut self) -> Result<(), error::Error> { fn mutate(&mut self) -> Result<(), error::Error> {
let mut rng = thread_rng();
loop { loop {
if self.population.len() >= POPULATION_SIZE.try_into().unwrap() { if self.population.len() >= POPULATION_SIZE.try_into().unwrap() {
break; break;
} }
let new_individual_index = self.thread_rng.gen_range(0..self.population.len()); let new_individual_index = rng.gen_range(0..self.population.len());
let mut cross_breed_index = self.thread_rng.gen_range(0..self.population.len()); let mut cross_breed_index = rng.gen_range(0..self.population.len());
loop { loop {
if new_individual_index != cross_breed_index { if new_individual_index != cross_breed_index {
break; break;
} }
cross_breed_index = self.thread_rng.gen_range(0..self.population.len()); cross_breed_index = rng.gen_range(0..self.population.len());
} }
let mut new_individual = self.population.clone()[new_individual_index]; let mut new_individual = self.population.clone()[new_individual_index];
let cross_breed = self.population.clone()[cross_breed_index]; let cross_breed = self.population.clone()[cross_breed_index];
new_individual += cross_breed + self.thread_rng.gen_range(-10.0..10.0); new_individual += cross_breed + rng.gen_range(-10.0..10.0);
self.population.push(new_individual); self.population.push(new_individual);
} }
@ -88,10 +100,7 @@ impl GeneticNode for TestState {
v = v[..(POPULATION_REDUCTION_SIZE as usize)].to_vec(); v = v[..(POPULATION_REDUCTION_SIZE as usize)].to_vec();
let mut result = TestState { let mut result = TestState { population: v };
population: v,
thread_rng: thread_rng(),
};
result.mutate()?; result.mutate()?;
@ -114,7 +123,6 @@ mod tests {
#[test] #[test]
fn test_simulate() { fn test_simulate() {
let mut state = TestState { let mut state = TestState {
thread_rng: thread_rng(),
population: vec![1.0, 1.0, 2.0, 3.0], population: vec![1.0, 1.0, 2.0, 3.0],
}; };
@ -139,7 +147,6 @@ mod tests {
#[test] #[test]
fn test_calculate_scores_and_trim() { fn test_calculate_scores_and_trim() {
let mut state = TestState { let mut state = TestState {
thread_rng: thread_rng(),
population: vec![4.0, 1.0, 1.0, 3.0, 2.0], population: vec![4.0, 1.0, 1.0, 3.0, 2.0],
}; };
@ -154,7 +161,6 @@ mod tests {
#[test] #[test]
fn test_mutate() { fn test_mutate() {
let mut state = TestState { let mut state = TestState {
thread_rng: thread_rng(),
population: vec![4.0, 3.0, 3.0], population: vec![4.0, 3.0, 3.0],
}; };
@ -166,12 +172,10 @@ mod tests {
#[test] #[test]
fn test_merge() { fn test_merge() {
let state1 = TestState { let state1 = TestState {
thread_rng: thread_rng(),
population: vec![1.0, 2.0, 4.0, 5.0], population: vec![1.0, 2.0, 4.0, 5.0],
}; };
let state2 = TestState { let state2 = TestState {
thread_rng: thread_rng(),
population: vec![0.0, 1.0, 3.0, 7.0], population: vec![0.0, 1.0, 3.0, 7.0],
}; };

View file

@ -1,2 +1,2 @@
/// Corresponds to the DIRECTORY command line argument used in accordance with the clap crate. /// Corresponds to the FILE command line argument used in accordance with the clap crate.
pub const DIRECTORY: &str = "DIRECTORY"; pub const FILE: &str = "FILE";

1
gemla/temp Normal file

File diff suppressed because one or more lines are too long