-use std::marker::PhantomData; +//use std::marker::PhantomData; + +use std::collections::HashMap; use void::Void; -trait Input { +use Node; +use node_defs::{Container, NodeData, Sum, Product, Power, Primitive}; + +/*trait Input { fn get(&self, index: I) -> T where T: Clone; } @@ -25,4 +30,83 @@ type Parameter: Parameter; type ConstantIndex; type Constant: Constant; +}*/ + +struct State { + inputs: Vec, + parameters: Vec, } + +struct Cache { + sums: HashMap>, f64>, + products: HashMap>, f64>, + powers: HashMap>, f64>, + primitives: HashMap>, f64>, +} + +impl Cache { + fn new() -> Cache { + Cache { + sums: HashMap::new(), + products: HashMap::new(), + powers: HashMap::new(), + primitives: HashMap::new(), + } + } +} + +impl> Cache + where T::Constant: Into, + T::Coefficient: Into, + T::Exponent: Into +{ + fn eval_sum(&mut self, state: &State, sum: Container>) -> f64 { + if !self.sums.contains_key(&sum.clone()) { + let mut total = sum.constant.clone().into(); + for product in &sum.terms { + total += self.eval_product(state, product.clone()); + } + if sum.minus { + total = -total; + } + self.sums.insert(sum.clone(), total); + } + self.sums[&sum.clone()] + } + + fn eval_product(&mut self, state: &State, product: Container>) -> f64 { + if !self.products.contains_key(&product.clone()) { + let mut total = product.coefficient.clone().into(); + for power in &product.powers { + total *= self.eval_power(state, power.clone()); + } + self.products.insert(product.clone(), total); + } + self.products[&product.clone()] + } + + fn eval_power(&mut self, state: &State, power: Container>) -> f64 { + if !self.powers.contains_key(&power.clone()) { + let result = self.eval_primitive(state, power.primitive.clone()) + .powi(power.exponent.clone().into()); + self.powers.insert(power.clone(), result); + } + self.powers[&power.clone()] + } + + fn eval_primitive(&mut self, state: &State, primitive: Container>) -> f64 { + if !self.primitives.contains_key(&primitive.clone()) { + let result = match primitive.as_ref() { + &Primitive::Input(index) => state.inputs[index], + &Primitive::Real(_) => unimplemented!(), + &Primitive::Parameter(index) => state.parameters[index], + &Primitive::Sigmoid(minus, ref sum) => { + let tanh = self.eval_sum(state, sum.clone()).tanh(); + if minus { -tanh } else { tanh } + } + }; + self.primitives.insert(primitive.clone(), result); + } + self.primitives[&primitive.clone()] + } +}