use variable::Variable;
use std::collections::HashMap;
use std::ops::Add;
use std::ops::Sub;
use std::ops::Mul;
use std::ops::Div;
type VariableValues = HashMap<char, f64>;
#[derive(Clone)]
pub enum Term {
Variable(Variable),
Constant(f64),
Sum(Vec<Term>),
Difference(Vec<Term>),
Product(Vec<Term>),
Quotient(Vec<Term>), Sine(Box<Term>), Cosine(Box<Term>), Tangent(Box<Term>), ArcSine(Box<Term>), ArcCosine(Box<Term>), ArcTangent(Box<Term>) }
impl Term {
pub fn evaluate(&self, values: &VariableValues) -> Result<f64, String> {
self.eval(Some(values))
}
pub fn reduce(&self) -> Result<f64, String> {
self.eval(None)
}
fn eval(&self, values: Option<&VariableValues>) -> Result<f64, String> {
use Term::*;
match *self {
Constant(value) => Ok(value),
Sum(ref terms) => {
let mut sum = 0.0;
for term in terms {
match term.eval(values) {
Ok(value) => {
sum += value;
}, Err(e) => {
return Err(e);
}
};
}
Ok(sum) }, Difference(ref terms) => {
let first = terms[0].eval(values);
if first.is_err() { return first; }
let mut difference = first.unwrap();
for term in terms[1..].iter() {
match term.eval(values) {
Ok(value) => {
difference -= value;
}, Err(e) => {
return Err(e);
}
};
}
Ok(difference)
}, Product(ref terms) => {
let mut product = 1.0;
for term in terms {
match term.eval(values) {
Ok(value) => {
product *= value;
}, Err(e) => {
return Err(e);
}
};
}
Ok(product)
}, Quotient(ref terms) => {
let first = terms[0].eval(values);
if first.is_err() { return first; }
let mut quotient = first.unwrap();
for term in terms[1..].iter() {
match term.eval(values) {
Ok(dividend) => {
if dividend.abs() < 0.00000000000000001 {
return Err("Attempted division by zero.".to_string());
}
quotient /= dividend;
}, Err(e) => {
return Err(e);
}
};
}
Ok(quotient)
}, Variable(ref variable) => {
if let Some(v) = values {
if let Some(value) = v.get(&variable.symbol) {
Ok(*value)
} else {
Err(format!("No value provided for variable {}", variable.symbol))
}
} else {
Err(format!("No variable values provided (looking for {})", variable.symbol))
}
}, Sine(ref term) => {
match term.eval(values) {
Ok(value) => Ok(value.sin()),
Err(e) => Err(e)
}
}, Cosine(ref term) => {
match term.eval(values) {
Ok(value) => Ok(value.cos()),
Err(e) => Err(e)
}
}, ArcSine(ref term) => {
match term.eval(values) {
Ok(value) => Ok(value.asin()),
Err(e) => Err(e)
}
}, ArcCosine(ref term) => {
match term.eval(values) {
Ok(value) => Ok(value.acos()),
Err(e) => Err(e)
}
}, Tangent(ref term) => {
match term.eval(values) {
Ok(value) => Ok(value.tan()),
Err(e) => Err(e)
}
}, ArcTangent(ref term) => {
match term.eval(values) {
Ok(value) => Ok(value.atan()),
Err(e) => Err(e)
}
}
}
}
}
impl<'a, 'b> Add<&'b Term> for &'a Term {
type Output = Term;
fn add(self, another: &'b Term) -> Term {
Term::Sum(vec!(self.clone(), another.clone()))
}
}
impl Add for Term {
type Output = Term;
fn add(self, another: Term) -> Term {
&self + &another
}
}
impl<'a, 'b> Sub<&'b Term> for &'a Term {
type Output = Term;
fn sub(self, another: &'b Term) -> Term {
Term::Difference(vec!(self.clone(), another.clone()))
}
}
impl Sub for Term {
type Output = Term;
fn sub(self, another: Term) -> Term {
&self - &another
}
}
impl<'a, 'b> Mul<&'b Term> for &'a Term {
type Output = Term;
fn mul(self, another: &'b Term) -> Term {
Term::Product(vec!(self.clone(), another.clone()))
}
}
impl Mul for Term {
type Output = Term;
fn mul(self, another: Term) -> Term {
&self * &another
}
}
impl<'a, 'b> Div<&'b Term> for &'a Term {
type Output = Term;
fn div(self, another: &'b Term) -> Term {
Term::Quotient(vec!(self.clone(), another.clone()))
}
}
impl Div for Term {
type Output = Term;
fn div(self, another: Term) -> Term {
&self / &another
}
}