use {
super::{Gene, MutationLine, MutationNode},
crate::DEBUG,
};
#[derive(Debug, Clone, Copy)]
struct MutationNodeStorage {
node_type: MutationNode,
stored_data: Option<f64>,
}
impl Gene {
pub fn largest_output(&self, input: &[i32]) -> usize {
index_of_largest(&self.output(input))
}
pub fn output(&self, input: &[i32]) -> Vec<f64> {
let mut output = Vec::new();
let mut node_values = node_value_calc(&self.node_dna);
if !self.validate() && DEBUG.check {
panic!("Gene is not valid")
};
for (node_index, node_tree) in self.line_dna[0].iter().enumerate() {
for (line_index, line) in node_tree.iter().enumerate() {
node_values[0][line_index].stored_data = Some(
node_values[0][line_index]
.calc_pass_value(line.calc_pass_value(input[node_index].into())),
);
}
}
for (block_index, block) in self.line_dna.iter().enumerate() {
if block_index == 0 {
continue;
}
for (node_index, node_tree) in block.iter().enumerate() {
for (line_index, line) in node_tree.iter().enumerate() {
node_values[block_index][line_index].stored_data = Some(
node_values[block_index][line_index].calc_pass_value(line.calc_pass_value(
match node_values[block_index - 1][node_index].stored_data {
Some(x) => x,
None => panic!("Error 1"),
},
)),
);
}
}
}
for node_values in node_values[node_values.len() - 1].clone() {
output.push(match node_values.stored_data {
Some(x) => x,
None => panic!("Error 2"),
})
}
output
}
}
fn node_value_calc(node_dna: &[Vec<MutationNode>]) -> Vec<Vec<MutationNodeStorage>> {
let mut output = Vec::new();
for row in node_dna {
output.push(node_value_calc_row(&row));
}
output
}
fn node_value_calc_row(row: &[MutationNode]) -> Vec<MutationNodeStorage> {
let mut output = Vec::new();
for node in row {
output.push(convert_mut_node_to_mut_node_store(*node));
}
output
}
fn convert_mut_node_to_mut_node_store(node: MutationNode) -> MutationNodeStorage {
MutationNodeStorage {
node_type: node,
stored_data: None,
}
}
impl MutationLine {
fn calc_pass_value(self, input_value: f64) -> f64 {
match self {
MutationLine::Multiply(x) => input_value * f64::from(x),
MutationLine::Add(x) => input_value + f64::from(x),
MutationLine::Divide(x) => input_value / if x == 0 { 1.0 } else { f64::from(x) },
MutationLine::Pass => input_value,
MutationLine::Reset => 0.0,
}
}
}
impl MutationNodeStorage {
fn calc_pass_value(&self, input_value: f64) -> f64 {
match self.stored_data {
Some(data) => match self.node_type {
MutationNode::Add => data + input_value,
MutationNode::Divide => {
if data == 0.0 {
input_value
} else if input_value == 0.0 {
data
} else {
data / input_value
}
}
MutationNode::Multiply => {
if data == 0.0 {
input_value
} else if input_value == 0.0 {
data
} else {
data * input_value
}
}
},
None => input_value,
}
}
}
fn index_of_largest(arr: &[f64]) -> usize {
let x = arr.iter().enumerate().find(|(_index, bigger_value)| {
arr.iter()
.all(|smaller_value| bigger_value >= &smaller_value)
});
if let Some(y) = x {
y.0
} else {
panic!("Error 6712: should be impossible");
}
}