Made bracket tree more balanced
This commit is contained in:
parent
8a66fe3ee6
commit
a32618da37
7 changed files with 92 additions and 106 deletions
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
/// 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 GeneticState {
|
pub trait GeneticState {
|
||||||
|
|
||||||
/// 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
|
||||||
///
|
///
|
||||||
|
|
|
@ -3,16 +3,16 @@ pub mod genetic_state;
|
||||||
use super::file_linked::FileLinked;
|
use super::file_linked::FileLinked;
|
||||||
use super::tree;
|
use super::tree;
|
||||||
|
|
||||||
|
use serde::de::DeserializeOwned;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::string::ToString;
|
use std::string::ToString;
|
||||||
use serde::de::DeserializeOwned;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
#[serde(tag = "enumType", content = "enumContent")]
|
#[serde(tag = "enumType", content = "enumContent")]
|
||||||
pub enum IterationScaling {
|
pub enum IterationScaling {
|
||||||
Linear(u32)
|
Linear(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for IterationScaling {
|
impl Default for IterationScaling {
|
||||||
|
@ -23,105 +23,98 @@ impl Default for IterationScaling {
|
||||||
|
|
||||||
impl fmt::Display for IterationScaling {
|
impl fmt::Display for IterationScaling {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{}", serde_json::to_string(self).expect("Unable to deserialize IterationScaling struct"))
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
serde_json::to_string(self).expect("Unable to deserialize IterationScaling struct")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct Bracket<T> {
|
pub struct Bracket<T> {
|
||||||
tree: tree::Tree<T>,
|
tree: tree::Tree<T>,
|
||||||
step: u64,
|
step: u64,
|
||||||
iteration_scaling: IterationScaling
|
iteration_scaling: IterationScaling,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: fmt::Display + Serialize> fmt::Display for Bracket<T> {
|
impl<T: fmt::Display + Serialize> fmt::Display for Bracket<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{}", serde_json::to_string(self).expect("Unable to deserialize Bracket struct"))
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
serde_json::to_string(self).expect("Unable to deserialize Bracket struct")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Bracket<T>
|
impl<T> Bracket<T>
|
||||||
where T: genetic_state::GeneticState + ToString + FromStr + Default + fmt::Display + DeserializeOwned + Serialize + Clone
|
where
|
||||||
|
T: genetic_state::GeneticState
|
||||||
|
+ ToString
|
||||||
|
+ FromStr
|
||||||
|
+ Default
|
||||||
|
+ fmt::Display
|
||||||
|
+ DeserializeOwned
|
||||||
|
+ Serialize
|
||||||
|
+ Clone,
|
||||||
{
|
{
|
||||||
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(),
|
||||||
}
|
},
|
||||||
,file_path)
|
file_path,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iteration_scaling(&mut self, iteration_scaling: IterationScaling) -> &mut Self
|
pub fn iteration_scaling(&mut self, iteration_scaling: IterationScaling) -> &mut Self {
|
||||||
{
|
|
||||||
self.iteration_scaling = iteration_scaling;
|
self.iteration_scaling = iteration_scaling;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_new_branch(&self, height: u64) -> tree::Tree<T>
|
pub fn create_new_branch(&self, height: u64) -> tree::Tree<T> {
|
||||||
{
|
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(
|
base_node.val.run_simulation(match self.iteration_scaling {
|
||||||
match self.iteration_scaling
|
IterationScaling::Linear(x) => (x as u64) * height,
|
||||||
{
|
});
|
||||||
IterationScaling::Linear(x) => (x * (height as u32)).into()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
btree!(base_node.val.clone())
|
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 {
|
|
||||||
right.val.clone()
|
right.val.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
new_val.run_simulation(
|
new_val.run_simulation(match self.iteration_scaling {
|
||||||
match self.iteration_scaling
|
IterationScaling::Linear(x) => (x as u64) * height,
|
||||||
{
|
});
|
||||||
IterationScaling::Linear(x) => (x * (height as u32)).into()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
btree!(new_val, Some(left), Some(right))
|
btree!(new_val, left, right)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
self.tree.val.run_simulation(match self.iteration_scaling {
|
||||||
match self.iteration_scaling
|
IterationScaling::Linear(x) => ((x as u64) * (self.step + 1)),
|
||||||
{
|
});
|
||||||
IterationScaling::Linear(x) => ((x as u64) * (self.step + 1)).into()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
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()
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
self.tree.val.clone()
|
self.tree.val.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
self.tree = btree!(new_val, new_branch, self.tree.clone());
|
||||||
self.tree = btree!(new_val, Some(new_branch), Some(self.tree.clone()));
|
|
||||||
|
|
||||||
self.step += 1;
|
self.step += 1;
|
||||||
|
|
||||||
|
|
|
@ -22,10 +22,7 @@ where
|
||||||
T: ToString,
|
T: ToString,
|
||||||
{
|
{
|
||||||
pub fn new(val: T, path: String) -> Result<FileLinked<T>, String> {
|
pub fn new(val: T, path: String) -> Result<FileLinked<T>, String> {
|
||||||
let result = FileLinked {
|
let result = FileLinked { val, path };
|
||||||
val,
|
|
||||||
path,
|
|
||||||
};
|
|
||||||
|
|
||||||
result.write_data()?;
|
result.write_data()?;
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,19 @@
|
||||||
use super::super::bracket;
|
use super::super::bracket;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::fmt;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::string::ToString;
|
use std::string::ToString;
|
||||||
use std::fmt;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Serialize, Clone)]
|
#[derive(Default, Deserialize, Serialize, Clone)]
|
||||||
struct TestState {
|
struct TestState {
|
||||||
pub score: f64
|
pub score: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for TestState
|
impl FromStr for TestState {
|
||||||
{
|
|
||||||
type Err = String;
|
type Err = String;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<TestState, Self::Err>
|
fn from_str(s: &str) -> Result<TestState, Self::Err> {
|
||||||
{
|
|
||||||
toml::from_str(s).map_err(|_| format!("Unable to parse string {}", s))
|
toml::from_str(s).map_err(|_| format!("Unable to parse string {}", s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,8 +31,7 @@ impl TestState {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl bracket::genetic_state::GeneticState for TestState {
|
impl bracket::genetic_state::GeneticState for TestState {
|
||||||
fn run_simulation(&mut self, iterations: u64)
|
fn run_simulation(&mut self, iterations: u64) {
|
||||||
{
|
|
||||||
self.score += iterations as f64;
|
self.score += iterations as f64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,15 +40,12 @@ impl bracket::genetic_state::GeneticState for TestState {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initialize() -> Self {
|
fn initialize() -> Self {
|
||||||
TestState {
|
TestState { score: 0.0 }
|
||||||
score: 0.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_new() {
|
fn test_new() {
|
||||||
|
|
||||||
let bracket = bracket::Bracket::<TestState>::initialize("./temp".to_string())
|
let bracket = bracket::Bracket::<TestState>::initialize("./temp".to_string())
|
||||||
.expect("Bracket failed to initialize");
|
.expect("Bracket failed to initialize");
|
||||||
|
|
||||||
|
@ -69,11 +63,13 @@ fn test_run() {
|
||||||
let mut bracket = bracket::Bracket::<TestState>::initialize("./temp".to_string())
|
let mut bracket = bracket::Bracket::<TestState>::initialize("./temp".to_string())
|
||||||
.expect("Bracket failed to initialize");
|
.expect("Bracket failed to initialize");
|
||||||
|
|
||||||
bracket.mutate(|b| drop(b.iteration_scaling(bracket::IterationScaling::Linear(2))))
|
bracket
|
||||||
|
.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.mutate(|b| drop(b.run_simulation_step()))
|
bracket
|
||||||
|
.mutate(|b| drop(b.run_simulation_step()))
|
||||||
.expect("Failed to run step");
|
.expect("Failed to run step");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,25 +78,25 @@ fn test_run() {
|
||||||
format!("{{\"tree\":{},\"step\":3,\"iteration_scaling\":{{\"enumType\":\"Linear\",\"enumContent\":2}}}}",
|
format!("{{\"tree\":{},\"step\":3,\"iteration_scaling\":{{\"enumType\":\"Linear\",\"enumContent\":2}}}}",
|
||||||
btree!(
|
btree!(
|
||||||
TestState::new(12.0),
|
TestState::new(12.0),
|
||||||
Some(btree!(
|
btree!(
|
||||||
TestState::new(12.0),
|
TestState::new(12.0),
|
||||||
Some(btree!(TestState::new(6.0),
|
btree!(TestState::new(6.0),
|
||||||
Some(btree!(TestState::new(2.0))),
|
btree!(TestState::new(2.0)),
|
||||||
Some(btree!(TestState::new(2.0))))),
|
btree!(TestState::new(2.0))),
|
||||||
Some(btree!(TestState::new(6.0),
|
btree!(TestState::new(6.0),
|
||||||
Some(btree!(TestState::new(2.0))),
|
btree!(TestState::new(2.0)),
|
||||||
Some(btree!(TestState::new(2.0)))))
|
btree!(TestState::new(2.0)))
|
||||||
)),
|
),
|
||||||
Some(btree!(
|
btree!(
|
||||||
TestState::new(12.0),
|
TestState::new(12.0),
|
||||||
Some(btree!(TestState::new(6.0),
|
btree!(TestState::new(6.0),
|
||||||
Some(btree!(TestState::new(2.0))),
|
btree!(TestState::new(2.0)),
|
||||||
Some(btree!(TestState::new(2.0))))),
|
btree!(TestState::new(2.0))),
|
||||||
Some(btree!(TestState::new(6.0),
|
btree!(TestState::new(6.0),
|
||||||
Some(btree!(TestState::new(2.0))),
|
btree!(TestState::new(2.0)),
|
||||||
Some(btree!(TestState::new(2.0)))))
|
btree!(TestState::new(2.0))))
|
||||||
))
|
)
|
||||||
))
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
std::fs::remove_file("./temp").expect("Unable to remove file");
|
std::fs::remove_file("./temp").expect("Unable to remove file");
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::fs;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mutate() -> Result<(), String> {
|
fn test_mutate() -> Result<(), String> {
|
||||||
let tree = btree!(1, Some(btree!(2)), Some(btree!(3, Some(btree!(4)),)));
|
let tree = btree!(1, btree!(2), btree!(3, btree!(4),));
|
||||||
let mut linked_tree = FileLinked::new(tree, String::from("test.txt"))?;
|
let mut linked_tree = FileLinked::new(tree, String::from("test.txt"))?;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
@ -19,14 +19,14 @@ fn test_new() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fmt() {
|
fn test_fmt() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{}", btree!("foo", Some(btree!("bar")),),),
|
format!("{}", btree!("foo", btree!("bar"),),),
|
||||||
"{\"val\":\"foo\",\"left\":{\"val\":\"bar\",\"left\":null,\"right\":null},\"right\":null}"
|
"{\"val\":\"foo\",\"left\":{\"val\":\"bar\",\"left\":null,\"right\":null},\"right\":null}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fmt_node() {
|
fn test_fmt_node() {
|
||||||
let t = btree!(17, Some(btree!(16)), Some(btree!(12)));
|
let t = btree!(17, btree!(16), btree!(12));
|
||||||
assert_eq!(Tree::fmt_node(&t.left), "16");
|
assert_eq!(Tree::fmt_node(&t.left), "16");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Tree::fmt_node(&Some(Box::new(btree!(btree!("foo"))))),
|
Tree::fmt_node(&Some(Box::new(btree!(btree!("foo"))))),
|
||||||
|
|
|
@ -77,15 +77,16 @@ pub struct Tree<T> {
|
||||||
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,
|
$val,
|
||||||
$l.and_then(|l| Some(Box::new(l))),
|
Some(Box::new($l)),
|
||||||
$r.and_then(|r| Some(Box::new(r))))
|
Some(Box::new($r)),
|
||||||
|
)
|
||||||
};
|
};
|
||||||
($val:expr, , $r:expr) => {
|
($val:expr, , $r:expr) => {
|
||||||
$crate::tree::Tree::new($val, None, $r.and_then(|r| Some(Box::new(r))))
|
$crate::tree::Tree::new($val, None, Some(Box::new($r)))
|
||||||
};
|
};
|
||||||
($val:expr, $l:expr,) => {
|
($val:expr, $l:expr,) => {
|
||||||
$crate::tree::Tree::new($val, $l.and_then(|l| Some(Box::new(l))), None)
|
$crate::tree::Tree::new($val, Some(Box::new($l)), None)
|
||||||
};
|
};
|
||||||
($val:expr) => {
|
($val:expr) => {
|
||||||
$crate::tree::Tree::new($val, None, None)
|
$crate::tree::Tree::new($val, None, None)
|
||||||
|
|
Loading…
Add table
Reference in a new issue