Revising error types
This commit is contained in:
parent
d4af685500
commit
edc2f67897
8 changed files with 153 additions and 132 deletions
|
@ -15,4 +15,6 @@ categories = ["filesystem", "data-structures"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
thiserror = "1.0"
|
||||||
|
anyhow = "1.0"
|
|
@ -4,11 +4,24 @@ extern crate serde;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::io;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::path;
|
use std::path;
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Context};
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
Serialization(serde_json::Error),
|
||||||
|
#[error(transparent)]
|
||||||
|
IO(std::io::Error),
|
||||||
|
#[error(transparent)]
|
||||||
|
Other(#[from] anyhow::Error),
|
||||||
|
}
|
||||||
|
|
||||||
/// 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
|
||||||
pub struct FileLinked<T>
|
pub struct FileLinked<T>
|
||||||
|
@ -95,9 +108,12 @@ where
|
||||||
/// # std::fs::remove_file("./temp").expect("Unable to remove file");
|
/// # std::fs::remove_file("./temp").expect("Unable to remove file");
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn new(val: T, path: path::PathBuf) -> Result<FileLinked<T>, String> {
|
pub fn new(val: T, path: path::PathBuf) -> Result<FileLinked<T>, Error> {
|
||||||
if path.is_file() {
|
if path.is_file() {
|
||||||
return Err(format!("{} is not a valid file path", path.display()));
|
return Err(Error::IO(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
anyhow!("{} is not a valid file path", path.display()),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = FileLinked { val, path };
|
let result = FileLinked { val, path };
|
||||||
|
@ -107,20 +123,20 @@ where
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_data(&self) -> Result<(), String> {
|
fn write_data(&self) -> Result<(), Error> {
|
||||||
let mut file = fs::OpenOptions::new()
|
let mut file = fs::OpenOptions::new()
|
||||||
.write(true)
|
.write(true)
|
||||||
.create(true)
|
.create(true)
|
||||||
.truncate(true)
|
.truncate(true)
|
||||||
.open(&self.path)
|
.open(&self.path)
|
||||||
.map_err(|_| format!("Unable to open path {}", self.path.display()))?;
|
.with_context(|| format!("Unable to open path {}", self.path.display()))?;
|
||||||
|
|
||||||
write!(
|
write!(
|
||||||
file,
|
file,
|
||||||
"{}",
|
"{}",
|
||||||
serde_json::to_string(&self.val).map_err(|e| e.to_string())?
|
serde_json::to_string(&self.val).map_err(Error::Serialization)?
|
||||||
)
|
)
|
||||||
.or_else(|_| Err(String::from("Unable to write to file.")))?;
|
.with_context(|| format!("Unable to write to file {}", self.path.display()))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -143,7 +159,7 @@ where
|
||||||
/// # pub c: f64
|
/// # pub c: f64
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # fn main() -> Result<(), String> {
|
/// # fn main() -> Result<(), Error> {
|
||||||
/// let test = Test {
|
/// let test = Test {
|
||||||
/// a: 1,
|
/// a: 1,
|
||||||
/// b: String::from(""),
|
/// b: String::from(""),
|
||||||
|
@ -164,7 +180,7 @@ where
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn mutate<U, F: FnOnce(&mut T) -> U>(&mut self, op: F) -> Result<U, String> {
|
pub fn mutate<U, F: FnOnce(&mut T) -> U>(&mut self, op: F) -> Result<U, Error> {
|
||||||
let result = op(&mut self.val);
|
let result = op(&mut self.val);
|
||||||
|
|
||||||
self.write_data()?;
|
self.write_data()?;
|
||||||
|
@ -189,7 +205,7 @@ where
|
||||||
/// # pub c: f64
|
/// # pub c: f64
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # fn main() -> Result<(), String> {
|
/// # fn main() -> Result<(), Error> {
|
||||||
/// let test = Test {
|
/// let test = Test {
|
||||||
/// a: 1,
|
/// a: 1,
|
||||||
/// b: String::from(""),
|
/// b: String::from(""),
|
||||||
|
@ -214,7 +230,7 @@ where
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn replace(&mut self, val: T) -> Result<(), String> {
|
pub fn replace(&mut self, val: T) -> Result<(), Error> {
|
||||||
self.val = val;
|
self.val = val;
|
||||||
|
|
||||||
self.write_data()
|
self.write_data()
|
||||||
|
@ -245,7 +261,7 @@ where
|
||||||
/// # pub c: f64
|
/// # pub c: f64
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # fn main() -> Result<(), String> {
|
/// # fn main() -> Result<(), Error> {
|
||||||
/// let test = Test {
|
/// let test = Test {
|
||||||
/// a: 1,
|
/// a: 1,
|
||||||
/// b: String::from("2"),
|
/// b: String::from("2"),
|
||||||
|
@ -278,27 +294,33 @@ where
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn from_file(path: path::PathBuf) -> Result<FileLinked<T>, String> {
|
pub fn from_file(path: path::PathBuf) -> Result<FileLinked<T>, Error> {
|
||||||
if !path.is_file() {
|
if !path.is_file() {
|
||||||
return Err(format!("{} is not a valid file path", path.display()));
|
return Err(Error::IO(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
anyhow!("{} is not a valid file path", path.display()),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let metadata = path
|
let metadata = path
|
||||||
.metadata()
|
.metadata()
|
||||||
.map_err(|_| format!("Error obtaining metadata for {}", path.display()))?;
|
.with_context(|| format!("Error obtaining metadata for {}", path.display()))?;
|
||||||
|
|
||||||
if metadata.is_file() {
|
if metadata.is_file() {
|
||||||
let file = fs::OpenOptions::new()
|
let file = fs::OpenOptions::new()
|
||||||
.read(true)
|
.read(true)
|
||||||
.open(&path)
|
.open(&path)
|
||||||
.map_err(|_| format!("Unable to open file {}", path.display()))?;
|
.with_context(|| format!("Unable to open file {}", path.display()))?;
|
||||||
|
|
||||||
let val = serde_json::from_reader(file)
|
let val = serde_json::from_reader(file)
|
||||||
.map_err(|_| String::from("Unable to parse value from file."))?;
|
.with_context(|| String::from("Unable to parse value from file."))?;
|
||||||
|
|
||||||
Ok(FileLinked { val, path })
|
Ok(FileLinked { val, path })
|
||||||
} else {
|
} else {
|
||||||
Err(format!("{} is not a file.", path.display()))
|
return Err(Error::IO(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
anyhow!("{} is not a file.", path.display()),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -318,7 +340,7 @@ mod tests {
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mutate() -> Result<(), String> {
|
fn test_mutate() -> Result<(), Error> {
|
||||||
let list = vec![1, 2, 3, 4];
|
let list = vec![1, 2, 3, 4];
|
||||||
let mut file_linked_list = FileLinked::new(list, path::PathBuf::from("test.txt"))?;
|
let mut file_linked_list = FileLinked::new(list, path::PathBuf::from("test.txt"))?;
|
||||||
|
|
||||||
|
|
|
@ -18,4 +18,6 @@ uuid = { version = "0.7", features = ["serde", "v4"] }
|
||||||
clap = { version = "~2.27.0", features = ["yaml"] }
|
clap = { version = "~2.27.0", features = ["yaml"] }
|
||||||
toml = "0.5.8"
|
toml = "0.5.8"
|
||||||
regex = "1"
|
regex = "1"
|
||||||
file_linked = { version = "0.1.0", path = "../file_linked" }
|
file_linked = { version = "0.1.0", path = "../file_linked" }
|
||||||
|
thiserror = "1.0"
|
||||||
|
anyhow = "1.0"
|
|
@ -2,6 +2,9 @@
|
||||||
//!
|
//!
|
||||||
//! [`Bracket`]: crate::bracket::Bracket
|
//! [`Bracket`]: crate::bracket::Bracket
|
||||||
|
|
||||||
|
use crate::error::Error;
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
@ -33,19 +36,20 @@ pub trait GeneticNode {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use gemla::bracket::genetic_node::GeneticNode;
|
/// # use gemla::bracket::genetic_node::GeneticNode;
|
||||||
|
/// # use gemla::error::Error;
|
||||||
/// #
|
/// #
|
||||||
/// struct Node {
|
/// struct Node {
|
||||||
/// pub fit_score: f64,
|
/// pub fit_score: f64,
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// impl GeneticNode for Node {
|
/// impl GeneticNode for Node {
|
||||||
/// fn initialize() -> Result<Box<Self>, String> {
|
/// fn initialize() -> Result<Box<Self>, Error> {
|
||||||
/// Ok(Box::new(Node {fit_score: 0.0}))
|
/// Ok(Box::new(Node {fit_score: 0.0}))
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// //...
|
/// //...
|
||||||
/// #
|
/// #
|
||||||
/// # fn simulate(&mut self, iterations: u64) -> Result<(), String> {
|
/// # fn simulate(&mut self, iterations: u64) -> Result<(), Error> {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
|
@ -53,22 +57,22 @@ pub trait GeneticNode {
|
||||||
/// # self.fit_score
|
/// # self.fit_score
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # fn calculate_scores_and_trim(&mut self) -> Result<(), String> {
|
/// # fn calculate_scores_and_trim(&mut self) -> Result<(), Error> {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # fn mutate(&mut self) -> Result<(), String> {
|
/// # fn mutate(&mut self) -> Result<(), Error> {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// # fn main() -> Result<(), String> {
|
/// # fn main() -> Result<(), Error> {
|
||||||
/// let node = Node::initialize()?;
|
/// let node = Node::initialize()?;
|
||||||
/// assert_eq!(node.get_fit_score(), 0.0);
|
/// assert_eq!(node.get_fit_score(), 0.0);
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
fn initialize() -> Result<Box<Self>, String>;
|
fn initialize() -> Result<Box<Self>, Error>;
|
||||||
|
|
||||||
/// Runs a simulation on the state object for the given number of `iterations` in order to guage it's fitness.
|
/// Runs a simulation on the state object for the given number of `iterations` in order to guage it's fitness.
|
||||||
/// This will be called for every node in a bracket before evaluating it's fitness against other nodes.
|
/// This will be called for every node in a bracket before evaluating it's fitness against other nodes.
|
||||||
|
@ -77,6 +81,7 @@ pub trait GeneticNode {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use gemla::bracket::genetic_node::GeneticNode;
|
/// # use gemla::bracket::genetic_node::GeneticNode;
|
||||||
|
/// # use gemla::error::Error;
|
||||||
/// #
|
/// #
|
||||||
/// struct Model {
|
/// struct Model {
|
||||||
/// pub fit_score: f64,
|
/// pub fit_score: f64,
|
||||||
|
@ -89,7 +94,7 @@ pub trait GeneticNode {
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// impl Model {
|
/// impl Model {
|
||||||
/// fn fit(&mut self, epochs: u64) -> Result<(), String> {
|
/// fn fit(&mut self, epochs: u64) -> Result<(), Error> {
|
||||||
/// //...
|
/// //...
|
||||||
/// # self.fit_score += epochs as f64;
|
/// # self.fit_score += epochs as f64;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
|
@ -97,13 +102,13 @@ pub trait GeneticNode {
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// impl GeneticNode for Node {
|
/// impl GeneticNode for Node {
|
||||||
/// # fn initialize() -> Result<Box<Self>, String> {
|
/// # fn initialize() -> Result<Box<Self>, Error> {
|
||||||
/// # Ok(Box::new(Node {models: vec![Model {fit_score: 0.0}]}))
|
/// # Ok(Box::new(Node {models: vec![Model {fit_score: 0.0}]}))
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// //...
|
/// //...
|
||||||
///
|
///
|
||||||
/// fn simulate(&mut self, iterations: u64) -> Result<(), String> {
|
/// fn simulate(&mut self, iterations: u64) -> Result<(), Error> {
|
||||||
/// for m in self.models.iter_mut()
|
/// for m in self.models.iter_mut()
|
||||||
/// {
|
/// {
|
||||||
/// m.fit(iterations)?;
|
/// m.fit(iterations)?;
|
||||||
|
@ -117,23 +122,23 @@ pub trait GeneticNode {
|
||||||
/// # self.models.iter().max_by(|m1, m2| m1.fit_score.partial_cmp(&m2.fit_score).unwrap()).unwrap().fit_score
|
/// # self.models.iter().max_by(|m1, m2| m1.fit_score.partial_cmp(&m2.fit_score).unwrap()).unwrap().fit_score
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # fn calculate_scores_and_trim(&mut self) -> Result<(), String> {
|
/// # fn calculate_scores_and_trim(&mut self) -> Result<(), Error> {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # fn mutate(&mut self) -> Result<(), String> {
|
/// # fn mutate(&mut self) -> Result<(), Error> {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// # fn main() -> Result<(), String> {
|
/// # fn main() -> Result<(), Error> {
|
||||||
/// let mut node = Node::initialize()?;
|
/// let mut node = Node::initialize()?;
|
||||||
/// node.simulate(5)?;
|
/// node.simulate(5)?;
|
||||||
/// assert_eq!(node.get_fit_score(), 5.0);
|
/// assert_eq!(node.get_fit_score(), 5.0);
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
fn simulate(&mut self, iterations: u64) -> Result<(), String>;
|
fn simulate(&mut self, iterations: u64) -> Result<(), Error>;
|
||||||
|
|
||||||
/// Returns a fit score associated with the nodes performance.
|
/// Returns a fit score associated with the nodes performance.
|
||||||
/// This will be used by a bracket in order to determine the most successful child.
|
/// This will be used by a bracket in order to determine the most successful child.
|
||||||
|
@ -141,6 +146,7 @@ pub trait GeneticNode {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// # use gemla::bracket::genetic_node::GeneticNode;
|
/// # use gemla::bracket::genetic_node::GeneticNode;
|
||||||
|
/// # use gemla::error::Error;
|
||||||
/// #
|
/// #
|
||||||
/// struct Model {
|
/// struct Model {
|
||||||
/// pub fit_score: f64,
|
/// pub fit_score: f64,
|
||||||
|
@ -153,7 +159,7 @@ pub trait GeneticNode {
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// # impl Model {
|
/// # impl Model {
|
||||||
/// # fn fit(&mut self, epochs: u64) -> Result<(), String> {
|
/// # fn fit(&mut self, epochs: u64) -> Result<(), Error> {
|
||||||
/// # //...
|
/// # //...
|
||||||
/// # self.fit_score += epochs as f64;
|
/// # self.fit_score += epochs as f64;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
|
@ -161,13 +167,13 @@ pub trait GeneticNode {
|
||||||
/// # }
|
/// # }
|
||||||
///
|
///
|
||||||
/// impl GeneticNode for Node {
|
/// impl GeneticNode for Node {
|
||||||
/// # fn initialize() -> Result<Box<Self>, String> {
|
/// # fn initialize() -> Result<Box<Self>, Error> {
|
||||||
/// # Ok(Box::new(Node {models: vec![Model {fit_score: 0.0}]}))
|
/// # Ok(Box::new(Node {models: vec![Model {fit_score: 0.0}]}))
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # //...
|
/// # //...
|
||||||
/// #
|
/// #
|
||||||
/// # fn simulate(&mut self, iterations: u64) -> Result<(), String> {
|
/// # fn simulate(&mut self, iterations: u64) -> Result<(), Error> {
|
||||||
/// # for m in self.models.iter_mut()
|
/// # for m in self.models.iter_mut()
|
||||||
/// # {
|
/// # {
|
||||||
/// # m.fit(iterations)?;
|
/// # m.fit(iterations)?;
|
||||||
|
@ -182,16 +188,16 @@ pub trait GeneticNode {
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// //...
|
/// //...
|
||||||
/// # fn calculate_scores_and_trim(&mut self) -> Result<(), String> {
|
/// # fn calculate_scores_and_trim(&mut self) -> Result<(), Error> {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # fn mutate(&mut self) -> Result<(), String> {
|
/// # fn mutate(&mut self) -> Result<(), Error> {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// # fn main() -> Result<(), String> {
|
/// # fn main() -> Result<(), Error> {
|
||||||
/// let mut node = Node::initialize()?;
|
/// let mut node = Node::initialize()?;
|
||||||
/// node.simulate(5)?;
|
/// node.simulate(5)?;
|
||||||
/// assert_eq!(node.get_fit_score(), 5.0);
|
/// assert_eq!(node.get_fit_score(), 5.0);
|
||||||
|
@ -205,6 +211,7 @@ pub trait GeneticNode {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// # use gemla::bracket::genetic_node::GeneticNode;
|
/// # use gemla::bracket::genetic_node::GeneticNode;
|
||||||
|
/// # use gemla::error::Error;
|
||||||
/// #
|
/// #
|
||||||
/// struct Model {
|
/// struct Model {
|
||||||
/// pub fit_score: f64,
|
/// pub fit_score: f64,
|
||||||
|
@ -218,7 +225,7 @@ pub trait GeneticNode {
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// # impl Model {
|
/// # impl Model {
|
||||||
/// # fn fit(&mut self, epochs: u64) -> Result<(), String> {
|
/// # fn fit(&mut self, epochs: u64) -> Result<(), Error> {
|
||||||
/// # //...
|
/// # //...
|
||||||
/// # self.fit_score += epochs as f64;
|
/// # self.fit_score += epochs as f64;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
|
@ -226,7 +233,7 @@ pub trait GeneticNode {
|
||||||
/// # }
|
/// # }
|
||||||
///
|
///
|
||||||
/// impl GeneticNode for Node {
|
/// impl GeneticNode for Node {
|
||||||
/// # fn initialize() -> Result<Box<Self>, String> {
|
/// # fn initialize() -> Result<Box<Self>, Error> {
|
||||||
/// # Ok(Box::new(Node {
|
/// # Ok(Box::new(Node {
|
||||||
/// # models: vec![
|
/// # models: vec![
|
||||||
/// # Model { fit_score: 0.0 },
|
/// # Model { fit_score: 0.0 },
|
||||||
|
@ -241,7 +248,7 @@ pub trait GeneticNode {
|
||||||
/// #
|
/// #
|
||||||
/// # //...
|
/// # //...
|
||||||
/// #
|
/// #
|
||||||
/// # fn simulate(&mut self, iterations: u64) -> Result<(), String> {
|
/// # fn simulate(&mut self, iterations: u64) -> Result<(), Error> {
|
||||||
/// # for m in self.models.iter_mut() {
|
/// # for m in self.models.iter_mut() {
|
||||||
/// # m.fit(iterations)?;
|
/// # m.fit(iterations)?;
|
||||||
/// # }
|
/// # }
|
||||||
|
@ -258,7 +265,7 @@ pub trait GeneticNode {
|
||||||
/// # .fit_score
|
/// # .fit_score
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// fn calculate_scores_and_trim(&mut self) -> Result<(), String> {
|
/// fn calculate_scores_and_trim(&mut self) -> Result<(), Error> {
|
||||||
/// self.models.sort_by(|a, b| a.fit_score.partial_cmp(&b.fit_score).unwrap().reverse());
|
/// self.models.sort_by(|a, b| a.fit_score.partial_cmp(&b.fit_score).unwrap().reverse());
|
||||||
/// self.models.truncate(3);
|
/// self.models.truncate(3);
|
||||||
/// Ok(())
|
/// Ok(())
|
||||||
|
@ -266,12 +273,12 @@ pub trait GeneticNode {
|
||||||
///
|
///
|
||||||
/// //...
|
/// //...
|
||||||
/// #
|
/// #
|
||||||
/// # fn mutate(&mut self) -> Result<(), String> {
|
/// # fn mutate(&mut self) -> Result<(), Error> {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// # fn main() -> Result<(), String> {
|
/// # fn main() -> Result<(), Error> {
|
||||||
/// let mut node = Node::initialize()?;
|
/// let mut node = Node::initialize()?;
|
||||||
/// assert_eq!(node.models.len(), 5);
|
/// assert_eq!(node.models.len(), 5);
|
||||||
///
|
///
|
||||||
|
@ -283,13 +290,14 @@ pub trait GeneticNode {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
fn calculate_scores_and_trim(&mut self) -> Result<(), String>;
|
fn calculate_scores_and_trim(&mut self) -> Result<(), Error>;
|
||||||
|
|
||||||
/// Mutates members in a population and/or crossbreeds them to produce new offspring.
|
/// Mutates members in a population and/or crossbreeds them to produce new offspring.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// # use gemla::bracket::genetic_node::GeneticNode;
|
/// # use gemla::bracket::genetic_node::GeneticNode;
|
||||||
|
/// # use gemla::error::Error;
|
||||||
/// # use std::convert::TryInto;
|
/// # use std::convert::TryInto;
|
||||||
/// #
|
/// #
|
||||||
/// struct Model {
|
/// struct Model {
|
||||||
|
@ -304,7 +312,7 @@ pub trait GeneticNode {
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// # impl Model {
|
/// # impl Model {
|
||||||
/// # fn fit(&mut self, epochs: u64) -> Result<(), String> {
|
/// # fn fit(&mut self, epochs: u64) -> Result<(), Error> {
|
||||||
/// # //...
|
/// # //...
|
||||||
/// # self.fit_score += epochs as f64;
|
/// # self.fit_score += epochs as f64;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
|
@ -320,7 +328,7 @@ pub trait GeneticNode {
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// impl GeneticNode for Node {
|
/// impl GeneticNode for Node {
|
||||||
/// # fn initialize() -> Result<Box<Self>, String> {
|
/// # fn initialize() -> Result<Box<Self>, Error> {
|
||||||
/// # Ok(Box::new(Node {
|
/// # Ok(Box::new(Node {
|
||||||
/// # models: vec![
|
/// # models: vec![
|
||||||
/// # Model { fit_score: 0.0 },
|
/// # Model { fit_score: 0.0 },
|
||||||
|
@ -333,7 +341,7 @@ pub trait GeneticNode {
|
||||||
/// # }))
|
/// # }))
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # fn simulate(&mut self, iterations: u64) -> Result<(), String> {
|
/// # fn simulate(&mut self, iterations: u64) -> Result<(), Error> {
|
||||||
/// # for m in self.models.iter_mut() {
|
/// # for m in self.models.iter_mut() {
|
||||||
/// # m.fit(iterations)?;
|
/// # m.fit(iterations)?;
|
||||||
/// # }
|
/// # }
|
||||||
|
@ -348,14 +356,14 @@ pub trait GeneticNode {
|
||||||
/// # .fit_score
|
/// # .fit_score
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # fn calculate_scores_and_trim(&mut self) -> Result<(), String> {
|
/// # fn calculate_scores_and_trim(&mut self) -> Result<(), Error> {
|
||||||
/// # self.models.sort_by(|a, b| a.fit_score.partial_cmp(&b.fit_score).unwrap().reverse());
|
/// # self.models.sort_by(|a, b| a.fit_score.partial_cmp(&b.fit_score).unwrap().reverse());
|
||||||
/// # self.models.truncate(3);
|
/// # self.models.truncate(3);
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// //...
|
/// //...
|
||||||
///
|
///
|
||||||
/// fn mutate(&mut self) -> Result<(), String> {
|
/// fn mutate(&mut self) -> Result<(), Error> {
|
||||||
/// loop {
|
/// loop {
|
||||||
/// if self.models.len() < self.population_size.try_into().unwrap()
|
/// if self.models.len() < self.population_size.try_into().unwrap()
|
||||||
/// {
|
/// {
|
||||||
|
@ -368,7 +376,7 @@ pub trait GeneticNode {
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// # fn main() -> Result<(), String> {
|
/// # fn main() -> Result<(), Error> {
|
||||||
/// let mut node = Node::initialize()?;
|
/// let mut node = Node::initialize()?;
|
||||||
/// assert_eq!(node.models.len(), 5);
|
/// assert_eq!(node.models.len(), 5);
|
||||||
///
|
///
|
||||||
|
@ -383,7 +391,7 @@ pub trait GeneticNode {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
fn mutate(&mut self) -> Result<(), String>;
|
fn mutate(&mut self) -> Result<(), Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used externally to wrap a node implementing the [`GeneticNode`] trait. Processes state transitions for the given node as
|
/// Used externally to wrap a node implementing the [`GeneticNode`] trait. Processes state transitions for the given node as
|
||||||
|
@ -410,6 +418,7 @@ where
|
||||||
/// ```
|
/// ```
|
||||||
/// # use gemla::bracket::genetic_node::GeneticNode;
|
/// # use gemla::bracket::genetic_node::GeneticNode;
|
||||||
/// # use gemla::bracket::genetic_node::GeneticNodeWrapper;
|
/// # use gemla::bracket::genetic_node::GeneticNodeWrapper;
|
||||||
|
/// # use gemla::error::Error;
|
||||||
/// # #[derive(Debug)]
|
/// # #[derive(Debug)]
|
||||||
/// struct Node {
|
/// struct Node {
|
||||||
/// # pub fit_score: f64,
|
/// # pub fit_score: f64,
|
||||||
|
@ -418,12 +427,12 @@ where
|
||||||
///
|
///
|
||||||
/// impl GeneticNode for Node {
|
/// impl GeneticNode for Node {
|
||||||
/// //...
|
/// //...
|
||||||
/// # fn initialize() -> Result<Box<Self>, String> {
|
/// # fn initialize() -> Result<Box<Self>, Error> {
|
||||||
/// # Ok(Box::new(Node {fit_score: 0.0}))
|
/// # Ok(Box::new(Node {fit_score: 0.0}))
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// #
|
/// #
|
||||||
/// # fn simulate(&mut self, iterations: u64) -> Result<(), String> {
|
/// # fn simulate(&mut self, iterations: u64) -> Result<(), Error> {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
|
@ -431,22 +440,22 @@ where
|
||||||
/// # self.fit_score
|
/// # self.fit_score
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # fn calculate_scores_and_trim(&mut self) -> Result<(), String> {
|
/// # fn calculate_scores_and_trim(&mut self) -> Result<(), Error> {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # fn mutate(&mut self) -> Result<(), String> {
|
/// # fn mutate(&mut self) -> Result<(), Error> {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// # fn main() -> Result<(), String> {
|
/// # fn main() -> Result<(), Error> {
|
||||||
/// let mut wrapped_node = GeneticNodeWrapper::<Node>::new()?;
|
/// let mut wrapped_node = GeneticNodeWrapper::<Node>::new()?;
|
||||||
/// assert_eq!(wrapped_node.data.unwrap().get_fit_score(), 0.0);
|
/// assert_eq!(wrapped_node.data.unwrap().get_fit_score(), 0.0);
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn new() -> Result<Self, String> {
|
pub fn new() -> Result<Self, Error> {
|
||||||
let mut node = GeneticNodeWrapper {
|
let mut node = GeneticNodeWrapper {
|
||||||
data: None,
|
data: None,
|
||||||
state: GeneticState::Initialize,
|
state: GeneticState::Initialize,
|
||||||
|
@ -476,14 +485,14 @@ where
|
||||||
/// [`simulate`]: crate::bracket::genetic_node::GeneticNode#tymethod.simulate
|
/// [`simulate`]: crate::bracket::genetic_node::GeneticNode#tymethod.simulate
|
||||||
/// [`calculate_scores_and_trim`]: crate::bracket::genetic_node::GeneticNode#tymethod.calculate_scores_and_trim
|
/// [`calculate_scores_and_trim`]: crate::bracket::genetic_node::GeneticNode#tymethod.calculate_scores_and_trim
|
||||||
/// [`mutate`]: crate::bracket::genetic_node::GeneticNode#tymethod.mutate
|
/// [`mutate`]: crate::bracket::genetic_node::GeneticNode#tymethod.mutate
|
||||||
pub fn process_node(&mut self, iterations: u32) -> Result<(), String> {
|
pub fn process_node(&mut self, iterations: u32) -> Result<(), Error> {
|
||||||
// Looping through each state transition until the number of iterations have been reached.
|
// Looping through each state transition until the number of iterations have been reached.
|
||||||
loop {
|
loop {
|
||||||
match (self.state, self.data.as_ref()) {
|
match (self.state, &self.data) {
|
||||||
(GeneticState::Initialize, _) => {
|
(GeneticState::Initialize, _) => {
|
||||||
self.iteration = 0;
|
self.iteration = 0;
|
||||||
let new_data =
|
let new_data = T::initialize()
|
||||||
T::initialize().map_err(|e| format!("Error initializing node: {}", e))?;
|
.with_context(|| format!("Error initializing node {:?}", self))?;
|
||||||
self.data = Some(*new_data);
|
self.data = Some(*new_data);
|
||||||
self.state = GeneticState::Simulate;
|
self.state = GeneticState::Simulate;
|
||||||
}
|
}
|
||||||
|
@ -492,7 +501,7 @@ where
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.simulate(5)
|
.simulate(5)
|
||||||
.map_err(|e| format!("Error simulating node: {}", e))?;
|
.with_context(|| format!("Error simulating node: {:?}", self))?;
|
||||||
self.state = GeneticState::Score;
|
self.state = GeneticState::Score;
|
||||||
}
|
}
|
||||||
(GeneticState::Score, Some(_)) => {
|
(GeneticState::Score, Some(_)) => {
|
||||||
|
@ -500,7 +509,7 @@ where
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.calculate_scores_and_trim()
|
.calculate_scores_and_trim()
|
||||||
.map_err(|e| format!("Error scoring and trimming node: {}", e))?;
|
.with_context(|| format!("Error scoring and trimming node: {:?}", self))?;
|
||||||
|
|
||||||
self.state = if self.iteration == iterations {
|
self.state = if self.iteration == iterations {
|
||||||
GeneticState::Finish
|
GeneticState::Finish
|
||||||
|
@ -513,13 +522,13 @@ where
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.mutate()
|
.mutate()
|
||||||
.map_err(|e| format!("Error mutating node: {}", e))?;
|
.with_context(|| format!("Error mutating node: {:?}", self))?;
|
||||||
self.state = GeneticState::Simulate;
|
self.state = GeneticState::Simulate;
|
||||||
}
|
}
|
||||||
(GeneticState::Finish, Some(_)) => {
|
(GeneticState::Finish, Some(_)) => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_ => return Err(format!("Error processing node {:?}", self.data)),
|
_ => panic!("Error processing node {:?}", self.data),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,14 +3,14 @@
|
||||||
|
|
||||||
pub mod genetic_node;
|
pub mod genetic_node;
|
||||||
|
|
||||||
use super::tree;
|
use crate::error::Error;
|
||||||
|
use crate::tree;
|
||||||
|
|
||||||
use file_linked::FileLinked;
|
use file_linked::FileLinked;
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::path;
|
use std::path;
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
/// As the bracket tree increases in height, `IterationScaling` can be used to configure the number of iterations that
|
/// As the bracket tree increases in height, `IterationScaling` can be used to configure the number of iterations that
|
||||||
/// a node runs for.
|
/// a node runs for.
|
||||||
|
@ -19,6 +19,7 @@ use std::str::FromStr;
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use gemla::bracket::*;
|
/// # use gemla::bracket::*;
|
||||||
|
/// # use gemla::error::Error;
|
||||||
/// # use serde::{Deserialize, Serialize};
|
/// # use serde::{Deserialize, Serialize};
|
||||||
/// # use std::fmt;
|
/// # use std::fmt;
|
||||||
/// # use std::str::FromStr;
|
/// # use std::str::FromStr;
|
||||||
|
@ -30,14 +31,6 @@ use std::str::FromStr;
|
||||||
/// # pub score: f64,
|
/// # pub score: f64,
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # impl FromStr for TestState {
|
|
||||||
/// # type Err = String;
|
|
||||||
/// #
|
|
||||||
/// # fn from_str(s: &str) -> Result<TestState, Self::Err> {
|
|
||||||
/// # serde_json::from_str(s).map_err(|_| format!("Unable to parse string {}", s))
|
|
||||||
/// # }
|
|
||||||
/// # }
|
|
||||||
/// #
|
|
||||||
/// # impl TestState {
|
/// # impl TestState {
|
||||||
/// # fn new(score: f64) -> TestState {
|
/// # fn new(score: f64) -> TestState {
|
||||||
/// # TestState { score: score }
|
/// # TestState { score: score }
|
||||||
|
@ -45,7 +38,7 @@ use std::str::FromStr;
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # impl genetic_node::GeneticNode for TestState {
|
/// # impl genetic_node::GeneticNode for TestState {
|
||||||
/// # fn simulate(&mut self, iterations: u64) -> Result<(), String> {
|
/// # fn simulate(&mut self, iterations: u64) -> Result<(), Error> {
|
||||||
/// # self.score += iterations as f64;
|
/// # self.score += iterations as f64;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
|
@ -54,15 +47,15 @@ use std::str::FromStr;
|
||||||
/// # self.score
|
/// # self.score
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # fn calculate_scores_and_trim(&mut self) -> Result<(), String> {
|
/// # fn calculate_scores_and_trim(&mut self) -> Result<(), Error> {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # fn mutate(&mut self) -> Result<(), String> {
|
/// # fn mutate(&mut self) -> Result<(), Error> {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # fn initialize() -> Result<Box<Self>, String> {
|
/// # fn initialize() -> Result<Box<Self>, Error> {
|
||||||
/// # Ok(Box::new(TestState { score: 0.0 }))
|
/// # Ok(Box::new(TestState { score: 0.0 }))
|
||||||
/// # }
|
/// # }
|
||||||
/// # }
|
/// # }
|
||||||
|
@ -135,7 +128,7 @@ where
|
||||||
|
|
||||||
impl<T> Bracket<T>
|
impl<T> Bracket<T>
|
||||||
where
|
where
|
||||||
T: genetic_node::GeneticNode + FromStr + Default + DeserializeOwned + Serialize + Clone,
|
T: genetic_node::GeneticNode + Default + DeserializeOwned + Serialize + Clone,
|
||||||
{
|
{
|
||||||
/// Initializes a bracket of type `T` storing the contents to `file_path`
|
/// Initializes a bracket of type `T` storing the contents to `file_path`
|
||||||
///
|
///
|
||||||
|
@ -143,6 +136,7 @@ where
|
||||||
/// ```
|
/// ```
|
||||||
/// # use gemla::bracket::*;
|
/// # use gemla::bracket::*;
|
||||||
/// # use gemla::btree;
|
/// # use gemla::btree;
|
||||||
|
/// # use gemla::error::Error;
|
||||||
/// # use serde::{Deserialize, Serialize};
|
/// # use serde::{Deserialize, Serialize};
|
||||||
/// # use std::fmt;
|
/// # use std::fmt;
|
||||||
/// # use std::str::FromStr;
|
/// # use std::str::FromStr;
|
||||||
|
@ -175,7 +169,7 @@ where
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// impl genetic_node::GeneticNode for TestState {
|
/// impl genetic_node::GeneticNode for TestState {
|
||||||
/// # fn simulate(&mut self, iterations: u64) -> Result<(), String> {
|
/// # fn simulate(&mut self, iterations: u64) -> Result<(), Error> {
|
||||||
/// # self.score += iterations as f64;
|
/// # self.score += iterations as f64;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
|
@ -184,15 +178,15 @@ where
|
||||||
/// # self.score
|
/// # self.score
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # fn calculate_scores_and_trim(&mut self) -> Result<(), String> {
|
/// # fn calculate_scores_and_trim(&mut self) -> Result<(), Error> {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # fn mutate(&mut self) -> Result<(), String> {
|
/// # fn mutate(&mut self) -> Result<(), Error> {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// fn initialize() -> Result<Box<Self>, String> {
|
/// fn initialize() -> Result<Box<Self>, Error> {
|
||||||
/// Ok(Box::new(TestState { score: 0.0 }))
|
/// Ok(Box::new(TestState { score: 0.0 }))
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
|
@ -212,14 +206,14 @@ where
|
||||||
/// std::fs::remove_file("./temp").expect("Unable to remove file");
|
/// std::fs::remove_file("./temp").expect("Unable to remove file");
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn initialize(file_path: path::PathBuf) -> Result<FileLinked<Self>, String> {
|
pub fn initialize(file_path: path::PathBuf) -> Result<FileLinked<Self>, Error> {
|
||||||
FileLinked::new(
|
Ok(FileLinked::new(
|
||||||
Bracket {
|
Bracket {
|
||||||
tree: btree!(*T::initialize()?),
|
tree: btree!(*T::initialize()?),
|
||||||
iteration_scaling: IterationScaling::default(),
|
iteration_scaling: IterationScaling::default(),
|
||||||
},
|
},
|
||||||
file_path,
|
file_path,
|
||||||
)
|
)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a bracket object, configures it's [`IterationScaling`].
|
/// Given a bracket object, configures it's [`IterationScaling`].
|
||||||
|
@ -227,6 +221,7 @@ where
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// # use gemla::bracket::*;
|
/// # use gemla::bracket::*;
|
||||||
|
/// # use gemla::error::Error;
|
||||||
/// # use serde::{Deserialize, Serialize};
|
/// # use serde::{Deserialize, Serialize};
|
||||||
/// # use std::fmt;
|
/// # use std::fmt;
|
||||||
/// # use std::str::FromStr;
|
/// # use std::str::FromStr;
|
||||||
|
@ -238,14 +233,6 @@ where
|
||||||
/// # pub score: f64,
|
/// # pub score: f64,
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # impl FromStr for TestState {
|
|
||||||
/// # type Err = String;
|
|
||||||
/// #
|
|
||||||
/// # fn from_str(s: &str) -> Result<TestState, Self::Err> {
|
|
||||||
/// # serde_json::from_str(s).map_err(|_| format!("Unable to parse string {}", s))
|
|
||||||
/// # }
|
|
||||||
/// # }
|
|
||||||
/// #
|
|
||||||
/// # impl fmt::Display for TestState {
|
/// # impl fmt::Display for TestState {
|
||||||
/// # fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
/// # fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
/// # write!(f, "{}", self.score)
|
/// # write!(f, "{}", self.score)
|
||||||
|
@ -259,7 +246,7 @@ where
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # impl genetic_node::GeneticNode for TestState {
|
/// # impl genetic_node::GeneticNode for TestState {
|
||||||
/// # fn simulate(&mut self, iterations: u64) -> Result<(), String> {
|
/// # fn simulate(&mut self, iterations: u64) -> Result<(), Error> {
|
||||||
/// # self.score += iterations as f64;
|
/// # self.score += iterations as f64;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
|
@ -268,15 +255,15 @@ where
|
||||||
/// # self.score
|
/// # self.score
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # fn calculate_scores_and_trim(&mut self) -> Result<(), String> {
|
/// # fn calculate_scores_and_trim(&mut self) -> Result<(), Error> {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # fn mutate(&mut self) -> Result<(), String> {
|
/// # fn mutate(&mut self) -> Result<(), Error> {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # fn initialize() -> Result<Box<Self>, String> {
|
/// # fn initialize() -> Result<Box<Self>, Error> {
|
||||||
/// # Ok(Box::new(TestState { score: 0.0 }))
|
/// # Ok(Box::new(TestState { score: 0.0 }))
|
||||||
/// # }
|
/// # }
|
||||||
/// # }
|
/// # }
|
||||||
|
@ -300,7 +287,7 @@ where
|
||||||
|
|
||||||
// Creates a balanced tree with the given `height` that will be used as a branch of the primary tree.
|
// Creates a balanced tree with the given `height` that will be used as a branch of the primary tree.
|
||||||
// This additionally simulates and evaluates nodes in the branch as it is built.
|
// This additionally simulates and evaluates nodes in the branch as it is built.
|
||||||
fn create_new_branch(&self, height: u64) -> Result<tree::Tree<T>, String> {
|
fn create_new_branch(&self, height: u64) -> Result<tree::Tree<T>, Error> {
|
||||||
if height == 1 {
|
if height == 1 {
|
||||||
let mut base_node = btree!(*T::initialize()?);
|
let mut base_node = btree!(*T::initialize()?);
|
||||||
|
|
||||||
|
@ -337,6 +324,7 @@ where
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// # use gemla::bracket::*;
|
/// # use gemla::bracket::*;
|
||||||
|
/// # use gemla::error::Error;
|
||||||
/// # use serde::{Deserialize, Serialize};
|
/// # use serde::{Deserialize, Serialize};
|
||||||
/// # use std::fmt;
|
/// # use std::fmt;
|
||||||
/// # use std::str::FromStr;
|
/// # use std::str::FromStr;
|
||||||
|
@ -348,14 +336,6 @@ where
|
||||||
/// # pub score: f64,
|
/// # pub score: f64,
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # impl FromStr for TestState {
|
|
||||||
/// # type Err = String;
|
|
||||||
/// #
|
|
||||||
/// # fn from_str(s: &str) -> Result<TestState, Self::Err> {
|
|
||||||
/// # serde_json::from_str(s).map_err(|_| format!("Unable to parse string {}", s))
|
|
||||||
/// # }
|
|
||||||
/// # }
|
|
||||||
/// #
|
|
||||||
/// # impl fmt::Display for TestState {
|
/// # impl fmt::Display for TestState {
|
||||||
/// # fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
/// # fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
/// # write!(f, "{}", self.score)
|
/// # write!(f, "{}", self.score)
|
||||||
|
@ -369,7 +349,7 @@ where
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # impl genetic_node::GeneticNode for TestState {
|
/// # impl genetic_node::GeneticNode for TestState {
|
||||||
/// # fn simulate(&mut self, iterations: u64) -> Result<(), String> {
|
/// # fn simulate(&mut self, iterations: u64) -> Result<(), Error> {
|
||||||
/// # self.score += iterations as f64;
|
/// # self.score += iterations as f64;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
|
@ -378,15 +358,15 @@ where
|
||||||
/// # self.score
|
/// # self.score
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # fn calculate_scores_and_trim(&mut self) -> Result<(), String> {
|
/// # fn calculate_scores_and_trim(&mut self) -> Result<(), Error> {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # fn mutate(&mut self) -> Result<(), String> {
|
/// # fn mutate(&mut self) -> Result<(), Error> {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # fn initialize() -> Result<Box<Self>, String> {
|
/// # fn initialize() -> Result<Box<Self>, Error> {
|
||||||
/// # Ok(Box::new(TestState { score: 0.0 }))
|
/// # Ok(Box::new(TestState { score: 0.0 }))
|
||||||
/// # }
|
/// # }
|
||||||
/// # }
|
/// # }
|
||||||
|
@ -407,7 +387,7 @@ where
|
||||||
/// # std::fs::remove_file("./temp").expect("Unable to remove file");
|
/// # std::fs::remove_file("./temp").expect("Unable to remove file");
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn run_simulation_step(&mut self) -> Result<&mut Self, String> {
|
pub fn run_simulation_step(&mut self) -> Result<&mut Self, Error> {
|
||||||
let new_branch = self.create_new_branch(self.tree.height())?;
|
let new_branch = self.create_new_branch(self.tree.height())?;
|
||||||
|
|
||||||
self.tree.val.simulate(match self.iteration_scaling {
|
self.tree.val.simulate(match self.iteration_scaling {
|
||||||
|
@ -448,7 +428,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl genetic_node::GeneticNode for TestState {
|
impl genetic_node::GeneticNode for TestState {
|
||||||
fn simulate(&mut self, iterations: u64) -> Result<(), String> {
|
fn simulate(&mut self, iterations: u64) -> Result<(), Error> {
|
||||||
self.score += iterations as f64;
|
self.score += iterations as f64;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -457,15 +437,15 @@ mod tests {
|
||||||
self.score
|
self.score
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_scores_and_trim(&mut self) -> Result<(), String> {
|
fn calculate_scores_and_trim(&mut self) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mutate(&mut self) -> Result<(), String> {
|
fn mutate(&mut self) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initialize() -> Result<Box<Self>, String> {
|
fn initialize() -> Result<Box<Self>, Error> {
|
||||||
Ok(Box::new(TestState { score: 0.0 }))
|
Ok(Box::new(TestState { score: 0.0 }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
18
gemla/src/error.rs
Normal file
18
gemla/src/error.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
FileLinked(file_linked::Error),
|
||||||
|
#[error(transparent)]
|
||||||
|
Other(#[from] anyhow::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<file_linked::Error> for Error {
|
||||||
|
fn from(error: file_linked::Error) -> Error {
|
||||||
|
match error {
|
||||||
|
file_linked::Error::Other(e) => Error::Other(e),
|
||||||
|
_ => Error::FileLinked(error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,3 +5,4 @@ extern crate regex;
|
||||||
pub mod tree;
|
pub mod tree;
|
||||||
pub mod bracket;
|
pub mod bracket;
|
||||||
pub mod constants;
|
pub mod constants;
|
||||||
|
pub mod error;
|
||||||
|
|
|
@ -16,11 +16,9 @@
|
||||||
//! assert_eq!(t.right.unwrap().val, 3);
|
//! assert_eq!(t.right.unwrap().val, 3);
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use serde::de::DeserializeOwned;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
/// An unbalanced binary tree type where each node has an optional left and right child.
|
/// An unbalanced binary tree type where each node has an optional left and right child.
|
||||||
///
|
///
|
||||||
|
@ -155,17 +153,6 @@ impl<T: fmt::Debug + Serialize> fmt::Debug for Tree<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> FromStr for Tree<T>
|
|
||||||
where
|
|
||||||
T: FromStr + DeserializeOwned,
|
|
||||||
{
|
|
||||||
type Err = String;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
serde_json::from_str(s).map_err(|_| format!("Unable to parse string {}", s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
Loading…
Add table
Reference in a new issue