Cleaned up use statements
This commit is contained in:
parent
95c65fa4b1
commit
265f554d08
5 changed files with 53 additions and 59 deletions
|
@ -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)
|
||||||
}) {
|
}) {
|
||||||
|
|
|
@ -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"
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
|
@ -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());
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue