extern crate num; use std::cmp::Ordering; use std::collections::HashMap; use std::collections::hash_map::{DefaultHasher, Entry}; use std::hash::{Hash, Hasher}; use std::sync::Arc; use num::{Integer, One, Signed, Zero}; trait NodeData { type Constant: Hash + Eq + Ord + Clone + Signed; type Coefficient: Hash + Eq + Ord + Clone + Signed; type Exponent: Hash + Clone + Integer; type Input: Hash + Eq + Clone; type SystemVariable: Hash + Eq + Clone; type Parameter: Hash + Eq + Clone; } struct Sum { pre_hash: u64, minus: bool, constant: T::Constant, terms: Vec>>, } impl Sum { fn negate(&self, env: &mut Environment) -> Arc> { env.make_sum(!self.minus, &self.constant, &self.terms) } } struct Product { pre_hash: u64, coefficient: T::Coefficient, powers: Vec>>, } impl Product { fn negate(&self, env: &mut Environment) -> Arc> { env.make_product(&-self.coefficient.clone(), &self.powers).unwrap() } } struct Power { exponent: T::Exponent, primitive: Arc>, } enum Primitive { Input(T::Input), SystemVariable(T::SystemVariable), Parameter(T::Parameter), Sigmoid(bool, Arc>), } type SelfMap = HashMap>; struct Environment { sum: SelfMap>, product: SelfMap>, power: SelfMap>, primitive: SelfMap>, //I could put in the maps for the various partial //derivatives, but that's a //non-vital optimization. } impl Environment { fn make_sum(&mut self, minus: bool, constant: &T::Constant, terms: &Vec>>) -> Arc> { if minus && terms.len() == 0 { self.make_sum(false, &-constant.clone(), terms) } else { Sum::new(minus, constant.clone(), terms.clone()).insert(self) } } fn make_product(&mut self, coefficient: &T::Coefficient, powers: &Vec>>) -> Option>> { if coefficient.clone() == T::Coefficient::zero() || powers.len() == 0 { None } else { Some(Product::new(coefficient.clone(), powers.clone()).insert(self)) } } fn make_power(&mut self, primitive: &Arc>, exponent: &T::Exponent) -> Option>> { if exponent.clone() <= T::Exponent::zero() { None } else { Some(Power::new(exponent.clone(), primitive.clone()).insert(self)) } } fn make_system_variable(&mut self, index: &T::SystemVariable) -> Arc> { Primitive::SystemVariable(index.clone()).insert(self) } fn make_parameter(&mut self, name: &T::Parameter) -> Arc> { Primitive::Parameter(name.clone()).insert(self) } fn make_input(&mut self, index: &T::Input) -> Arc> { Primitive::Input(index.clone()).insert(self) } fn make_sigmoid(&mut self, minus: bool, sum: &Arc>) -> Arc> { if sum.minus || (sum.terms.len() == 0 && sum.constant < T::Constant::zero()) { let sum = sum.negate(self); self.make_sigmoid(!minus, &sum) } else { Primitive::Sigmoid(minus, sum.clone()).insert(self) } } //fn number(&mut self, &T::Constant) } trait Summable { fn as_sum(&self, env: &mut Environment) -> Arc>; } trait Productable { fn as_product(&self, env: &mut Environment) -> Arc>; } fn _as_sum(productable: &Productable, env: &mut Environment) -> Arc> { let product = productable.as_product(env); if product.coefficient < T::Coefficient::zero() { let product = product.negate(env); env.make_sum(true, &T::Constant::zero(), &vec![product]) } else { env.make_sum(false, &T::Constant::zero(), &vec![product]) } } impl Summable for Product { fn as_sum(&self, env: &mut Environment) -> Arc> { _as_sum(self, env) } } impl Summable for Power { fn as_sum(&self, env: &mut Environment) -> Arc> { _as_sum(self, env) } } impl Summable for Primitive { fn as_sum(&self, env: &mut Environment) -> Arc> { _as_sum(self, env) } } trait Node: Summable { fn partial_derivative(&self, variable: &T::Parameter, env: &mut Environment) -> Arc>; fn fancy_clone(&self, env: &mut Environment) -> Self; fn get_storage<'a>(&self, env: &'a mut Environment) -> &'a mut SelfMap where Self: Sized; fn insert(&self, env: &mut Environment) -> Arc where Self: Sized + Clone + Eq + Hash { if !self.get_storage(env).contains_key(self) { let key = self.fancy_clone(env); let value = key.clone(); self.get_storage(env).insert(key, Arc::new(value)); } match self.get_storage(env).get(self) { Some(node) => node, None => unreachable!(), } .clone() } } impl Summable for Sum { fn as_sum(&self, env: &mut Environment) -> Arc> { self.insert(env) } } impl Node for Sum { fn partial_derivative(&self, variable: &T::Parameter, env: &mut Environment) -> Arc> { unimplemented!(); } fn fancy_clone(&self, env: &mut Environment) -> Sum { Sum { pre_hash: self.pre_hash.clone(), minus: self.minus.clone(), constant: self.constant.clone(), terms: self.terms .iter() .map(|p| p.insert(env)) .collect::>(), } } fn get_storage<'a>(&self, env: &'a mut Environment) -> &'a mut SelfMap> { &mut env.sum } } impl Productable for Product { fn as_product(&self, env: &mut Environment) -> Arc> { self.insert(env) } } impl Node for Product { fn partial_derivative(&self, variable: &T::Parameter, env: &mut Environment) -> Arc> { unimplemented!(); } fn fancy_clone(&self, env: &mut Environment) -> Product { Product { pre_hash: self.pre_hash.clone(), coefficient: self.coefficient.clone(), powers: self.powers .iter() .map(|p| p.insert(env)) .collect::>(), } } fn get_storage<'a>(&self, env: &'a mut Environment) -> &'a mut SelfMap> { &mut env.product } } impl Productable for Power { fn as_product(&self, env: &mut Environment) -> Arc> { let power = self.insert(env); env.make_product(&T::Coefficient::one(), &vec![power]).unwrap() } } impl Node for Power { fn partial_derivative(&self, variable: &T::Parameter, env: &mut Environment) -> Arc> { unimplemented!(); } fn fancy_clone(&self, env: &mut Environment) -> Power { Power { exponent: self.exponent.clone(), primitive: self.primitive.insert(env), } } fn get_storage<'a>(&self, env: &'a mut Environment) -> &'a mut SelfMap> { &mut env.power } } impl Primitive { fn as_power(&self, env: &mut Environment) -> Arc> { let primitive = self.insert(env); env.make_power(&primitive, &T::Exponent::one()).unwrap() } } impl Productable for Primitive { fn as_product(&self, env: &mut Environment) -> Arc> { match self { &Primitive::Sigmoid(true, ref sum) => { let sigmoid = env.make_sigmoid(false, sum); let power = sigmoid.as_power(env); env.make_product(&-T::Coefficient::one(), &vec![power]).unwrap() } _ => { let power = self.as_power(env); power.as_product(env) } } } } impl Node for Primitive { fn partial_derivative(&self, variable: &T::Parameter, env: &mut Environment) -> Arc> { unimplemented!(); } fn fancy_clone(&self, env: &mut Environment) -> Primitive { match self { &Primitive::Sigmoid(minus, ref a) => Primitive::Sigmoid(minus, a.insert(env)), _ => self.clone(), } } fn get_storage<'a>(&self, env: &'a mut Environment) -> &'a mut SelfMap> { &mut env.primitive } } impl Sum { fn new(minus: bool, constant: T::Constant, terms: Vec>>) -> Sum { let mut s = DefaultHasher::new(); minus.hash(&mut s); constant.hash(&mut s); terms.hash(&mut s); Sum { pre_hash: s.finish(), minus: minus, constant: constant, terms: terms, } } } impl Product { fn new(coefficient: T::Coefficient, powers: Vec>>) -> Product { let mut s = DefaultHasher::new(); coefficient.hash(&mut s); powers.hash(&mut s); Product { pre_hash: s.finish(), coefficient: coefficient, powers: powers, } } } impl Power { fn new(exponent: T::Exponent, primitive: Arc>) -> Power { Power { exponent: exponent, primitive: primitive, } } } impl Ord for Sum { fn cmp(&self, other: &Sum) -> Ordering { let cmp_result = self.constant.cmp(&other.constant); match cmp_result { Ordering::Equal => { for (self_term, other_term) in self.terms .clone() .into_iter() .zip(other.terms.clone()) { let cmp_result = self_term.cmp(&other_term); match cmp_result { Ordering::Equal => (), _ => return cmp_result, } } let cmp_result = self.terms.len().cmp(&other.terms.len()); match cmp_result { Ordering::Equal => self.minus.cmp(&other.minus), _ => cmp_result, } } _ => cmp_result, } } } impl Ord for Product { fn cmp(&self, other: &Product) -> Ordering { let cmp_result = self.fuzzy_cmp(other); match cmp_result { Ordering::Equal => self.coefficient.cmp(&other.coefficient), _ => cmp_result, } } } impl Product { fn fuzzy_cmp(&self, other: &Product) -> Ordering { for (self_power, other_power) in self.powers .clone() .into_iter() .zip(other.powers.clone()) { let cmp_result = self_power.cmp(&other_power); match cmp_result { Ordering::Equal => (), _ => return cmp_result, } } self.powers.len().cmp(&other.powers.len()) } } impl Ord for Power { fn cmp(&self, other: &Power) -> Ordering { let cmp_result = self.primitive.cmp(&other.primitive); match cmp_result { Ordering::Equal => self.exponent.cmp(&other.exponent), _ => cmp_result, } } } impl Ord for Primitive { fn cmp(&self, other: &Primitive) -> Ordering { unimplemented!() } } impl PartialOrd for Sum { fn partial_cmp(&self, other: &Sum) -> Option { Some(self.cmp(other)) } } impl PartialOrd for Product { fn partial_cmp(&self, other: &Product) -> Option { Some(self.cmp(other)) } } impl PartialOrd for Power { fn partial_cmp(&self, other: &Power) -> Option { Some(self.cmp(other)) } } impl PartialOrd for Primitive { fn partial_cmp(&self, other: &Primitive) -> Option { Some(self.cmp(other)) } } impl Hash for Sum { fn hash(&self, state: &mut H) { self.pre_hash.hash(state); } } impl Hash for Product { fn hash(&self, state: &mut H) { self.pre_hash.hash(state); } } impl Hash for Power { fn hash(&self, state: &mut H) { self.exponent.hash(state); self.primitive.hash(state); } } impl Hash for Primitive { fn hash(&self, state: &mut H) { match self { &Primitive::Input(ref a) => { "Input".hash(state); a.hash(state) } &Primitive::SystemVariable(ref a) => { "SystemVariable".hash(state); a.hash(state) } &Primitive::Parameter(ref a) => { "Parameter".hash(state); a.hash(state) } &Primitive::Sigmoid(minus, ref a) => { "Sigmoid".hash(state); minus.hash(state); a.hash(state) } } } } impl PartialEq for Sum { fn eq(&self, other: &Sum) -> bool { self.minus == other.minus && self.constant == other.constant && self.terms == other.terms } } impl PartialEq for Product { fn eq(&self, other: &Product) -> bool { self.coefficient == other.coefficient && self.powers == other.powers } } impl PartialEq for Power { fn eq(&self, other: &Power) -> bool { self.exponent == other.exponent && self.primitive == other.primitive } } impl PartialEq for Primitive { fn eq(&self, other: &Primitive) -> bool { match (self, other) { (&Primitive::Input(ref a), &Primitive::Input(ref b)) => a == b, (&Primitive::SystemVariable(ref a), &Primitive::SystemVariable(ref b)) => a == b, (&Primitive::Parameter(ref a), &Primitive::Parameter(ref b)) => a == b, (&Primitive::Sigmoid(minus_a, ref a), &Primitive::Sigmoid(minus_b, ref b)) => { minus_a == minus_b && a == b } _ => false, } } } impl Eq for Sum {} impl Eq for Product {} impl Eq for Power {} impl Eq for Primitive {} impl Clone for Sum { fn clone(&self) -> Sum { Sum { pre_hash: self.pre_hash.clone(), minus: self.minus.clone(), constant: self.constant.clone(), terms: self.terms.clone(), } } } impl Clone for Product { fn clone(&self) -> Product { Product { pre_hash: self.pre_hash.clone(), coefficient: self.coefficient.clone(), powers: self.powers.clone(), } } } impl Clone for Power { fn clone(&self) -> Power { Power { exponent: self.exponent.clone(), primitive: self.primitive.clone(), } } } impl Clone for Primitive { fn clone(&self) -> Primitive { match self { &Primitive::Input(ref a) => Primitive::Input(a.clone()), &Primitive::SystemVariable(ref a) => Primitive::SystemVariable(a.clone()), &Primitive::Parameter(ref a) => Primitive::Parameter(a.clone()), &Primitive::Sigmoid(minus, ref a) => Primitive::Sigmoid(minus, a.clone()), } } } #[cfg(test)] mod tests { #[test] fn it_works() {} }