Rename derivatives -> factorize; deduplicate

This commit is contained in:
Tiffany Bennett 2016-08-15 21:24:57 -04:00
parent 60b3fef18e
commit e54edca635
5 changed files with 69 additions and 71 deletions

View file

@ -1,58 +0,0 @@
use std::collections::{BTreeMap, BinaryHeap};
use eval::Context;
use std::rc::Rc;
use number::{Number, Unit};
use std::cmp;
#[derive(PartialEq, Eq, Debug)]
pub struct Deriv(pub usize, pub Vec<Rc<String>>);
impl cmp::PartialOrd for Deriv {
fn partial_cmp(&self, other: &Deriv) -> Option<cmp::Ordering> {
Some(self.0.cmp(&other.0).reverse())
}
}
impl cmp::Ord for Deriv {
fn cmp(&self, other: &Deriv) -> cmp::Ordering {
self.partial_cmp(other).unwrap()
}
}
pub fn derivatives(ctx: &Context, value: &Number, aliases: &BTreeMap<Unit, Rc<String>>)
-> BinaryHeap<Deriv> {
if value.1.len() == 0 {
let mut map = BinaryHeap::new();
map.push(Deriv(0, vec![]));
return map;
}
let mut candidates: BinaryHeap<Deriv> = BinaryHeap::new();
let value_score = value.complexity_score();
for (unit, name) in aliases.iter().rev() {
use gmp::mpq::Mpq;
let res = (value / &Number(Mpq::one(), unit.clone())).unwrap();
//if res.1.len() >= value.1.len() {
let score = res.complexity_score();
// we are not making the unit any simpler
if score >= value_score {
continue
}
let res = derivatives(ctx, &res, aliases);
for Deriv(score, mut vec) in res {
vec.push(name.clone());
candidates.push(Deriv(score + 1, vec));
}
let mut next = BinaryHeap::new();
for _ in 0..10 {
if let Some(v) = candidates.pop() {
next.push(v);
} else {
break
}
}
candidates = next;
}
assert!(candidates.len() <= 10);
candidates
}

View file

@ -7,7 +7,7 @@ use date;
use unit_defs::DatePattern;
use std::ops::{Add, Div, Mul, Neg, Sub};
use std::rc::Rc;
use derivatives::{derivatives, Deriv};
use factorize::{factorize, Factors};
#[derive(Clone)]
pub enum Value {
@ -324,7 +324,7 @@ impl Context {
})
}),
Expr::Convert(_, _) => Err(format!("Conversions (->) must be top-level expressions")),
Expr::Derivatives(_) => Err(format!("Derivatives must be top-level expressions")),
Expr::Factorize(_) => Err(format!("Derivatives must be top-level expressions")),
Expr::Equals(_, ref right) => self.eval(right),
Expr::Call(ref name, ref args) => {
let args = try!(args.iter().map(|x| self.eval(x)).collect::<Result<Vec<_>, _>>());
@ -416,7 +416,7 @@ impl Context {
Err(format!("Temperature conversions must not be compound units")),
Expr::Date(_) => Err(format!("Dates are not allowed in the right hand side of conversions")),
Expr::Convert(_, _) => Err(format!("Conversions are not allowed in the right hand of conversions")),
Expr::Derivatives(_) => Err(format!("Derivatives are not allowed in the right hand of conversions")),
Expr::Factorize(_) => Err(format!("Derivatives are not allowed in the right hand of conversions")),
Expr::Error(ref e) => Err(e.clone()),
}
}
@ -561,7 +561,7 @@ impl Context {
(Err(e), _, _) => Err(e),
(_, _, Err(e)) => Err(e),
},
Expr::Derivatives(ref expr) => {
Expr::Factorize(ref expr) => {
let val = try!(self.eval(expr));
let val = match val {
Value::Number(val) => val,
@ -570,18 +570,21 @@ impl Context {
let aliases = self.aliases.iter()
.map(|(a, b)| (a.clone(), Rc::new(b.clone())))
.collect::<BTreeMap<_, _>>();
let derivs = derivatives(self, &val, &aliases);
let derivs = derivs.into_iter().map(|Deriv(_score, names)| {
let results = factorize(self, &val, &aliases);
let mut results = results.into_sorted_vec();
results.dedup();
let results = results.into_iter().map(|Factors(_score, names)| {
let first = names.first().cloned();
names.into_iter().skip(1).fold(
first.map(|x| (**x).to_owned()).unwrap_or(String::new()),
|a, x| format!("{} {}", a, x))
}).collect::<Vec<_>>();
let first = derivs.first().cloned();
let derivs = derivs.into_iter().skip(1).fold(
let first = results.first().cloned();
let len = results.len();
let results = results.into_iter().skip(1).fold(
first.unwrap_or(String::new()),
|a, x| format!("{}; {}", a, x));
Ok(format!("Possible derivatives: {}", derivs))
Ok(format!("Factorizations: {}{}", results, if len < 10 {""} else {"; ..."}))
},
_ => {
let val = try!(self.eval(expr));

53
src/factorize.rs Normal file
View file

@ -0,0 +1,53 @@
use std::collections::{BTreeMap, BinaryHeap};
use eval::Context;
use std::rc::Rc;
use number::{Number, Unit};
use std::cmp;
#[derive(PartialEq, Eq, Debug)]
pub struct Factors(pub usize, pub Vec<Rc<String>>);
impl cmp::PartialOrd for Factors {
fn partial_cmp(&self, other: &Factors) -> Option<cmp::Ordering> {
Some(self.0.cmp(&other.0))
}
}
impl cmp::Ord for Factors {
fn cmp(&self, other: &Factors) -> cmp::Ordering {
self.partial_cmp(other).unwrap()
}
}
pub fn factorize(ctx: &Context, value: &Number, aliases: &BTreeMap<Unit, Rc<String>>)
-> BinaryHeap<Factors> {
if value.1.len() == 0 {
let mut map = BinaryHeap::new();
map.push(Factors(0, vec![]));
return map;
}
let mut candidates: BinaryHeap<Factors> = BinaryHeap::new();
let value_score = value.complexity_score();
for (unit, name) in aliases.iter().rev() {
use gmp::mpq::Mpq;
let res = (value / &Number(Mpq::one(), unit.clone())).unwrap();
//if res.1.len() >= value.1.len() {
let score = res.complexity_score();
// we are not making the unit any simpler
if score >= value_score {
continue
}
let res = factorize(ctx, &res, aliases);
for Factors(score, mut vec) in res {
vec.push(name.clone());
vec.sort();
candidates.push(Factors(score + 1, vec));
}
let mut next = candidates.into_sorted_vec();
next.dedup();
candidates = next.into_iter().take(10).collect();
}
assert!(candidates.len() <= 10);
candidates
}

View file

@ -39,7 +39,7 @@ pub mod unit_defs;
pub mod eval;
pub mod number;
pub mod date;
pub mod derivatives;
pub mod factorize;
pub use number::Number;
pub use eval::{Context, Value};

View file

@ -301,7 +301,7 @@ pub enum Expr {
Equals(Box<Expr>, Box<Expr>),
Suffix(SuffixOp, Box<Expr>),
Call(String, Vec<Expr>),
Derivatives(Box<Expr>),
Factorize(Box<Expr>),
DegC,
DegF,
DegRe,
@ -502,9 +502,9 @@ fn parse_eq(mut iter: &mut Iter) -> Expr {
pub fn parse_expr(mut iter: &mut Iter) -> Expr {
match iter.peek().cloned() {
Some(Token::Ident(ref s)) if s == "derivatives" => {
Some(Token::Ident(ref s)) if s == "factorize" => {
iter.next();
return Expr::Derivatives(Box::new(parse_eq(iter)))
return Expr::Factorize(Box::new(parse_eq(iter)))
},
_ => ()
}