diff --git a/rust/adagio/src/eval.rs b/rust/adagio/src/eval.rs new file mode 100644 diff --git a/rust/adagio/src/lib.rs b/rust/adagio/src/lib.rs --- a/rust/adagio/src/lib.rs +++ b/rust/adagio/src/lib.rs @@ -2,30 +2,37 @@ use std::cmp::Ordering; use std::collections::HashMap; -use std::hash::{Hash, Hasher}; +use std::hash::Hash; -use num::{One, Zero}; - +mod node_conversions; mod node_defs; mod node_ordering; -use node_defs::{Container, container, NodeData, Sum, Product, Power, Primitive}; +use node_conversions::Summable; +use node_defs::{Container, container, FancyClone, NodeData, Sum, Product, Power, Primitive}; +/// Negates a Sum node. impl Sum { fn negate(&self, env: &mut Environment) -> Container> { - env.make_sum(!self.minus, &self.constant, &self.terms) + env.make_sum(!self.minus, + self.constant.clone(), + self.terms.iter().cloned()) } } +/// Negates a Product node. impl Product { fn negate(&self, env: &mut Environment) -> Container> { - env.make_product(&-self.coefficient.clone(), &self.powers).unwrap() + env.secret_make_product(-self.coefficient.clone(), self.powers.clone()) } } +/// Convenience type, maps an instance of a type to an Arc containing a clone of the instance. type SelfMap = HashMap>; -struct Environment { +/// A struct that contains canonicalization maps for every node type, as well as maps to +/// memoize partial derivatives. +pub struct Environment { sum: SelfMap>, product: SelfMap>, power: SelfMap>, @@ -37,6 +44,7 @@ } impl Sum { + /// Returns the value of the sum, if every term were 0. fn at_zero(&self) -> T::Constant { if self.minus { -self.constant.clone() @@ -45,108 +53,143 @@ } } + /// Returns a Sum that has the same shape as the sum, but equal to constant at zero. fn adjust_constant(&self, - constant: &T::Constant, + constant: T::Constant, env: &mut Environment) -> Container> { env.make_sum(self.minus, - &(if self.minus { - -constant.clone() - } else { - constant.clone() - }), - &self.terms) + (if self.minus { -constant } else { constant }), + self.terms.iter().cloned()) } + /// Returns the terms of the sum, negated if the sum was negated. fn conditional_negate(&self, env: &mut Environment) -> Vec>> { if self.minus { - env.negate_products(&self.terms) + env.negate_products(self.terms.iter().cloned()) } else { self.terms .iter() .map(|p| p.insert(env)) - .collect::>() + .collect() } } } impl Environment { - fn make_sum(&mut self, - minus: bool, - constant: &T::Constant, - terms: &Vec>>) - -> Container> { + /// Makes a canonicalized Sum from the given components. + pub fn make_sum>(&mut self, + minus: bool, + constant: N, + terms: C) + -> Container> + where C: IntoIterator>> + { + let terms = terms.into_iter().collect::>(); + let mut minus = minus; + let mut constant = constant.into(); if minus && terms.len() == 0 { - self.make_sum(false, &-constant.clone(), terms) - } else { - Sum::new(minus, constant.clone(), terms.clone()).insert(self) + minus = false; + constant = -constant; } + Sum::new(minus, constant, terms).insert(self) + } + + fn secret_make_product>(&mut self, + coefficient: N, + powers: Vec>>) + -> Container> { + Product::new(coefficient.into(), powers).insert(self) } - fn make_product(&mut self, - coefficient: &T::Constant, - powers: &Vec>>) - -> Option>> { - if coefficient.clone() == T::Constant::zero() || powers.len() == 0 { + /// Makes a canonicalized Product from the given components. Because some inputs create + /// invalid products, this returns an Option. + pub fn make_product>(&mut self, + coefficient: N, + powers: C) + -> Option>> + where C: IntoIterator>> + { + let coefficient = coefficient.into(); + if coefficient != 0.into() { + let powers = powers.into_iter().collect::>(); + if powers.len() != 0 { + return Some(self.secret_make_product(coefficient, powers)); + } + } + None + } + + fn secret_make_power>(&mut self, + primitive: Container>, + exponent: N) + -> Container> { + Power::new(exponent.into(), primitive).insert(self) + } + + /// Makes a canonicalized Power from the given components. Because some inputs create + /// invalid powers, this returns an Option. + pub fn make_power>(&mut self, + primitive: Container>, + exponent: N) + -> Option>> { + let exponent = exponent.into(); + if exponent <= 0.into() { None } else { - Some(Product::new(coefficient.clone(), powers.clone()).insert(self)) - } - } - - fn make_power(&mut self, - primitive: &Container>, - exponent: &T::Exponent) - -> Option>> { - if exponent.clone() <= T::Exponent::zero() { - None - } else { - Some(Power::new(exponent.clone(), primitive.clone()).insert(self)) + Some(self.secret_make_power(primitive, exponent)) } } - fn make_system_variable(&mut self, index: &T::SystemVariable) -> Container> { - Primitive::SystemVariable(index.clone()).insert(self) + /// Makes a canonicalized SystemVariable from the given components. + pub fn make_system_variable(&mut self, index: T::SystemVariable) -> Container> { + Primitive::SystemVariable(index).insert(self) } - fn make_parameter(&mut self, name: &T::Parameter) -> Container> { - Primitive::Parameter(name.clone()).insert(self) + /// Makes a canonicalized Parameter from the given components. + pub fn make_parameter(&mut self, name: T::Parameter) -> Container> { + Primitive::Parameter(name).insert(self) } - fn make_input(&mut self, index: &T::Input) -> Container> { - Primitive::Input(index.clone()).insert(self) + /// Makes a canonicalized Input from the given components. + pub fn make_input(&mut self, index: T::Input) -> Container> { + Primitive::Input(index).insert(self) } - fn make_sigmoid(&mut self, minus: bool, sum: &Container>) -> Container> { - if sum.minus || (sum.terms.len() == 0 && sum.constant < T::Constant::zero()) { + /// Makes a canonicalized Sigmoid from the given components. + pub fn make_sigmoid(&mut self, minus: bool, sum: Container>) -> Container> { + if sum.minus || (sum.terms.len() == 0 && sum.constant < 0.into()) { let sum = sum.negate(self); - self.make_sigmoid(!minus, &sum) + self.make_sigmoid(!minus, sum) } else { - Primitive::Sigmoid(minus, sum.clone()).insert(self) + Primitive::Sigmoid(minus, sum).insert(self) } } - fn negate_products(&mut self, - terms: &Vec>>) - -> Vec>> { - terms.iter().map(|p| p.negate(self)).collect::>() - } - fn number(&mut self, number: &T::Constant) -> Container> { - self.make_sum(false, number, &vec![]) + fn negate_products(&mut self, terms: C) -> Vec>> + where C: IntoIterator>> + { + terms.into_iter().map(|p| p.negate(self)).collect() } - fn add, B: Node>(&mut self, - left: &Container, - right: &Container) - -> Container> { + /// Makes a constant Sum. + pub fn number>(&mut self, number: N) -> Container> { + self.make_sum(false, number, vec![]) + } + + /// Adds two Nodes together, producing a Sum. + pub fn add, B: Node>(&mut self, + left: Container, + right: Container) + -> Container> { let left_sum = left.as_sum(self); let right_sum = right.as_sum(self); let constant = left_sum.at_zero() + right_sum.at_zero(); if left_sum.terms.len() == 0 { - return right_sum.adjust_constant(&constant, self); + return right_sum.adjust_constant(constant, self); } if right_sum.terms.len() == 0 { - return left_sum.adjust_constant(&constant, self); + return left_sum.adjust_constant(constant, self); } // Begin port of weird logic @@ -170,8 +213,9 @@ Ordering::Equal => { let coefficient = left_term.coefficient.clone() + right_term.coefficient.clone(); - if coefficient != T::Constant::zero() { - terms.push(self.make_product(&coefficient, &left_term.powers).unwrap()); + match self.make_product(coefficient, left_term.powers.iter().cloned()) { + Some(product) => terms.push(product), + None => (), } left_index += 1; right_index += 1; @@ -182,40 +226,41 @@ } } if left_index == left_length { - terms.extend_from_slice(&right_terms[..].split_at(right_index).1); + terms.extend_from_slice(&right_terms[right_index..]); } if right_index == right_length { - terms.extend_from_slice(&left_terms[..].split_at(left_index).1); + terms.extend_from_slice(&left_terms[left_index..]); } } terms.shrink_to_fit(); // Why not. - if terms.len() == 0 || terms[0].coefficient >= T::Constant::zero() { - self.make_sum(false, &constant, &terms) + if terms.len() == 0 || terms[0].coefficient >= 0.into() { + self.make_sum(false, constant, terms) } else { - let terms = self.negate_products(&terms); - self.make_sum(true, &constant, &terms) + let terms = self.negate_products(terms); + self.make_sum(true, constant, terms) } } - fn multiply, B: Node>(&mut self, - left: &Container, - right: &Container) - -> Container> { + /// Multiplies two Nodes together, producing a Sum. + pub fn multiply, B: Node>(&mut self, + left: Container, + right: Container) + -> Container> { let left_sum = left.as_sum(self); let right_sum = right.as_sum(self); let minus = left_sum.minus != right_sum.minus; let first_constant = left_sum.constant.clone() * right_sum.constant.clone(); - let first = self.make_sum(minus, &first_constant, &vec![]); + let first = self.make_sum(minus, first_constant, vec![]); let mut outer_terms = Vec::with_capacity(right_sum.terms.len()); - if left_sum.constant != T::Constant::zero() { + if left_sum.constant != 0.into() { for term in &right_sum.terms { - let outer_coefficient = left_sum.constant.clone() * term.coefficient.clone(); - let outer_term = self.make_product(&outer_coefficient, &term.powers).unwrap(); - if left_sum.constant < T::Constant::zero() { + let outer_coefficient = left_sum.constant.clone().into() * term.coefficient.clone(); + let outer_term = self.secret_make_product(outer_coefficient, term.powers.clone()); + if left_sum.constant < 0.into() { outer_terms.push(outer_term.negate(self)); } else { outer_terms.push(outer_term); @@ -223,17 +268,16 @@ } } outer_terms.shrink_to_fit(); - let outer = self.make_sum((left_sum.constant < T::Constant::zero()) != minus, - &T::Constant::zero(), - &outer_terms); + let outer = self.make_sum((left_sum.constant < 0.into()) != minus, 0, outer_terms); // Should be possible to turn these into functions. let mut inner_terms = Vec::with_capacity(left_sum.terms.len()); - if right_sum.constant != T::Constant::zero() { + if right_sum.constant != 0.into() { for term in &left_sum.terms { - let inner_coefficient = right_sum.constant.clone() * term.coefficient.clone(); - let inner_term = self.make_product(&inner_coefficient, &term.powers).unwrap(); - if right_sum.constant < T::Constant::zero() { + let inner_coefficient = right_sum.constant.clone().into() * + term.coefficient.clone(); + let inner_term = self.secret_make_product(inner_coefficient, term.powers.clone()); + if right_sum.constant < 0.into() { inner_terms.push(inner_term.negate(self)); } else { inner_terms.push(inner_term); @@ -241,24 +285,22 @@ } } inner_terms.shrink_to_fit(); - let inner = self.make_sum((right_sum.constant < T::Constant::zero()) != minus, - &T::Constant::zero(), - &inner_terms); + let inner = self.make_sum((right_sum.constant < 0.into()) != minus, 0, inner_terms); - let mut last = self.number(&T::Constant::zero()); + let mut last = self.number(0); for left_term in &left_sum.terms { for right_term in &right_sum.terms { - let combined_terms = self._combine_terms(&left_term.powers, &right_term.powers); let last_coefficient = left_term.coefficient.clone() * right_term.coefficient.clone(); - let product = self.make_product(&last_coefficient, &combined_terms).unwrap(); - last = self.add(&last, &product); + let combined_terms = self._combine_terms(&left_term.powers, &right_term.powers); + let product = self.secret_make_product(last_coefficient, combined_terms); + last = self.add(last, product); } } - last = self.add(&last, &inner); - last = self.add(&last, &outer); - self.add(&last, &first) + last = self.add(last, inner); + last = self.add(last, outer); + self.add(last, first) } fn _combine_terms(&mut self, @@ -275,14 +317,14 @@ while left_index < left_length && right_index < right_length { let ref left_power = left[left_index]; let ref right_power = right[right_length]; - match left_power.fuzzy_cmp(&right_power) { + match left_power.fuzzy_cmp(right_power.as_ref()) { Ordering::Less => { powers.push(left_power.clone()); left_index += 1; } Ordering::Equal => { let exponent = left_power.exponent.clone() + right_power.exponent.clone(); - powers.push(self.make_power(&left_power.primitive, &exponent).unwrap()); + powers.push(self.secret_make_power(left_power.primitive.clone(), exponent)); left_index += 1; right_index += 1; } @@ -292,10 +334,10 @@ } } if left_index == left_length { - powers.extend_from_slice(&right[..].split_at(right_index).1); + powers.extend_from_slice(&right[right_index..]); } if right_index == right_length { - powers.extend_from_slice(&left[..].split_at(left_index).1); + powers.extend_from_slice(&left[left_index..]); } } @@ -306,55 +348,37 @@ } } -trait Summable { - fn as_sum(&self, env: &mut Environment) -> Container>; -} - -trait Productable { - fn as_product(&self, env: &mut Environment) -> Container>; -} - -fn _as_sum(productable: &Productable, - env: &mut Environment) - -> Container> { - let product = productable.as_product(env); - if product.coefficient < T::Constant::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) -> Container> { - _as_sum(self, env) - } -} - -impl Summable for Power { - fn as_sum(&self, env: &mut Environment) -> Container> { - _as_sum(self, env) - } -} - -impl Summable for Primitive { - fn as_sum(&self, env: &mut Environment) -> Container> { - _as_sum(self, env) - } -} - -trait Node: Summable { +pub trait Node: Summable + FancyClone { fn partial_derivative(&self, variable: &T::Parameter, env: &mut Environment) - -> Container>; - - fn fancy_clone(&self, env: &mut Environment) -> Self; + -> Container> + where Self: Sized + Clone + Eq + Hash + { + if !self.get_derivative_cache(env).contains_key(&(self.clone(), variable.clone())) { + let key = (self.fancy_clone(env), variable.clone()); + let result = self.derivative_impl(variable, env); + self.get_derivative_cache(env).insert(key, result); + } + match self.get_derivative_cache(env).get(&(self.clone(), variable.clone())) { + Some(derivative) => derivative.clone(), + None => unreachable!(), + } + } fn get_storage<'a>(&self, env: &'a mut Environment) -> &'a mut SelfMap where Self: Sized; + fn get_derivative_cache<'a>(&self, + env: &'a mut Environment) + -> &'a mut HashMap<(Self, T::Parameter), Container>> + where Self: Sized; + + fn derivative_impl(&self, + variable: &T::Parameter, + env: &mut Environment) + -> Container>; + fn insert(&self, env: &mut Environment) -> Container where Self: Sized + Clone + Eq + Hash { @@ -364,173 +388,142 @@ self.get_storage(env).insert(key, container(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) -> Container> { - self.insert(env) + Some(node) => node.clone(), + None => unreachable!(), + } } } impl Node for Sum { - fn partial_derivative(&self, - variable: &T::Parameter, - env: &mut Environment) - -> Container> { - if !env.sum_derivative.contains_key(&(self.clone(), variable.clone())) { - let key = (self.fancy_clone(env), variable.clone()); - let mut result = env.number(&T::Constant::zero()); - for term in &self.terms { - let partial = term.partial_derivative(variable, env); - result = env.add(&result, &partial); - } - if self.minus { - result = result.negate(env); - } - env.sum_derivative.insert(key, result); + fn derivative_impl(&self, + variable: &T::Parameter, + env: &mut Environment) + -> Container> { + let mut result = env.number(0); + for term in &self.terms { + let partial = term.partial_derivative(variable, env); + result = env.add(result, partial); } - match env.sum_derivative.get(&(self.clone(), variable.clone())) { - Some(derivative) => derivative.clone(), - None => unreachable!(), + if self.minus { + result = result.negate(env); } - } - - 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::>(), - } + result } 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) -> Container> { - self.insert(env) + fn get_derivative_cache<'a>(&self, + env: &'a mut Environment) + -> &'a mut HashMap<(Sum, T::Parameter), Container>> + where Self: Sized + { + &mut env.sum_derivative } } impl Node for Product { - fn partial_derivative(&self, - variable: &T::Parameter, - env: &mut Environment) - -> Container> { - if !env.product_derivative.contains_key(&(self.clone(), variable.clone())) { - let key = (self.fancy_clone(env), variable.clone()); - let result = if self.powers.len() == 1 { - self.powers[0].partial_derivative(variable, env) - } else { - let mut result = env.number(&T::Constant::zero()); - unimplemented!() - /*for (index, focus) in self.powers.iter().enumerate() { - let remainder = env.make_product(T::Constant::one(), ) - }*/ - }; - env.product_derivative.insert(key, result); - } - match env.product_derivative.get(&(self.clone(), variable.clone())) { - Some(derivative) => derivative.clone(), - None => unreachable!(), - } - } - - 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 derivative_impl(&self, + variable: &T::Parameter, + env: &mut Environment) + -> Container> { + let coefficient = env.number(self.coefficient.clone()); + let result = if self.powers.len() == 1 { + self.powers[0].partial_derivative(variable, env) + } else { + let mut result = env.number(0); + for (index, focus) in self.powers.iter().enumerate() { + let remainder = env.secret_make_product(1, + self.powers[..index] + .iter() + .chain(self.powers[index + 1..] + .iter()) + .cloned() + .collect()); + let partial_derivative = focus.partial_derivative(variable, env); + let product = env.multiply(remainder, partial_derivative); + result = env.add(result, product); + } + result + }; + env.multiply(result, coefficient) } 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) -> Container> { - let power = self.insert(env); - env.make_product(&T::Constant::one(), &vec![power]).unwrap() + fn get_derivative_cache<'a>(&self, + env: &'a mut Environment) + -> &'a mut HashMap<(Product, T::Parameter), Container>> + where Self: Sized + { + &mut env.product_derivative } } impl Node for Power { - fn partial_derivative(&self, - variable: &T::Parameter, - env: &mut Environment) - -> Container> { - unimplemented!(); - } - - fn fancy_clone(&self, env: &mut Environment) -> Power { - Power { - exponent: self.exponent.clone(), - primitive: self.primitive.insert(env), + fn derivative_impl(&self, + variable: &T::Parameter, + env: &mut Environment) + -> Container> { + let derivative = self.primitive.partial_derivative(variable, env); + if self.exponent == 1.into() { + derivative + } else { + let coefficient = env.number(self.exponent.clone()); + let remainder = env.secret_make_power(self.primitive.clone(), + self.exponent.clone() - 1.into()); + let product = env.multiply(derivative, remainder); + env.multiply(coefficient, product) } } fn get_storage<'a>(&self, env: &'a mut Environment) -> &'a mut SelfMap> { &mut env.power } -} -impl Primitive { - fn as_power(&self, env: &mut Environment) -> Container> { - let primitive = self.insert(env); - env.make_power(&primitive, &T::Exponent::one()).unwrap() - } -} - -impl Productable for Primitive { - fn as_product(&self, env: &mut Environment) -> Container> { - match self { - &Primitive::Sigmoid(true, ref sum) => { - let sigmoid = env.make_sigmoid(false, sum); - let power = sigmoid.as_power(env); - env.make_product(&-T::Constant::one(), &vec![power]).unwrap() - } - _ => { - let power = self.as_power(env); - power.as_product(env) - } - } + fn get_derivative_cache<'a>(&self, + env: &'a mut Environment) + -> &'a mut HashMap<(Power, T::Parameter), Container>> + where Self: Sized + { + &mut env.power_derivative } } impl Node for Primitive { - fn partial_derivative(&self, - variable: &T::Parameter, - env: &mut Environment) - -> Container> { - unimplemented!(); - } - - fn fancy_clone(&self, env: &mut Environment) -> Primitive { + fn derivative_impl(&self, + variable: &T::Parameter, + env: &mut Environment) + -> Container> { match self { - &Primitive::Sigmoid(minus, ref a) => Primitive::Sigmoid(minus, a.insert(env)), - _ => self.clone(), + &Primitive::Sigmoid(minus, ref sum) => { + let derivative = sum.partial_derivative(variable, env); + let self_in_env = self.insert(env); + let self_squared = env.secret_make_power(self_in_env, 2); + let minus_self_squared = env.secret_make_product(-1, vec![self_squared]); + let sum = env.make_sum(minus, 1, vec![minus_self_squared]); + env.multiply(derivative, sum) + } + &Primitive::Parameter(ref p) => env.number(if p == variable { 1 } else { 0 }), + _ => env.number(0), } } fn get_storage<'a>(&self, env: &'a mut Environment) -> &'a mut SelfMap> { &mut env.primitive } + + fn get_derivative_cache<'a> + (&self, + env: &'a mut Environment) + -> &'a mut HashMap<(Primitive, T::Parameter), Container>> + where Self: Sized + { + &mut env.primitive_derivative + } } #[cfg(test)] diff --git a/rust/adagio/src/node_conversions.rs b/rust/adagio/src/node_conversions.rs new file mode 100644 --- /dev/null +++ b/rust/adagio/src/node_conversions.rs @@ -0,0 +1,83 @@ +use {Environment, Node}; + +use node_defs::{Container, NodeData, Sum, Product, Power, Primitive}; + +pub trait Summable { + fn as_sum(&self, env: &mut Environment) -> Container>; +} + +trait Productable { + fn as_product(&self, env: &mut Environment) -> Container>; +} + +fn _as_sum>(productable: &U, + env: &mut Environment) + -> Container> { + let product = productable.as_product(env); + if product.coefficient < 0.into() { + let product = product.as_ref().negate(env); + env.make_sum(true, 0, vec![product]) + } else { + env.make_sum(false, 0, vec![product]) + } +} + +impl Productable for Product { + fn as_product(&self, env: &mut Environment) -> Container> { + self.insert(env) + } +} + +impl Productable for Power { + fn as_product(&self, env: &mut Environment) -> Container> { + let power = self.insert(env); + env.secret_make_product(1, vec![power]) + } +} + +impl Primitive { + fn as_power(&self, env: &mut Environment) -> Container> { + let primitive = self.insert(env); + env.secret_make_power(primitive, 1) + } +} + +impl Productable for Primitive { + fn as_product(&self, env: &mut Environment) -> Container> { + match self { + &Primitive::Sigmoid(true, ref sum) => { + let sigmoid = env.make_sigmoid(false, sum.clone()); + let power = sigmoid.as_power(env); + env.secret_make_product(-1, vec![power]) + } + _ => { + let power = self.as_power(env); + power.as_product(env) + } + } + } +} + +impl Summable for Sum { + fn as_sum(&self, env: &mut Environment) -> Container> { + self.insert(env) + } +} + +impl Summable for Product { + fn as_sum(&self, env: &mut Environment) -> Container> { + _as_sum(self, env) + } +} + +impl Summable for Power { + fn as_sum(&self, env: &mut Environment) -> Container> { + _as_sum(self, env) + } +} + +impl Summable for Primitive { + fn as_sum(&self, env: &mut Environment) -> Container> { + _as_sum(self, env) + } +} diff --git a/rust/adagio/src/node_defs.rs b/rust/adagio/src/node_defs.rs --- a/rust/adagio/src/node_defs.rs +++ b/rust/adagio/src/node_defs.rs @@ -5,6 +5,8 @@ use num::{Integer, Signed}; +use {Environment, Node}; + pub type Container = Arc; pub fn container(data: T) -> Container { @@ -12,23 +14,28 @@ } pub trait NodeData { - type Constant: Hash + Ord + Clone + Signed; - type Exponent: Hash + Clone + Integer; + type Constant: Hash + Ord + Clone + Signed + Into + From; + type Coefficient: Hash + Ord + Clone + Signed + Into + From; + type Exponent: Hash + Clone + Integer + Into + From; type Input: Hash + Ord + Clone; type SystemVariable: Hash + Ord + Clone; type Parameter: Hash + Ord + Clone; } +pub trait FancyClone { + fn fancy_clone(&self, env: &mut Environment) -> Self; +} + pub struct Sum { - pub pre_hash: u64, //I would like these fields to be private if possible. + pre_hash: u64, //I would like these fields to be private if possible. pub minus: bool, pub constant: T::Constant, pub terms: Vec>>, } pub struct Product { - pub pre_hash: u64, //I would like these fields to be private if possible. - pub coefficient: T::Constant, + pre_hash: u64, //I would like these fields to be private if possible. + pub coefficient: T::Coefficient, pub powers: Vec>>, } @@ -145,6 +152,51 @@ } } +impl FancyClone for Sum { + 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(), + } + } +} + +impl FancyClone for Product { + 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(), + } + } +} + +impl FancyClone for Power { + fn fancy_clone(&self, env: &mut Environment) -> Power { + Power { + exponent: self.exponent.clone(), + primitive: self.primitive.insert(env), + } + } +} + +impl FancyClone for Primitive { + fn fancy_clone(&self, env: &mut Environment) -> Primitive { + match self { + &Primitive::Sigmoid(minus, ref a) => Primitive::Sigmoid(minus, a.insert(env)), + _ => self.clone(), + } + } +} + impl Clone for Sum { fn clone(&self) -> Sum { Sum { @@ -202,7 +254,7 @@ } impl Product { - pub fn new(coefficient: T::Constant, powers: Vec>>) -> Product { + pub fn new(coefficient: T::Coefficient, powers: Vec>>) -> Product { let mut s = DefaultHasher::new(); coefficient.hash(&mut s); powers.hash(&mut s); diff --git a/rust/adagio/src/node_ordering.rs b/rust/adagio/src/node_ordering.rs --- a/rust/adagio/src/node_ordering.rs +++ b/rust/adagio/src/node_ordering.rs @@ -1,6 +1,6 @@ use std::cmp::Ordering; -use node_defs::{Container, NodeData, Sum, Product, Power, Primitive}; +use node_defs::{NodeData, Sum, Product, Power, Primitive}; #[derive(Eq, Ord, PartialEq, PartialOrd)] enum PrimitiveType {