Partial implementation of node state machine
This commit is contained in:
parent
a32618da37
commit
fdcf0b1e23
5 changed files with 113 additions and 28 deletions
91
gemla/src/bracket/genetic_node.rs
Normal file
91
gemla/src/bracket/genetic_node.rs
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
//! A trait used to interact with the internal state of nodes within the genetic bracket
|
||||||
|
|
||||||
|
use super::genetic_state::GeneticState;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
/// A trait used to interact with the internal state of nodes within the genetic bracket
|
||||||
|
pub trait GeneticNode {
|
||||||
|
/// 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
|
||||||
|
///
|
||||||
|
/// This will be called for every node in a bracket before evaluating it's fitness against other nodes.
|
||||||
|
fn simulate(&mut self, iterations: u64);
|
||||||
|
|
||||||
|
/// Returns a fit score associated with the nodes performance.
|
||||||
|
/// This will be used by a bracket in order to determine the most successful child.
|
||||||
|
fn get_fit_score(&self) -> f64;
|
||||||
|
|
||||||
|
fn calculate_scores_and_trim(&mut self);
|
||||||
|
|
||||||
|
fn mutate(&mut self);
|
||||||
|
|
||||||
|
/// Initializes a new instance of a genetic state.
|
||||||
|
fn initialize() -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub struct GeneticNodeWrapper<T>
|
||||||
|
where
|
||||||
|
T: GeneticNode,
|
||||||
|
{
|
||||||
|
data: Option<T>,
|
||||||
|
state: GeneticState,
|
||||||
|
iteration: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> GeneticNodeWrapper<T>
|
||||||
|
where
|
||||||
|
T: GeneticNode + fmt::Debug,
|
||||||
|
{
|
||||||
|
fn new() -> Self {
|
||||||
|
let mut node = GeneticNodeWrapper {
|
||||||
|
data: None,
|
||||||
|
state: GeneticState::Initialize,
|
||||||
|
iteration: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
node.data = Some(T::initialize());
|
||||||
|
node.state = GeneticState::Simulate;
|
||||||
|
|
||||||
|
node
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_node(&mut self, iterations: u32) -> Result<(), String> {
|
||||||
|
let mut result = Ok(());
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match (self.state, self.data.as_ref()) {
|
||||||
|
(GeneticState::Initialize, _) => {
|
||||||
|
self.iteration = 0;
|
||||||
|
self.data = Some(T::initialize());
|
||||||
|
self.state = GeneticState::Simulate;
|
||||||
|
}
|
||||||
|
(GeneticState::Simulate, Some(_)) => {
|
||||||
|
self.data.as_mut().unwrap().simulate(5);
|
||||||
|
self.state = GeneticState::Score;
|
||||||
|
}
|
||||||
|
(GeneticState::Score, Some(_)) => {
|
||||||
|
self.data.as_mut().unwrap().calculate_scores_and_trim();
|
||||||
|
|
||||||
|
self.state = if self.iteration == iterations {
|
||||||
|
GeneticState::Finish
|
||||||
|
} else {
|
||||||
|
GeneticState::Mutate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(GeneticState::Mutate, Some(_)) => {
|
||||||
|
self.data.as_mut().unwrap().mutate();
|
||||||
|
self.state = GeneticState::Simulate;
|
||||||
|
}
|
||||||
|
(GeneticState::Finish, Some(_)) => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => result = Err(format!("Error processing node {:?}", self.data)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,17 +1,11 @@
|
||||||
//! A trait used to interact with the internal state of nodes within the genetic bracket
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// A trait used to interact with the internal state of nodes within the genetic bracket
|
#[derive(Clone, Debug, Serialize, Deserialize, Copy)]
|
||||||
pub trait GeneticState {
|
#[serde(tag = "enumType", content = "enumContent")]
|
||||||
/// Runs a simulation on the state object in order to guage it's fitness.
|
pub enum GeneticState {
|
||||||
/// - iterations: the number of iterations (learning cycles) that the current state should simulate
|
Initialize,
|
||||||
///
|
Simulate,
|
||||||
/// This will be called for every node in a bracket before evaluating it's fitness against other nodes.
|
Score,
|
||||||
fn run_simulation(&mut self, iterations: u64);
|
Mutate,
|
||||||
|
Finish,
|
||||||
/// Returns a fit score associated with the nodes performance.
|
|
||||||
/// This will be used by a bracket in order to determine the most successful child.
|
|
||||||
fn get_fit_score(&self) -> f64;
|
|
||||||
|
|
||||||
/// Initializes a new instance of a genetic state.
|
|
||||||
fn initialize() -> Self;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
pub mod genetic_node;
|
||||||
pub mod genetic_state;
|
pub mod genetic_state;
|
||||||
|
|
||||||
use super::file_linked::FileLinked;
|
use super::file_linked::FileLinked;
|
||||||
|
@ -9,7 +10,7 @@ use std::fmt;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::string::ToString;
|
use std::string::ToString;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize, Copy)]
|
||||||
#[serde(tag = "enumType", content = "enumContent")]
|
#[serde(tag = "enumType", content = "enumContent")]
|
||||||
pub enum IterationScaling {
|
pub enum IterationScaling {
|
||||||
Linear(u32),
|
Linear(u32),
|
||||||
|
@ -50,7 +51,7 @@ impl<T: fmt::Display + Serialize> fmt::Display for Bracket<T> {
|
||||||
|
|
||||||
impl<T> Bracket<T>
|
impl<T> Bracket<T>
|
||||||
where
|
where
|
||||||
T: genetic_state::GeneticState
|
T: genetic_node::GeneticNode
|
||||||
+ ToString
|
+ ToString
|
||||||
+ FromStr
|
+ FromStr
|
||||||
+ Default
|
+ Default
|
||||||
|
@ -79,7 +80,7 @@ where
|
||||||
if height == 1 {
|
if height == 1 {
|
||||||
let mut base_node = btree!(T::initialize());
|
let mut base_node = btree!(T::initialize());
|
||||||
|
|
||||||
base_node.val.run_simulation(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,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -93,7 +94,7 @@ where
|
||||||
right.val.clone()
|
right.val.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
new_val.run_simulation(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,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -104,7 +105,7 @@ where
|
||||||
pub fn run_simulation_step(&mut self) -> &mut Self {
|
pub fn run_simulation_step(&mut self) -> &mut Self {
|
||||||
let new_branch = self.create_new_branch(self.step + 1);
|
let new_branch = self.create_new_branch(self.step + 1);
|
||||||
|
|
||||||
self.tree.val.run_simulation(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)),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -30,8 +30,8 @@ impl TestState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl bracket::genetic_state::GeneticState for TestState {
|
impl bracket::genetic_node::GeneticNode for TestState {
|
||||||
fn run_simulation(&mut self, iterations: u64) {
|
fn simulate(&mut self, iterations: u64) {
|
||||||
self.score += iterations as f64;
|
self.score += iterations as f64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +39,10 @@ impl bracket::genetic_state::GeneticState for TestState {
|
||||||
self.score
|
self.score
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn calculate_scores_and_trim(&mut self) {}
|
||||||
|
|
||||||
|
fn mutate(&mut self) {}
|
||||||
|
|
||||||
fn initialize() -> Self {
|
fn initialize() -> Self {
|
||||||
TestState { score: 0.0 }
|
TestState { score: 0.0 }
|
||||||
}
|
}
|
||||||
|
@ -66,7 +70,6 @@ fn test_run() {
|
||||||
bracket
|
bracket
|
||||||
.mutate(|b| drop(b.iteration_scaling(bracket::IterationScaling::Linear(2))))
|
.mutate(|b| drop(b.iteration_scaling(bracket::IterationScaling::Linear(2))))
|
||||||
.expect("Failed to set iteration scaling");
|
.expect("Failed to set iteration scaling");
|
||||||
|
|
||||||
for _ in 0..3 {
|
for _ in 0..3 {
|
||||||
bracket
|
bracket
|
||||||
.mutate(|b| drop(b.run_simulation_step()))
|
.mutate(|b| drop(b.run_simulation_step()))
|
||||||
|
|
|
@ -76,11 +76,7 @@ pub struct Tree<T> {
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! btree {
|
macro_rules! btree {
|
||||||
($val:expr, $l:expr, $r:expr) => {
|
($val:expr, $l:expr, $r:expr) => {
|
||||||
$crate::tree::Tree::new(
|
$crate::tree::Tree::new($val, Some(Box::new($l)), Some(Box::new($r)))
|
||||||
$val,
|
|
||||||
Some(Box::new($l)),
|
|
||||||
Some(Box::new($r)),
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
($val:expr, , $r:expr) => {
|
($val:expr, , $r:expr) => {
|
||||||
$crate::tree::Tree::new($val, None, Some(Box::new($r)))
|
$crate::tree::Tree::new($val, None, Some(Box::new($r)))
|
||||||
|
|
Loading…
Add table
Reference in a new issue