Removing Bracket type
This commit is contained in:
parent
71e613c1c1
commit
fb78ce77ab
2 changed files with 59 additions and 110 deletions
|
@ -53,8 +53,7 @@ pub trait GeneticNode {
|
|||
/// Used externally to wrap a node implementing the [`GeneticNode`] trait. Processes state transitions for the given node as
|
||||
/// well as signal recovery. Transition states are given by [`GeneticState`]
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct GeneticNodeWrapper<T>
|
||||
{
|
||||
pub struct GeneticNodeWrapper<T> {
|
||||
pub data: Option<T>,
|
||||
state: GeneticState,
|
||||
pub iteration: u64,
|
||||
|
|
|
@ -9,70 +9,83 @@ use anyhow::anyhow;
|
|||
use file_linked::FileLinked;
|
||||
use genetic_node::{GeneticNode, GeneticNodeWrapper};
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::Serialize;
|
||||
use std::fmt::Debug;
|
||||
use std::fs::File;
|
||||
use std::io::ErrorKind;
|
||||
use std::mem::replace;
|
||||
use std::mem::swap;
|
||||
use std::path::Path;
|
||||
|
||||
/// As the bracket tree increases in height, `IterationScaling` can be used to configure the number of iterations that
|
||||
/// a node runs for.
|
||||
/// Creates a tournament style bracket for simulating and evaluating nodes of type `T` implementing [`GeneticNode`].
|
||||
/// These nodes are built upwards as a balanced binary tree starting from the bottom. This results in `Bracket` building
|
||||
/// a separate tree of the same height then merging trees together. Evaluating populations between nodes and taking the strongest
|
||||
/// individuals.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// TODO
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(tag = "enumType", content = "enumContent")]
|
||||
pub enum IterationScaling {
|
||||
/// Scales the number of simulations linearly with the height of the bracket tree given by `f(x) = mx` where
|
||||
/// x is the height and m is the linear constant provided.
|
||||
Linear(u64),
|
||||
/// Each node in a bracket is simulated the same number of times.
|
||||
Constant(u64),
|
||||
}
|
||||
|
||||
impl Default for IterationScaling {
|
||||
fn default() -> Self {
|
||||
IterationScaling::Constant(1)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct Bracket<T>
|
||||
{
|
||||
tree: Option<Tree<Option<GeneticNodeWrapper<T>>>>,
|
||||
iteration_scaling: IterationScaling,
|
||||
}
|
||||
|
||||
impl<T> Bracket<T>
|
||||
/// [`GeneticNode`]: genetic_node::GeneticNode
|
||||
pub struct Gemla<T>
|
||||
where
|
||||
T: GeneticNode + Serialize + Debug,
|
||||
T: Serialize,
|
||||
{
|
||||
data: FileLinked<Option<Tree<Option<GeneticNodeWrapper<T>>>>>,
|
||||
}
|
||||
|
||||
impl<T> Gemla<T>
|
||||
where
|
||||
T: GeneticNode + Serialize + DeserializeOwned + Debug,
|
||||
{
|
||||
pub fn new(path: &Path, overwrite: bool) -> Result<Self, Error> {
|
||||
match File::open(path) {
|
||||
Ok(file) => {
|
||||
drop(file);
|
||||
|
||||
Ok(Gemla {
|
||||
data: if overwrite {
|
||||
FileLinked::new(Some(btree!(None)), path)?
|
||||
} else {
|
||||
FileLinked::from_file(path)?
|
||||
},
|
||||
})
|
||||
}
|
||||
Err(error) if error.kind() == ErrorKind::NotFound => Ok(Gemla {
|
||||
data: FileLinked::new(Some(btree!(None)), path)?,
|
||||
}),
|
||||
Err(error) => Err(Error::IO(error)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn simulate(&mut self, steps: u64) -> Result<(), Error> {
|
||||
self.data.mutate(|d| Gemla::increase_height(d, steps))?;
|
||||
|
||||
self.data
|
||||
.mutate(|d| Gemla::process_tree(d.as_mut().unwrap()))??;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn build_empty_tree(size: usize) -> Tree<Option<GeneticNodeWrapper<T>>> {
|
||||
if size <= 1 {
|
||||
btree!(None)
|
||||
} else {
|
||||
btree!(
|
||||
None,
|
||||
Bracket::build_empty_tree(size - 1),
|
||||
Bracket::build_empty_tree(size - 1)
|
||||
Gemla::build_empty_tree(size - 1),
|
||||
Gemla::build_empty_tree(size - 1)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn increase_height(&mut self, amount: u64) {
|
||||
fn increase_height(tree: &mut Option<Tree<Option<GeneticNodeWrapper<T>>>>, amount: u64) {
|
||||
for _ in 0..amount {
|
||||
let height = self.tree.as_ref().unwrap().height();
|
||||
let tree = replace(&mut self.tree, None);
|
||||
drop(replace(
|
||||
&mut self.tree,
|
||||
Some(btree!(
|
||||
let height = tree.as_ref().unwrap().height();
|
||||
let temp = tree.take();
|
||||
swap(
|
||||
tree,
|
||||
&mut Some(btree!(
|
||||
None,
|
||||
tree.unwrap(),
|
||||
Bracket::build_empty_tree(height as usize)
|
||||
temp.unwrap(),
|
||||
Gemla::build_empty_tree(height as usize)
|
||||
)),
|
||||
));
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,8 +93,8 @@ where
|
|||
if tree.val.is_none() {
|
||||
match (&mut tree.left, &mut tree.right) {
|
||||
(Some(l), Some(r)) => {
|
||||
Bracket::process_tree(&mut (*l))?;
|
||||
Bracket::process_tree(&mut (*r))?;
|
||||
Gemla::process_tree(&mut (*l))?;
|
||||
Gemla::process_tree(&mut (*r))?;
|
||||
|
||||
let left_node = (*l).val.as_ref().unwrap().data.as_ref().unwrap();
|
||||
let right_node = (*r).val.as_ref().unwrap().data.as_ref().unwrap();
|
||||
|
@ -102,69 +115,6 @@ where
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process(&mut self) -> Result<(), Error> {
|
||||
Bracket::process_tree(self.tree.as_mut().unwrap())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a tournament style bracket for simulating and evaluating nodes of type `T` implementing [`GeneticNode`].
|
||||
/// These nodes are built upwards as a balanced binary tree starting from the bottom. This results in `Bracket` building
|
||||
/// a separate tree of the same height then merging trees together. Evaluating populations between nodes and taking the strongest
|
||||
/// individuals.
|
||||
///
|
||||
/// [`GeneticNode`]: genetic_node::GeneticNode
|
||||
pub struct Gemla<T>
|
||||
where T: Serialize
|
||||
{
|
||||
data: FileLinked<Bracket<T>>,
|
||||
}
|
||||
|
||||
impl<T> Gemla<T>
|
||||
where
|
||||
T: GeneticNode + Serialize + DeserializeOwned + Debug,
|
||||
{
|
||||
pub fn new(path: &Path, overwrite: bool) -> Result<Self, Error> {
|
||||
match File::open(path) {
|
||||
Ok(file) => {
|
||||
drop(file);
|
||||
|
||||
Ok(Gemla {
|
||||
data: if overwrite {
|
||||
FileLinked::new(
|
||||
Bracket {
|
||||
tree: Some(btree!(None)),
|
||||
iteration_scaling: IterationScaling::default(),
|
||||
},
|
||||
path,
|
||||
)?
|
||||
} else {
|
||||
FileLinked::from_file(path)?
|
||||
},
|
||||
})
|
||||
}
|
||||
Err(error) if error.kind() == ErrorKind::NotFound => Ok(Gemla {
|
||||
data: FileLinked::new(
|
||||
Bracket {
|
||||
tree: Some(btree!(None)),
|
||||
iteration_scaling: IterationScaling::default(),
|
||||
},
|
||||
path,
|
||||
)?,
|
||||
}),
|
||||
Err(error) => Err(Error::IO(error)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn simulate(&mut self, steps: u64) -> Result<(), Error> {
|
||||
self.data.mutate(|b| b.increase_height(steps))?;
|
||||
|
||||
self.data.mutate(|b| b.process())??;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
Loading…
Add table
Reference in a new issue