Cleaned up use statements

This commit is contained in:
vandomej 2021-11-07 11:21:46 -08:00
parent 95c65fa4b1
commit 265f554d08
5 changed files with 53 additions and 59 deletions

View file

@ -5,12 +5,14 @@ pub mod error;
use anyhow::{anyhow, Context}; use anyhow::{anyhow, Context};
use error::Error; use error::Error;
use log::info; use log::info;
use serde::de::DeserializeOwned; use serde::{de::DeserializeOwned, Serialize};
use serde::Serialize; use std::{
use std::fs::{copy, remove_file, File}; fs::{copy, remove_file, File},
use std::io::ErrorKind; io::{ErrorKind, Write},
use std::io::Write; path::{Path, PathBuf},
use std::path::{Path, PathBuf}; thread,
thread::JoinHandle,
};
/// A wrapper around an object `T` that ties the object to a physical file /// A wrapper around an object `T` that ties the object to a physical file
#[derive(Debug)] #[derive(Debug)]
@ -21,7 +23,7 @@ where
val: T, val: T,
path: PathBuf, path: PathBuf,
temp_file_path: PathBuf, temp_file_path: PathBuf,
file_thread: Option<std::thread::JoinHandle<()>>, file_thread: Option<JoinHandle<()>>,
} }
impl<T> Drop for FileLinked<T> impl<T> Drop for FileLinked<T>
@ -145,12 +147,14 @@ where
.with_context(|| "Unable to serialize object into bincode".to_string())?; .with_context(|| "Unable to serialize object into bincode".to_string())?;
if let Some(file_thread) = self.file_thread.take() { if let Some(file_thread) = self.file_thread.take() {
file_thread.join().expect("Error cleaning up file thread for file_linked object"); file_thread
.join()
.expect("Error cleaning up file thread for file_linked object");
} }
match File::open(&self.path) { match File::open(&self.path) {
Ok(_) => { Ok(_) => {
let handle = std::thread::spawn(move || { let handle = thread::spawn(move || {
copy(&thread_path, &thread_temp_path).expect("Unable to copy temp file"); copy(&thread_path, &thread_temp_path).expect("Unable to copy temp file");
let mut file = File::create(&thread_path).expect("Error creating file handle"); let mut file = File::create(&thread_path).expect("Error creating file handle");
@ -164,7 +168,7 @@ where
self.file_thread = Some(handle); self.file_thread = Some(handle);
} }
Err(error) if error.kind() == ErrorKind::NotFound => { Err(error) if error.kind() == ErrorKind::NotFound => {
let handle = std::thread::spawn(move || { let handle = thread::spawn(move || {
let mut file = File::create(&thread_path).expect("Error creating file handle"); let mut file = File::create(&thread_path).expect("Error creating file handle");
file.write_all(thread_val.as_slice()) file.write_all(thread_val.as_slice())
@ -348,7 +352,7 @@ where
)); ));
match File::open(path).map_err(Error::from).and_then(|file| { match File::open(path).map_err(Error::from).and_then(|file| {
bincode::deserialize_from::<std::fs::File, T>(file) bincode::deserialize_from::<File, T>(file)
.with_context(|| format!("Unable to deserialize file {}", path.display())) .with_context(|| format!("Unable to deserialize file {}", path.display()))
.map_err(Error::from) .map_err(Error::from)
}) { }) {

View file

@ -8,12 +8,15 @@ mod test_state;
use anyhow::anyhow; use anyhow::anyhow;
use clap::App; use clap::App;
use gemla::core::{Gemla, GemlaConfig}; use easy_parallel::Parallel;
use gemla::error::log_error; use gemla::{
use std::path::PathBuf; constants::args::FILE,
use std::time::Instant; core::{Gemla, GemlaConfig},
error::{log_error, Error},
};
use smol::{channel, channel::RecvError, future, Executor};
use std::{path::PathBuf, time::Instant};
use test_state::TestState; use test_state::TestState;
// use std::io::Write;
/// Runs a simluation of a genetic algorithm against a dataset. /// Runs a simluation of a genetic algorithm against a dataset.
/// ///
@ -27,16 +30,13 @@ fn main() -> anyhow::Result<()> {
// Obtainning number of threads to use // Obtainning number of threads to use
let num_threads = num_cpus::get().max(1); let num_threads = num_cpus::get().max(1);
let ex = smol::Executor::new(); let ex = Executor::new();
let (signal, shutdown) = smol::channel::unbounded::<()>(); let (signal, shutdown) = channel::unbounded::<()>();
// Create an executor thread pool. // Create an executor thread pool.
let (_, result): ( let (_, result): (Vec<Result<(), RecvError>>, Result<(), Error>) = Parallel::new()
Vec<Result<(), smol::channel::RecvError>>,
Result<(), gemla::error::Error>,
) = easy_parallel::Parallel::new()
.each(0..num_threads, |_| { .each(0..num_threads, |_| {
smol::future::block_on(ex.run(shutdown.recv())) future::block_on(ex.run(shutdown.recv()))
}) })
.finish(|| { .finish(|| {
smol::block_on(async { smol::block_on(async {
@ -48,7 +48,7 @@ fn main() -> anyhow::Result<()> {
let matches = App::from_yaml(yaml).get_matches(); let matches = App::from_yaml(yaml).get_matches();
// Checking that the first argument <FILE> is a valid file // Checking that the first argument <FILE> is a valid file
if let Some(file_path) = matches.value_of(gemla::constants::args::FILE) { if let Some(file_path) = matches.value_of(FILE) {
let mut gemla = log_error(Gemla::<TestState>::new( let mut gemla = log_error(Gemla::<TestState>::new(
&PathBuf::from(file_path), &PathBuf::from(file_path),
GemlaConfig { GemlaConfig {
@ -61,9 +61,7 @@ fn main() -> anyhow::Result<()> {
Ok(()) Ok(())
} else { } else {
Err(gemla::error::Error::Other(anyhow!( Err(Error::Other(anyhow!("Invalid argument for FILE")))
"Invalid argument for FILE"
)))
} }
}) })
}); });

View file

@ -1,7 +1,5 @@
use gemla::core::genetic_node::GeneticNode; use gemla::{core::genetic_node::GeneticNode, error::Error};
use gemla::error;
use rand::prelude::*; use rand::prelude::*;
use rand::thread_rng;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
const POPULATION_SIZE: u64 = 5; const POPULATION_SIZE: u64 = 5;
@ -13,7 +11,7 @@ pub struct TestState {
} }
impl GeneticNode for TestState { impl GeneticNode for TestState {
fn initialize() -> Result<Box<Self>, error::Error> { fn initialize() -> Result<Box<Self>, Error> {
let mut population: Vec<i64> = vec![]; let mut population: Vec<i64> = vec![];
for _ in 0..POPULATION_SIZE { for _ in 0..POPULATION_SIZE {
@ -23,7 +21,7 @@ impl GeneticNode for TestState {
Ok(Box::new(TestState { population })) Ok(Box::new(TestState { population }))
} }
fn simulate(&mut self) -> Result<(), error::Error> { fn simulate(&mut self) -> Result<(), Error> {
let mut rng = thread_rng(); let mut rng = thread_rng();
self.population = self self.population = self
@ -35,7 +33,7 @@ impl GeneticNode for TestState {
Ok(()) Ok(())
} }
fn mutate(&mut self) -> Result<(), error::Error> { fn mutate(&mut self) -> Result<(), Error> {
let mut rng = thread_rng(); let mut rng = thread_rng();
let mut v = self.population.clone(); let mut v = self.population.clone();
@ -73,7 +71,7 @@ impl GeneticNode for TestState {
Ok(()) Ok(())
} }
fn merge(left: &TestState, right: &TestState) -> Result<Box<TestState>, error::Error> { fn merge(left: &TestState, right: &TestState) -> Result<Box<TestState>, Error> {
let mut v = left.population.clone(); let mut v = left.population.clone();
v.append(&mut right.population.clone()); v.append(&mut right.population.clone());

View file

@ -7,6 +7,7 @@ use crate::error::Error;
use anyhow::Context; use anyhow::Context;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt::Debug; use std::fmt::Debug;
use uuid::Uuid;
/// An enum used to control the state of a [`GeneticNode`] /// An enum used to control the state of a [`GeneticNode`]
/// ///
@ -52,7 +53,7 @@ pub struct GeneticNodeWrapper<T> {
state: GeneticState, state: GeneticState,
generation: u64, generation: u64,
max_generations: u64, max_generations: u64,
id: uuid::Uuid, id: Uuid,
} }
impl<T> Default for GeneticNodeWrapper<T> { impl<T> Default for GeneticNodeWrapper<T> {
@ -62,7 +63,7 @@ impl<T> Default for GeneticNodeWrapper<T> {
state: GeneticState::Initialize, state: GeneticState::Initialize,
generation: 0, generation: 0,
max_generations: 1, max_generations: 1,
id: uuid::Uuid::new_v4(), id: Uuid::new_v4(),
} }
} }
} }
@ -78,7 +79,7 @@ where
} }
} }
pub fn from(data: T, max_generations: u64, id: uuid::Uuid) -> Self { pub fn from(data: T, max_generations: u64, id: Uuid) -> Self {
GeneticNodeWrapper { GeneticNodeWrapper {
node: Some(data), node: Some(data),
state: GeneticState::Simulate, state: GeneticState::Simulate,
@ -92,7 +93,7 @@ where
self.node.as_ref() self.node.as_ref()
} }
pub fn id(&self) -> uuid::Uuid { pub fn id(&self) -> Uuid {
self.id self.id
} }

View file

@ -3,19 +3,17 @@
pub mod genetic_node; pub mod genetic_node;
use crate::error::Error; use crate::{error::Error, tree::Tree};
use crate::tree::Tree;
use file_linked::FileLinked; use file_linked::FileLinked;
use futures::{future, future::BoxFuture};
use genetic_node::{GeneticNode, GeneticNodeWrapper, GeneticState}; use genetic_node::{GeneticNode, GeneticNodeWrapper, GeneticState};
use log::{info, trace, warn}; use log::{info, trace, warn};
use serde::de::DeserializeOwned; use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde::{Deserialize, Serialize}; use std::{
use std::fmt::Debug; collections::HashMap, fmt::Debug, fs::File, io::ErrorKind, marker::Send, mem, path::Path,
use std::fs::File; time::Instant,
use std::io::ErrorKind; };
use std::mem::swap; use uuid::Uuid;
use std::path::Path;
use std::time::Instant;
type SimulationTree<T> = Box<Tree<GeneticNodeWrapper<T>>>; type SimulationTree<T> = Box<Tree<GeneticNodeWrapper<T>>>;
@ -36,15 +34,12 @@ where
T: Serialize + Clone, T: Serialize + Clone,
{ {
pub data: FileLinked<(Option<SimulationTree<T>>, GemlaConfig)>, pub data: FileLinked<(Option<SimulationTree<T>>, GemlaConfig)>,
threads: std::collections::HashMap< threads: HashMap<Uuid, BoxFuture<'a, Result<GeneticNodeWrapper<T>, Error>>>,
uuid::Uuid,
futures::prelude::future::BoxFuture<'a, Result<GeneticNodeWrapper<T>, Error>>,
>,
} }
impl<'a, T: 'a> Gemla<'a, T> impl<'a, T: 'a> Gemla<'a, T>
where where
T: GeneticNode + Serialize + DeserializeOwned + Debug + Clone + std::marker::Send, T: GeneticNode + Serialize + DeserializeOwned + Debug + Clone + Send,
{ {
pub fn new(path: &Path, config: GemlaConfig) -> Result<Self, Error> { pub fn new(path: &Path, config: GemlaConfig) -> Result<Self, Error> {
match File::open(path) { match File::open(path) {
@ -54,11 +49,11 @@ where
} else { } else {
FileLinked::from_file(path)? FileLinked::from_file(path)?
}, },
threads: std::collections::HashMap::new(), threads: HashMap::new(),
}), }),
Err(error) if error.kind() == ErrorKind::NotFound => Ok(Gemla { Err(error) if error.kind() == ErrorKind::NotFound => Ok(Gemla {
data: FileLinked::new((None, config), path)?, data: FileLinked::new((None, config), path)?,
threads: std::collections::HashMap::new(), threads: HashMap::new(),
}), }),
Err(error) => Err(Error::IO(error)), Err(error) => Err(Error::IO(error)),
} }
@ -69,11 +64,9 @@ where
// in the tree and which nodes have not. // in the tree and which nodes have not.
self.data.mutate(|(d, c)| { self.data.mutate(|(d, c)| {
let mut tree: Option<SimulationTree<T>> = Gemla::increase_height(d.take(), c, steps); let mut tree: Option<SimulationTree<T>> = Gemla::increase_height(d.take(), c, steps);
swap(d, &mut tree); mem::swap(d, &mut tree);
})?; })?;
// println!("{}", serde_json::to_string(&self.data.readonly().0).expect(""));
info!( info!(
"Height of simulation tree increased to {}", "Height of simulation tree increased to {}",
self.data self.data
@ -124,7 +117,7 @@ where
if !self.threads.is_empty() { if !self.threads.is_empty() {
trace!("Joining threads for nodes {:?}", self.threads.keys()); trace!("Joining threads for nodes {:?}", self.threads.keys());
let results = futures::future::join_all(self.threads.values_mut()).await; let results = future::join_all(self.threads.values_mut()).await;
let reduced_results: Result<Vec<GeneticNodeWrapper<T>>, Error> = let reduced_results: Result<Vec<GeneticNodeWrapper<T>>, Error> =
results.into_iter().collect(); results.into_iter().collect();