Adding result type to genetic node return values.
This commit is contained in:
parent
fdcf0b1e23
commit
f751e46389
3 changed files with 55 additions and 31 deletions
|
@ -7,24 +7,27 @@ use std::fmt;
|
||||||
|
|
||||||
/// A trait used to interact with the internal state of nodes within the genetic bracket
|
/// A trait used to interact with the internal state of nodes within the genetic bracket
|
||||||
pub trait GeneticNode {
|
pub trait GeneticNode {
|
||||||
|
/// Initializes a new instance of a genetic state.
|
||||||
|
fn initialize() -> Result<Box<Self>, String>;
|
||||||
|
|
||||||
/// Runs a simulation on the state object in order to guage it's fitness.
|
/// Runs a simulation on the state object in order to guage it's fitness.
|
||||||
/// - iterations: the number of iterations (learning cycles) that the current state should simulate
|
/// - iterations: the number of iterations (learning cycles) that the current state should simulate
|
||||||
///
|
///
|
||||||
/// 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.
|
||||||
fn simulate(&mut self, iterations: u64);
|
fn simulate(&mut self, iterations: u64) -> Result<(), String>;
|
||||||
|
|
||||||
/// 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.
|
||||||
fn get_fit_score(&self) -> f64;
|
fn get_fit_score(&self) -> f64;
|
||||||
|
|
||||||
fn calculate_scores_and_trim(&mut self);
|
/// Used when scoring the nodes after simulating and should remove underperforming children.
|
||||||
|
fn calculate_scores_and_trim(&mut self) -> Result<(), String>;
|
||||||
|
|
||||||
fn mutate(&mut self);
|
/// Mutates members in a population and/or crossbreeds them to produce new offspring.
|
||||||
|
fn mutate(&mut self) -> Result<(), String>;
|
||||||
/// Initializes a new instance of a genetic state.
|
|
||||||
fn initialize() -> Self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used externally to wrap a node implementing the GeneticNode trait. Processes state transitions for the given node as well as signal recovery.
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct GeneticNodeWrapper<T>
|
pub struct GeneticNodeWrapper<T>
|
||||||
where
|
where
|
||||||
|
@ -39,17 +42,19 @@ impl<T> GeneticNodeWrapper<T>
|
||||||
where
|
where
|
||||||
T: GeneticNode + fmt::Debug,
|
T: GeneticNode + fmt::Debug,
|
||||||
{
|
{
|
||||||
fn new() -> Self {
|
/// Initializes a wrapper around a GeneticNode
|
||||||
|
fn new() -> Result<Self, String> {
|
||||||
let mut node = GeneticNodeWrapper {
|
let mut node = GeneticNodeWrapper {
|
||||||
data: None,
|
data: None,
|
||||||
state: GeneticState::Initialize,
|
state: GeneticState::Initialize,
|
||||||
iteration: 0,
|
iteration: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
node.data = Some(T::initialize());
|
let new_data = T::initialize()?;
|
||||||
|
node.data = Some(*new_data);
|
||||||
node.state = GeneticState::Simulate;
|
node.state = GeneticState::Simulate;
|
||||||
|
|
||||||
node
|
Ok(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_node(&mut self, iterations: u32) -> Result<(), String> {
|
fn process_node(&mut self, iterations: u32) -> Result<(), String> {
|
||||||
|
@ -59,15 +64,25 @@ where
|
||||||
match (self.state, self.data.as_ref()) {
|
match (self.state, self.data.as_ref()) {
|
||||||
(GeneticState::Initialize, _) => {
|
(GeneticState::Initialize, _) => {
|
||||||
self.iteration = 0;
|
self.iteration = 0;
|
||||||
self.data = Some(T::initialize());
|
let new_data =
|
||||||
|
T::initialize().map_err(|e| format!("Error initializing node: {}", e))?;
|
||||||
|
self.data = Some(*new_data);
|
||||||
self.state = GeneticState::Simulate;
|
self.state = GeneticState::Simulate;
|
||||||
}
|
}
|
||||||
(GeneticState::Simulate, Some(_)) => {
|
(GeneticState::Simulate, Some(_)) => {
|
||||||
self.data.as_mut().unwrap().simulate(5);
|
self.data
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.simulate(5)
|
||||||
|
.map_err(|e| format!("Error simulating node: {}", e))?;
|
||||||
self.state = GeneticState::Score;
|
self.state = GeneticState::Score;
|
||||||
}
|
}
|
||||||
(GeneticState::Score, Some(_)) => {
|
(GeneticState::Score, Some(_)) => {
|
||||||
self.data.as_mut().unwrap().calculate_scores_and_trim();
|
self.data
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.calculate_scores_and_trim()
|
||||||
|
.map_err(|e| format!("Error scoring and trimming node: {}", e))?;
|
||||||
|
|
||||||
self.state = if self.iteration == iterations {
|
self.state = if self.iteration == iterations {
|
||||||
GeneticState::Finish
|
GeneticState::Finish
|
||||||
|
@ -76,7 +91,11 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(GeneticState::Mutate, Some(_)) => {
|
(GeneticState::Mutate, Some(_)) => {
|
||||||
self.data.as_mut().unwrap().mutate();
|
self.data
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.mutate()
|
||||||
|
.map_err(|e| format!("Error mutating node: {}", e))?;
|
||||||
self.state = GeneticState::Simulate;
|
self.state = GeneticState::Simulate;
|
||||||
}
|
}
|
||||||
(GeneticState::Finish, Some(_)) => {
|
(GeneticState::Finish, Some(_)) => {
|
||||||
|
|
|
@ -63,7 +63,7 @@ where
|
||||||
pub fn initialize(file_path: String) -> Result<FileLinked<Self>, String> {
|
pub fn initialize(file_path: String) -> Result<FileLinked<Self>, String> {
|
||||||
FileLinked::new(
|
FileLinked::new(
|
||||||
Bracket {
|
Bracket {
|
||||||
tree: btree!(T::initialize()),
|
tree: btree!(*T::initialize()?),
|
||||||
step: 0,
|
step: 0,
|
||||||
iteration_scaling: IterationScaling::default(),
|
iteration_scaling: IterationScaling::default(),
|
||||||
},
|
},
|
||||||
|
@ -76,18 +76,18 @@ where
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_new_branch(&self, height: u64) -> tree::Tree<T> {
|
pub fn create_new_branch(&self, height: u64) -> Result<tree::Tree<T>, String> {
|
||||||
if height == 1 {
|
if height == 1 {
|
||||||
let mut base_node = btree!(T::initialize());
|
let mut base_node = btree!(*T::initialize()?);
|
||||||
|
|
||||||
base_node.val.simulate(match self.iteration_scaling {
|
base_node.val.simulate(match self.iteration_scaling {
|
||||||
IterationScaling::Linear(x) => (x as u64) * height,
|
IterationScaling::Linear(x) => (x as u64) * height,
|
||||||
});
|
})?;
|
||||||
|
|
||||||
btree!(base_node.val)
|
Ok(btree!(base_node.val))
|
||||||
} else {
|
} else {
|
||||||
let left = self.create_new_branch(height - 1);
|
let left = self.create_new_branch(height - 1)?;
|
||||||
let right = self.create_new_branch(height - 1);
|
let right = self.create_new_branch(height - 1)?;
|
||||||
let mut new_val = if left.val.get_fit_score() >= right.val.get_fit_score() {
|
let mut new_val = if left.val.get_fit_score() >= right.val.get_fit_score() {
|
||||||
left.val.clone()
|
left.val.clone()
|
||||||
} else {
|
} else {
|
||||||
|
@ -96,18 +96,18 @@ where
|
||||||
|
|
||||||
new_val.simulate(match self.iteration_scaling {
|
new_val.simulate(match self.iteration_scaling {
|
||||||
IterationScaling::Linear(x) => (x as u64) * height,
|
IterationScaling::Linear(x) => (x as u64) * height,
|
||||||
});
|
})?;
|
||||||
|
|
||||||
btree!(new_val, left, right)
|
Ok(btree!(new_val, left, right))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_simulation_step(&mut self) -> &mut Self {
|
pub fn run_simulation_step(&mut self) -> Result<&mut Self, String> {
|
||||||
let new_branch = self.create_new_branch(self.step + 1);
|
let new_branch = self.create_new_branch(self.step + 1)?;
|
||||||
|
|
||||||
self.tree.val.simulate(match self.iteration_scaling {
|
self.tree.val.simulate(match self.iteration_scaling {
|
||||||
IterationScaling::Linear(x) => ((x as u64) * (self.step + 1)),
|
IterationScaling::Linear(x) => ((x as u64) * (self.step + 1)),
|
||||||
});
|
})?;
|
||||||
|
|
||||||
let new_val = if new_branch.val.get_fit_score() >= self.tree.val.get_fit_score() {
|
let new_val = if new_branch.val.get_fit_score() >= self.tree.val.get_fit_score() {
|
||||||
new_branch.val.clone()
|
new_branch.val.clone()
|
||||||
|
@ -119,6 +119,6 @@ where
|
||||||
|
|
||||||
self.step += 1;
|
self.step += 1;
|
||||||
|
|
||||||
self
|
Ok(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,20 +31,25 @@ impl TestState {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl bracket::genetic_node::GeneticNode for TestState {
|
impl bracket::genetic_node::GeneticNode for TestState {
|
||||||
fn simulate(&mut self, iterations: u64) {
|
fn simulate(&mut self, iterations: u64) -> Result<(), String> {
|
||||||
self.score += iterations as f64;
|
self.score += iterations as f64;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_fit_score(&self) -> f64 {
|
fn get_fit_score(&self) -> f64 {
|
||||||
self.score
|
self.score
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_scores_and_trim(&mut self) {}
|
fn calculate_scores_and_trim(&mut self) -> Result<(), String> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn mutate(&mut self) {}
|
fn mutate(&mut self) -> Result<(), String> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn initialize() -> Self {
|
fn initialize() -> Result<Box<Self>, String> {
|
||||||
TestState { score: 0.0 }
|
Ok(Box::new(TestState { score: 0.0 }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue