Adding self determination of generation length
This commit is contained in:
parent
98803b3700
commit
822df77f62
7 changed files with 1089 additions and 180 deletions
163
analyze_data.py
Normal file
163
analyze_data.py
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
# Re-importing necessary libraries
|
||||||
|
import json
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
from collections import defaultdict
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
# Simplified JSON data for demonstration
|
||||||
|
with open('gemla/round2.json', 'r') as file:
|
||||||
|
simplified_json_data = json.load(file)
|
||||||
|
|
||||||
|
target_node_id = '0c1e64dc-6ddf-4dbb-bf6e-e8218b925194'
|
||||||
|
|
||||||
|
# Function to traverse the tree to find a node id
|
||||||
|
def traverse_left_nodes(node):
|
||||||
|
if node is None:
|
||||||
|
return []
|
||||||
|
|
||||||
|
left_node = node.get("left")
|
||||||
|
if left_node is None:
|
||||||
|
return [node]
|
||||||
|
|
||||||
|
return [node] + traverse_left_nodes(left_node)
|
||||||
|
|
||||||
|
# Function to traverse the tree to find a node id
|
||||||
|
def traverse_right_nodes(node):
|
||||||
|
if node is None:
|
||||||
|
return []
|
||||||
|
|
||||||
|
right_node = node.get("right")
|
||||||
|
left_node = node.get("left")
|
||||||
|
|
||||||
|
if right_node is None and left_node is None:
|
||||||
|
return []
|
||||||
|
elif right_node and left_node:
|
||||||
|
return [right_node] + traverse_right_nodes(left_node)
|
||||||
|
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
# Getting the left graph
|
||||||
|
left_nodes = traverse_left_nodes(simplified_json_data[0])
|
||||||
|
left_nodes.reverse()
|
||||||
|
# print(node)
|
||||||
|
# Print properties available on the first node
|
||||||
|
node = left_nodes[0]
|
||||||
|
# print(node["val"].keys())
|
||||||
|
|
||||||
|
scores = []
|
||||||
|
for node in left_nodes:
|
||||||
|
# print(node)
|
||||||
|
# print(f'Node ID: {node["val"]["id"]}')
|
||||||
|
# print(f'Node scores length: {len(node["val"]["node"]["scores"])}')
|
||||||
|
if node["val"]["node"]:
|
||||||
|
node_scores = node["val"]["node"]["scores"]
|
||||||
|
if node_scores:
|
||||||
|
for score in node_scores:
|
||||||
|
scores.append(score)
|
||||||
|
|
||||||
|
# print(scores)
|
||||||
|
|
||||||
|
scores_values = [list(score_set.values()) for score_set in scores]
|
||||||
|
|
||||||
|
# Set up the figure for plotting on the same graph
|
||||||
|
fig, ax = plt.subplots(figsize=(10, 6))
|
||||||
|
|
||||||
|
# Generate a boxplot for each set of scores on the same graph
|
||||||
|
boxplots = ax.boxplot(scores_values, vert=False, patch_artist=True, labels=[f'Set {i+1}' for i in range(len(scores_values))])
|
||||||
|
|
||||||
|
# Set figure name to node id
|
||||||
|
# fig.canvas.set_window_title('Main node line')
|
||||||
|
|
||||||
|
# Labeling
|
||||||
|
ax.set_xlabel(f'Scores - Main Line')
|
||||||
|
ax.set_ylabel('Score Sets')
|
||||||
|
ax.yaxis.grid(True) # Add horizontal grid lines for clarity
|
||||||
|
|
||||||
|
# Set y-axis labels to be visible
|
||||||
|
ax.set_yticklabels([f'Set {i+1}' for i in range(len(scores_values))])
|
||||||
|
|
||||||
|
# Getting most recent right graph
|
||||||
|
right_nodes = traverse_right_nodes(simplified_json_data[0])
|
||||||
|
target_node_id = None
|
||||||
|
target_node = None
|
||||||
|
if target_node_id:
|
||||||
|
for node in right_nodes:
|
||||||
|
if node["val"]["id"] == target_node_id:
|
||||||
|
target_node = node
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
target_node = right_nodes[1]
|
||||||
|
scores = target_node["val"]["node"]["scores"]
|
||||||
|
|
||||||
|
scores_values = [list(score_set.values()) for score_set in scores]
|
||||||
|
|
||||||
|
# Set up the figure for plotting on the same graph
|
||||||
|
fig, ax = plt.subplots(figsize=(10, 6))
|
||||||
|
|
||||||
|
# Generate a boxplot for each set of scores on the same graph
|
||||||
|
boxplots = ax.boxplot(scores_values, vert=False, patch_artist=True, labels=[f'Set {i+1}' for i in range(len(scores_values))])
|
||||||
|
|
||||||
|
|
||||||
|
# Labeling
|
||||||
|
ax.set_xlabel(f'Scores: {target_node['val']['id']}')
|
||||||
|
ax.set_ylabel('Score Sets')
|
||||||
|
ax.yaxis.grid(True) # Add horizontal grid lines for clarity
|
||||||
|
|
||||||
|
# Set y-axis labels to be visible
|
||||||
|
ax.set_yticklabels([f'Set {i+1}' for i in range(len(scores_values))])
|
||||||
|
|
||||||
|
# Find the highest scoring sets combining all scores and generations
|
||||||
|
scores = []
|
||||||
|
for node in left_nodes:
|
||||||
|
if node["val"]["node"]:
|
||||||
|
node_scores = node["val"]["node"]["scores"]
|
||||||
|
translated_node_scores = []
|
||||||
|
if node_scores:
|
||||||
|
for i in range(len(node_scores)):
|
||||||
|
for (individual, score) in node_scores[i].items():
|
||||||
|
translated_node_scores.append((node["val"]["id"], i, score))
|
||||||
|
|
||||||
|
scores.append(translated_node_scores)
|
||||||
|
|
||||||
|
# Add scores from the right nodes
|
||||||
|
for node in right_nodes:
|
||||||
|
if node["val"]["node"]:
|
||||||
|
node_scores = node["val"]["node"]["scores"]
|
||||||
|
translated_node_scores = []
|
||||||
|
if node_scores:
|
||||||
|
for i in range(len(node_scores)):
|
||||||
|
for (individual, score) in node_scores[i].items():
|
||||||
|
translated_node_scores.append((node["val"]["id"], i, score))
|
||||||
|
|
||||||
|
# Organize scores by individual and then by generation
|
||||||
|
individual_generation_scores = defaultdict(lambda: defaultdict(list))
|
||||||
|
for sublist in scores:
|
||||||
|
for id, generation, score in sublist:
|
||||||
|
individual_generation_scores[id][generation].append(score)
|
||||||
|
|
||||||
|
# Calculate Q3 for each individual's generation
|
||||||
|
individual_generation_q3 = {}
|
||||||
|
for id, generations in individual_generation_scores.items():
|
||||||
|
for gen, scores in generations.items():
|
||||||
|
individual_generation_q3[(id, gen)] = np.percentile(scores, 75)
|
||||||
|
|
||||||
|
# Sort by Q3 value, highest first, and select the top 20
|
||||||
|
top_20_individual_generations = sorted(individual_generation_q3, key=individual_generation_q3.get, reverse=True)[:40]
|
||||||
|
|
||||||
|
# Prepare scores for the top 20 for plotting
|
||||||
|
top_20_scores = [individual_generation_scores[id][gen] for id, gen in top_20_individual_generations]
|
||||||
|
|
||||||
|
# Adjust labels for clarity, indicating both the individual ID and generation
|
||||||
|
labels = [f'{id[:8]}... Gen {gen}' for id, gen in top_20_individual_generations]
|
||||||
|
|
||||||
|
# Generate box and whisker plots for the top 20 individual generations
|
||||||
|
fig, ax = plt.subplots(figsize=(12, 10))
|
||||||
|
ax.boxplot(top_20_scores, vert=False, patch_artist=True, labels=labels)
|
||||||
|
ax.set_xlabel('Scores')
|
||||||
|
ax.set_ylabel('Individual Generation')
|
||||||
|
ax.set_title('Top 20 Individual Generations by Q3 Value')
|
||||||
|
|
||||||
|
# Display the plot
|
||||||
|
plt.show()
|
||||||
|
|
|
@ -47,10 +47,7 @@ fn main() -> Result<()> {
|
||||||
let mut gemla = log_error(
|
let mut gemla = log_error(
|
||||||
Gemla::<FighterNN>::new(
|
Gemla::<FighterNN>::new(
|
||||||
&PathBuf::from(args.file),
|
&PathBuf::from(args.file),
|
||||||
GemlaConfig {
|
GemlaConfig { overwrite: false },
|
||||||
generations_per_height: 5,
|
|
||||||
overwrite: false,
|
|
||||||
},
|
|
||||||
DataFormat::Json,
|
DataFormat::Json,
|
||||||
)
|
)
|
||||||
.await,
|
.await,
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,6 +13,7 @@ const POPULATION_REDUCTION_SIZE: u64 = 3;
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct TestState {
|
pub struct TestState {
|
||||||
pub population: Vec<i64>,
|
pub population: Vec<i64>,
|
||||||
|
pub max_generations: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
@ -26,10 +27,16 @@ impl GeneticNode for TestState {
|
||||||
population.push(thread_rng().gen_range(0..100))
|
population.push(thread_rng().gen_range(0..100))
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Box::new(TestState { population }))
|
Ok(Box::new(TestState {
|
||||||
|
population,
|
||||||
|
max_generations: 10,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn simulate(&mut self, _context: GeneticNodeContext<Self::Context>) -> Result<(), Error> {
|
async fn simulate(
|
||||||
|
&mut self,
|
||||||
|
context: GeneticNodeContext<Self::Context>,
|
||||||
|
) -> Result<bool, Error> {
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
|
|
||||||
self.population = self
|
self.population = self
|
||||||
|
@ -38,7 +45,11 @@ impl GeneticNode for TestState {
|
||||||
.map(|p| p.saturating_add(rng.gen_range(-1..2)))
|
.map(|p| p.saturating_add(rng.gen_range(-1..2)))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Ok(())
|
if context.generation >= self.max_generations {
|
||||||
|
Ok(false)
|
||||||
|
} else {
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn mutate(&mut self, _context: GeneticNodeContext<Self::Context>) -> Result<(), Error> {
|
async fn mutate(&mut self, _context: GeneticNodeContext<Self::Context>) -> Result<(), Error> {
|
||||||
|
@ -93,13 +104,15 @@ impl GeneticNode for TestState {
|
||||||
|
|
||||||
v = v[..(POPULATION_REDUCTION_SIZE as usize)].to_vec();
|
v = v[..(POPULATION_REDUCTION_SIZE as usize)].to_vec();
|
||||||
|
|
||||||
let mut result = TestState { population: v };
|
let mut result = TestState {
|
||||||
|
population: v,
|
||||||
|
max_generations: 10,
|
||||||
|
};
|
||||||
|
|
||||||
result
|
result
|
||||||
.mutate(GeneticNodeContext {
|
.mutate(GeneticNodeContext {
|
||||||
id: *id,
|
id: *id,
|
||||||
generation: 0,
|
generation: 0,
|
||||||
max_generations: 0,
|
|
||||||
gemla_context,
|
gemla_context,
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -118,7 +131,6 @@ mod tests {
|
||||||
let state = TestState::initialize(GeneticNodeContext {
|
let state = TestState::initialize(GeneticNodeContext {
|
||||||
id: Uuid::new_v4(),
|
id: Uuid::new_v4(),
|
||||||
generation: 0,
|
generation: 0,
|
||||||
max_generations: 0,
|
|
||||||
gemla_context: (),
|
gemla_context: (),
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
@ -131,6 +143,7 @@ mod tests {
|
||||||
async fn test_simulate() {
|
async fn test_simulate() {
|
||||||
let mut state = TestState {
|
let mut state = TestState {
|
||||||
population: vec![1, 1, 2, 3],
|
population: vec![1, 1, 2, 3],
|
||||||
|
max_generations: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
let original_population = state.population.clone();
|
let original_population = state.population.clone();
|
||||||
|
@ -139,7 +152,6 @@ mod tests {
|
||||||
.simulate(GeneticNodeContext {
|
.simulate(GeneticNodeContext {
|
||||||
id: Uuid::new_v4(),
|
id: Uuid::new_v4(),
|
||||||
generation: 0,
|
generation: 0,
|
||||||
max_generations: 0,
|
|
||||||
gemla_context: (),
|
gemla_context: (),
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
@ -153,7 +165,6 @@ mod tests {
|
||||||
.simulate(GeneticNodeContext {
|
.simulate(GeneticNodeContext {
|
||||||
id: Uuid::new_v4(),
|
id: Uuid::new_v4(),
|
||||||
generation: 0,
|
generation: 0,
|
||||||
max_generations: 0,
|
|
||||||
gemla_context: (),
|
gemla_context: (),
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
@ -162,7 +173,6 @@ mod tests {
|
||||||
.simulate(GeneticNodeContext {
|
.simulate(GeneticNodeContext {
|
||||||
id: Uuid::new_v4(),
|
id: Uuid::new_v4(),
|
||||||
generation: 0,
|
generation: 0,
|
||||||
max_generations: 0,
|
|
||||||
gemla_context: (),
|
gemla_context: (),
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
@ -177,13 +187,13 @@ mod tests {
|
||||||
async fn test_mutate() {
|
async fn test_mutate() {
|
||||||
let mut state = TestState {
|
let mut state = TestState {
|
||||||
population: vec![4, 3, 3],
|
population: vec![4, 3, 3],
|
||||||
|
max_generations: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
state
|
state
|
||||||
.mutate(GeneticNodeContext {
|
.mutate(GeneticNodeContext {
|
||||||
id: Uuid::new_v4(),
|
id: Uuid::new_v4(),
|
||||||
generation: 0,
|
generation: 0,
|
||||||
max_generations: 0,
|
|
||||||
gemla_context: (),
|
gemla_context: (),
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
@ -196,10 +206,12 @@ mod tests {
|
||||||
async fn test_merge() {
|
async fn test_merge() {
|
||||||
let state1 = TestState {
|
let state1 = TestState {
|
||||||
population: vec![1, 2, 4, 5],
|
population: vec![1, 2, 4, 5],
|
||||||
|
max_generations: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
let state2 = TestState {
|
let state2 = TestState {
|
||||||
population: vec![0, 1, 3, 7],
|
population: vec![0, 1, 3, 7],
|
||||||
|
max_generations: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
let merged_state = TestState::merge(&state1, &state2, &Uuid::new_v4(), ())
|
let merged_state = TestState::merge(&state1, &state2, &Uuid::new_v4(), ())
|
||||||
|
|
|
@ -28,7 +28,6 @@ pub enum GeneticState {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct GeneticNodeContext<S> {
|
pub struct GeneticNodeContext<S> {
|
||||||
pub generation: u64,
|
pub generation: u64,
|
||||||
pub max_generations: u64,
|
|
||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
pub gemla_context: S,
|
pub gemla_context: S,
|
||||||
}
|
}
|
||||||
|
@ -46,7 +45,8 @@ pub trait GeneticNode: Send {
|
||||||
/// TODO
|
/// TODO
|
||||||
async fn initialize(context: GeneticNodeContext<Self::Context>) -> Result<Box<Self>, Error>;
|
async fn initialize(context: GeneticNodeContext<Self::Context>) -> Result<Box<Self>, Error>;
|
||||||
|
|
||||||
async fn simulate(&mut self, context: GeneticNodeContext<Self::Context>) -> Result<(), Error>;
|
async fn simulate(&mut self, context: GeneticNodeContext<Self::Context>)
|
||||||
|
-> Result<bool, 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.
|
||||||
///
|
///
|
||||||
|
@ -72,7 +72,6 @@ where
|
||||||
node: Option<T>,
|
node: Option<T>,
|
||||||
state: GeneticState,
|
state: GeneticState,
|
||||||
generation: u64,
|
generation: u64,
|
||||||
max_generations: u64,
|
|
||||||
id: Uuid,
|
id: Uuid,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +84,6 @@ where
|
||||||
node: None,
|
node: None,
|
||||||
state: GeneticState::Initialize,
|
state: GeneticState::Initialize,
|
||||||
generation: 1,
|
generation: 1,
|
||||||
max_generations: 1,
|
|
||||||
id: Uuid::new_v4(),
|
id: Uuid::new_v4(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,19 +94,17 @@ where
|
||||||
T: GeneticNode + Debug + Send + Clone,
|
T: GeneticNode + Debug + Send + Clone,
|
||||||
T::Context: Send + Sync + Clone + Debug + Serialize + DeserializeOwned + 'static + Default,
|
T::Context: Send + Sync + Clone + Debug + Serialize + DeserializeOwned + 'static + Default,
|
||||||
{
|
{
|
||||||
pub fn new(max_generations: u64) -> Self {
|
pub fn new() -> Self {
|
||||||
GeneticNodeWrapper::<T> {
|
GeneticNodeWrapper::<T> {
|
||||||
max_generations,
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from(data: T, max_generations: u64, id: Uuid) -> Self {
|
pub fn from(data: T, id: Uuid) -> Self {
|
||||||
GeneticNodeWrapper {
|
GeneticNodeWrapper {
|
||||||
node: Some(data),
|
node: Some(data),
|
||||||
state: GeneticState::Simulate,
|
state: GeneticState::Simulate,
|
||||||
generation: 1,
|
generation: 1,
|
||||||
max_generations,
|
|
||||||
id,
|
id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,10 +121,6 @@ where
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn max_generations(&self) -> u64 {
|
|
||||||
self.max_generations
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generation(&self) -> u64 {
|
pub fn generation(&self) -> u64 {
|
||||||
self.generation
|
self.generation
|
||||||
}
|
}
|
||||||
|
@ -140,7 +132,6 @@ where
|
||||||
pub async fn process_node(&mut self, gemla_context: T::Context) -> Result<GeneticState, Error> {
|
pub async fn process_node(&mut self, gemla_context: T::Context) -> Result<GeneticState, Error> {
|
||||||
let context = GeneticNodeContext {
|
let context = GeneticNodeContext {
|
||||||
generation: self.generation,
|
generation: self.generation,
|
||||||
max_generations: self.max_generations,
|
|
||||||
id: self.id,
|
id: self.id,
|
||||||
gemla_context,
|
gemla_context,
|
||||||
};
|
};
|
||||||
|
@ -151,14 +142,15 @@ where
|
||||||
self.state = GeneticState::Simulate;
|
self.state = GeneticState::Simulate;
|
||||||
}
|
}
|
||||||
(GeneticState::Simulate, Some(n)) => {
|
(GeneticState::Simulate, Some(n)) => {
|
||||||
n.simulate(context.clone())
|
let next_generation = n
|
||||||
|
.simulate(context.clone())
|
||||||
.await
|
.await
|
||||||
.with_context(|| format!("Error simulating node: {:?}", self))?;
|
.with_context(|| format!("Error simulating node: {:?}", self))?;
|
||||||
|
|
||||||
self.state = if self.generation >= self.max_generations {
|
self.state = if next_generation {
|
||||||
GeneticState::Finish
|
|
||||||
} else {
|
|
||||||
GeneticState::Mutate
|
GeneticState::Mutate
|
||||||
|
} else {
|
||||||
|
GeneticState::Finish
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
(GeneticState::Mutate, Some(n)) => {
|
(GeneticState::Mutate, Some(n)) => {
|
||||||
|
@ -187,6 +179,7 @@ mod tests {
|
||||||
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
|
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
|
||||||
struct TestState {
|
struct TestState {
|
||||||
pub score: f64,
|
pub score: f64,
|
||||||
|
pub max_generations: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
@ -195,10 +188,14 @@ mod tests {
|
||||||
|
|
||||||
async fn simulate(
|
async fn simulate(
|
||||||
&mut self,
|
&mut self,
|
||||||
_context: GeneticNodeContext<Self::Context>,
|
context: GeneticNodeContext<Self::Context>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<bool, Error> {
|
||||||
self.score += 1.0;
|
self.score += 1.0;
|
||||||
Ok(())
|
if context.generation >= self.max_generations {
|
||||||
|
Ok(false)
|
||||||
|
} else {
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn mutate(
|
async fn mutate(
|
||||||
|
@ -211,7 +208,10 @@ mod tests {
|
||||||
async fn initialize(
|
async fn initialize(
|
||||||
_context: GeneticNodeContext<Self::Context>,
|
_context: GeneticNodeContext<Self::Context>,
|
||||||
) -> Result<Box<TestState>, Error> {
|
) -> Result<Box<TestState>, Error> {
|
||||||
Ok(Box::new(TestState { score: 0.0 }))
|
Ok(Box::new(TestState {
|
||||||
|
score: 0.0,
|
||||||
|
max_generations: 2,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn merge(
|
async fn merge(
|
||||||
|
@ -226,13 +226,12 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_new() -> Result<(), Error> {
|
fn test_new() -> Result<(), Error> {
|
||||||
let genetic_node = GeneticNodeWrapper::<TestState>::new(10);
|
let genetic_node = GeneticNodeWrapper::<TestState>::new();
|
||||||
|
|
||||||
let other_genetic_node = GeneticNodeWrapper::<TestState> {
|
let other_genetic_node = GeneticNodeWrapper::<TestState> {
|
||||||
node: None,
|
node: None,
|
||||||
state: GeneticState::Initialize,
|
state: GeneticState::Initialize,
|
||||||
generation: 1,
|
generation: 1,
|
||||||
max_generations: 10,
|
|
||||||
id: genetic_node.id(),
|
id: genetic_node.id(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -243,15 +242,17 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_from() -> Result<(), Error> {
|
fn test_from() -> Result<(), Error> {
|
||||||
let val = TestState { score: 0.0 };
|
let val = TestState {
|
||||||
|
score: 0.0,
|
||||||
|
max_generations: 10,
|
||||||
|
};
|
||||||
let uuid = Uuid::new_v4();
|
let uuid = Uuid::new_v4();
|
||||||
let genetic_node = GeneticNodeWrapper::from(val.clone(), 10, uuid);
|
let genetic_node = GeneticNodeWrapper::from(val.clone(), uuid);
|
||||||
|
|
||||||
let other_genetic_node = GeneticNodeWrapper::<TestState> {
|
let other_genetic_node = GeneticNodeWrapper::<TestState> {
|
||||||
node: Some(val),
|
node: Some(val),
|
||||||
state: GeneticState::Simulate,
|
state: GeneticState::Simulate,
|
||||||
generation: 1,
|
generation: 1,
|
||||||
max_generations: 10,
|
|
||||||
id: genetic_node.id(),
|
id: genetic_node.id(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -262,9 +263,12 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_as_ref() -> Result<(), Error> {
|
fn test_as_ref() -> Result<(), Error> {
|
||||||
let val = TestState { score: 3.0 };
|
let val = TestState {
|
||||||
|
score: 3.0,
|
||||||
|
max_generations: 10,
|
||||||
|
};
|
||||||
let uuid = Uuid::new_v4();
|
let uuid = Uuid::new_v4();
|
||||||
let genetic_node = GeneticNodeWrapper::from(val.clone(), 10, uuid);
|
let genetic_node = GeneticNodeWrapper::from(val.clone(), uuid);
|
||||||
|
|
||||||
let ref_value = genetic_node.as_ref().unwrap();
|
let ref_value = genetic_node.as_ref().unwrap();
|
||||||
|
|
||||||
|
@ -275,9 +279,12 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_id() -> Result<(), Error> {
|
fn test_id() -> Result<(), Error> {
|
||||||
let val = TestState { score: 3.0 };
|
let val = TestState {
|
||||||
|
score: 3.0,
|
||||||
|
max_generations: 10,
|
||||||
|
};
|
||||||
let uuid = Uuid::new_v4();
|
let uuid = Uuid::new_v4();
|
||||||
let genetic_node = GeneticNodeWrapper::from(val.clone(), 10, uuid);
|
let genetic_node = GeneticNodeWrapper::from(val.clone(), uuid);
|
||||||
|
|
||||||
let id_value = genetic_node.id();
|
let id_value = genetic_node.id();
|
||||||
|
|
||||||
|
@ -286,24 +293,14 @@ mod tests {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_max_generations() -> Result<(), Error> {
|
|
||||||
let val = TestState { score: 3.0 };
|
|
||||||
let uuid = Uuid::new_v4();
|
|
||||||
let genetic_node = GeneticNodeWrapper::from(val.clone(), 10, uuid);
|
|
||||||
|
|
||||||
let max_generations = genetic_node.max_generations();
|
|
||||||
|
|
||||||
assert_eq!(max_generations, 10);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_state() -> Result<(), Error> {
|
fn test_state() -> Result<(), Error> {
|
||||||
let val = TestState { score: 3.0 };
|
let val = TestState {
|
||||||
|
score: 3.0,
|
||||||
|
max_generations: 10,
|
||||||
|
};
|
||||||
let uuid = Uuid::new_v4();
|
let uuid = Uuid::new_v4();
|
||||||
let genetic_node = GeneticNodeWrapper::from(val.clone(), 10, uuid);
|
let genetic_node = GeneticNodeWrapper::from(val.clone(), uuid);
|
||||||
|
|
||||||
let state = genetic_node.state();
|
let state = genetic_node.state();
|
||||||
|
|
||||||
|
@ -314,7 +311,7 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_process_node() -> Result<(), Error> {
|
async fn test_process_node() -> Result<(), Error> {
|
||||||
let mut genetic_node = GeneticNodeWrapper::<TestState>::new(2);
|
let mut genetic_node = GeneticNodeWrapper::<TestState>::new();
|
||||||
|
|
||||||
assert_eq!(genetic_node.state(), GeneticState::Initialize);
|
assert_eq!(genetic_node.state(), GeneticState::Initialize);
|
||||||
assert_eq!(genetic_node.process_node(()).await?, GeneticState::Simulate);
|
assert_eq!(genetic_node.process_node(()).await?, GeneticState::Simulate);
|
||||||
|
|
|
@ -57,7 +57,6 @@ type SimulationTree<T> = Box<Tree<GeneticNodeWrapper<T>>>;
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Serialize, Deserialize, Copy, Clone)]
|
#[derive(Serialize, Deserialize, Copy, Clone)]
|
||||||
pub struct GemlaConfig {
|
pub struct GemlaConfig {
|
||||||
pub generations_per_height: u64,
|
|
||||||
pub overwrite: bool,
|
pub overwrite: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,9 +125,9 @@ where
|
||||||
// Before we can process nodes we must create blank nodes in their place to keep track of which nodes have been processed
|
// Before we can process nodes we must create blank nodes in their place to keep track of which nodes have been processed
|
||||||
// in the tree and which nodes have not.
|
// in the tree and which nodes have not.
|
||||||
self.data
|
self.data
|
||||||
.mutate(|(d, c, _)| {
|
.mutate(|(d, _, _)| {
|
||||||
let mut tree: Option<SimulationTree<T>> =
|
let mut tree: Option<SimulationTree<T>> =
|
||||||
Gemla::increase_height(d.take(), c, steps);
|
Gemla::increase_height(d.take(), steps);
|
||||||
mem::swap(d, &mut tree);
|
mem::swap(d, &mut tree);
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -268,11 +267,7 @@ where
|
||||||
gemla_context.clone(),
|
gemla_context.clone(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
tree.val = GeneticNodeWrapper::from(
|
tree.val = GeneticNodeWrapper::from(*merged_node, tree.val.id());
|
||||||
*merged_node,
|
|
||||||
tree.val.max_generations(),
|
|
||||||
tree.val.id(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(Some(l), Some(r)) => {
|
(Some(l), Some(r)) => {
|
||||||
|
@ -284,11 +279,7 @@ where
|
||||||
trace!("Copying node {}", l.val.id());
|
trace!("Copying node {}", l.val.id());
|
||||||
|
|
||||||
if let Some(left_node) = l.val.as_ref() {
|
if let Some(left_node) = l.val.as_ref() {
|
||||||
GeneticNodeWrapper::from(
|
GeneticNodeWrapper::from(left_node.clone(), tree.val.id());
|
||||||
left_node.clone(),
|
|
||||||
tree.val.max_generations(),
|
|
||||||
tree.val.id(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(Some(l), None) => Gemla::merge_completed_nodes(l, gemla_context.clone()).await?,
|
(Some(l), None) => Gemla::merge_completed_nodes(l, gemla_context.clone()).await?,
|
||||||
|
@ -296,11 +287,7 @@ where
|
||||||
trace!("Copying node {}", r.val.id());
|
trace!("Copying node {}", r.val.id());
|
||||||
|
|
||||||
if let Some(right_node) = r.val.as_ref() {
|
if let Some(right_node) = r.val.as_ref() {
|
||||||
tree.val = GeneticNodeWrapper::from(
|
tree.val = GeneticNodeWrapper::from(right_node.clone(), tree.val.id());
|
||||||
right_node.clone(),
|
|
||||||
tree.val.max_generations(),
|
|
||||||
tree.val.id(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(None, Some(r)) => Gemla::merge_completed_nodes(r, gemla_context.clone()).await?,
|
(None, Some(r)) => Gemla::merge_completed_nodes(r, gemla_context.clone()).await?,
|
||||||
|
@ -353,11 +340,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn increase_height(
|
fn increase_height(tree: Option<SimulationTree<T>>, amount: u64) -> Option<SimulationTree<T>> {
|
||||||
tree: Option<SimulationTree<T>>,
|
|
||||||
config: &GemlaConfig,
|
|
||||||
amount: u64,
|
|
||||||
) -> Option<SimulationTree<T>> {
|
|
||||||
if amount == 0 {
|
if amount == 0 {
|
||||||
tree
|
tree
|
||||||
} else {
|
} else {
|
||||||
|
@ -365,13 +348,11 @@ where
|
||||||
tree.as_ref().map(|t| t.height() as u64).unwrap_or(0) + amount - 1;
|
tree.as_ref().map(|t| t.height() as u64).unwrap_or(0) + amount - 1;
|
||||||
|
|
||||||
Some(Box::new(Tree::new(
|
Some(Box::new(Tree::new(
|
||||||
GeneticNodeWrapper::new(config.generations_per_height),
|
GeneticNodeWrapper::new(),
|
||||||
Gemla::increase_height(tree, config, amount - 1),
|
Gemla::increase_height(tree, amount - 1),
|
||||||
// The right branch height has to equal the left branches total height
|
// The right branch height has to equal the left branches total height
|
||||||
if left_branch_height > 0 {
|
if left_branch_height > 0 {
|
||||||
Some(Box::new(btree!(GeneticNodeWrapper::new(
|
Some(Box::new(btree!(GeneticNodeWrapper::new())))
|
||||||
left_branch_height * config.generations_per_height
|
|
||||||
))))
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
|
@ -446,6 +427,7 @@ mod tests {
|
||||||
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
|
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
|
||||||
struct TestState {
|
struct TestState {
|
||||||
pub score: f64,
|
pub score: f64,
|
||||||
|
pub max_generations: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
@ -454,10 +436,10 @@ mod tests {
|
||||||
|
|
||||||
async fn simulate(
|
async fn simulate(
|
||||||
&mut self,
|
&mut self,
|
||||||
_context: GeneticNodeContext<Self::Context>,
|
context: GeneticNodeContext<Self::Context>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<bool, Error> {
|
||||||
self.score += 1.0;
|
self.score += 1.0;
|
||||||
Ok(())
|
Ok(context.generation < self.max_generations)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn mutate(
|
async fn mutate(
|
||||||
|
@ -470,7 +452,10 @@ mod tests {
|
||||||
async fn initialize(
|
async fn initialize(
|
||||||
_context: GeneticNodeContext<Self::Context>,
|
_context: GeneticNodeContext<Self::Context>,
|
||||||
) -> Result<Box<TestState>, Error> {
|
) -> Result<Box<TestState>, Error> {
|
||||||
Ok(Box::new(TestState { score: 0.0 }))
|
Ok(Box::new(TestState {
|
||||||
|
score: 0.0,
|
||||||
|
max_generations: 10,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn merge(
|
async fn merge(
|
||||||
|
@ -498,10 +483,7 @@ mod tests {
|
||||||
assert!(!path.exists());
|
assert!(!path.exists());
|
||||||
|
|
||||||
// Testing initial creation
|
// Testing initial creation
|
||||||
let mut config = GemlaConfig {
|
let mut config = GemlaConfig { overwrite: true };
|
||||||
generations_per_height: 1,
|
|
||||||
overwrite: true,
|
|
||||||
};
|
|
||||||
let mut gemla = Gemla::<TestState>::new(&p, config, DataFormat::Json).await?;
|
let mut gemla = Gemla::<TestState>::new(&p, config, DataFormat::Json).await?;
|
||||||
|
|
||||||
// Now we can use `.await` within the spawned blocking task.
|
// Now we can use `.await` within the spawned blocking task.
|
||||||
|
@ -559,10 +541,7 @@ mod tests {
|
||||||
CleanUp::new(&path).run(move |p| {
|
CleanUp::new(&path).run(move |p| {
|
||||||
rt.block_on(async {
|
rt.block_on(async {
|
||||||
// Testing initial creation
|
// Testing initial creation
|
||||||
let config = GemlaConfig {
|
let config = GemlaConfig { overwrite: true };
|
||||||
generations_per_height: 10,
|
|
||||||
overwrite: true,
|
|
||||||
};
|
|
||||||
let mut gemla = Gemla::<TestState>::new(&p, config, DataFormat::Json).await?;
|
let mut gemla = Gemla::<TestState>::new(&p, config, DataFormat::Json).await?;
|
||||||
|
|
||||||
// Now we can use `.await` within the spawned blocking task.
|
// Now we can use `.await` within the spawned blocking task.
|
||||||
|
|
Loading…
Add table
Reference in a new issue