|
|
|
@ -1,8 +1,10 @@
@@ -1,8 +1,10 @@
|
|
|
|
|
use std::borrow::{Borrow, Cow}; |
|
|
|
|
use std::collections::btree_map::Entry; |
|
|
|
|
use std::collections::BTreeMap; |
|
|
|
|
use std::fmt; |
|
|
|
|
|
|
|
|
|
use super::expr::Expr; |
|
|
|
|
use super::unknown::*; |
|
|
|
|
use super::Scalar; |
|
|
|
|
use crate::math::expr::Expr::*; |
|
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq)] |
|
|
|
@ -43,21 +45,23 @@ impl Eqn {
@@ -43,21 +45,23 @@ impl Eqn {
|
|
|
|
|
Eqn(self.0.simplify(), self.1.simplify()) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn solve(&self, for_u: Unknown) -> Option<Expr> { |
|
|
|
|
pub fn substitute(self, eqns: &Eqns) -> Eqn { |
|
|
|
|
Self(self.0.substitute(eqns), self.1.substitute(eqns)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn solve_eqn(eqn: &Eqn, for_u: Unknown) -> Option<Expr> { |
|
|
|
|
use Expr::*; |
|
|
|
|
if !self.has_unknown(for_u) { |
|
|
|
|
if !eqn.has_unknown(for_u) { |
|
|
|
|
return None; |
|
|
|
|
} |
|
|
|
|
trace!("solve: {}", self); |
|
|
|
|
let (l, r) = ( |
|
|
|
|
self.0 |
|
|
|
|
.clone().distribute() |
|
|
|
|
.simplify(), |
|
|
|
|
self.1 |
|
|
|
|
.clone().distribute() |
|
|
|
|
.simplify(), |
|
|
|
|
); |
|
|
|
|
let (mut l, mut r) = ord_by_unkn(l, r, for_u)?; |
|
|
|
|
trace!("solve: {}", eqn); |
|
|
|
|
let (mut l, mut r) = (eqn.0.clone().distribute().simplify(), eqn.1.clone().distribute().simplify()); |
|
|
|
|
if l == r { |
|
|
|
|
return None |
|
|
|
|
}; |
|
|
|
|
l = (l - r).distribute().simplify(); |
|
|
|
|
r = Expr::Const(0.); |
|
|
|
|
loop { |
|
|
|
|
trace!("solve iter: {} == {}", l, r); |
|
|
|
|
let (new_l, new_r): (Expr, Expr) = match l { |
|
|
|
@ -69,8 +73,12 @@ impl Eqn {
@@ -69,8 +73,12 @@ impl Eqn {
|
|
|
|
|
return None; |
|
|
|
|
} |
|
|
|
|
( |
|
|
|
|
Sum(us).simplify(), |
|
|
|
|
Expr::new_minus(r, Sum(not_us)).simplify(), |
|
|
|
|
us.into_iter().next().unwrap(), |
|
|
|
|
if not_us.len() == 0 { |
|
|
|
|
r |
|
|
|
|
} else { |
|
|
|
|
Expr::new_minus(r, Sum(not_us)) |
|
|
|
|
}, |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
Product(es) => { |
|
|
|
@ -80,8 +88,12 @@ impl Eqn {
@@ -80,8 +88,12 @@ impl Eqn {
|
|
|
|
|
return None; |
|
|
|
|
} |
|
|
|
|
( |
|
|
|
|
Product(us).simplify(), |
|
|
|
|
Expr::new_div(r, Product(not_us)).simplify(), |
|
|
|
|
us.into_iter().next().unwrap(), |
|
|
|
|
if not_us.len() == 0 { |
|
|
|
|
r |
|
|
|
|
} else { |
|
|
|
|
Expr::new_div(r, Product(not_us)) |
|
|
|
|
}, |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
Neg(v) => (*v, Expr::new_neg(r)), |
|
|
|
@ -96,9 +108,8 @@ impl Eqn {
@@ -96,9 +108,8 @@ impl Eqn {
|
|
|
|
|
} |
|
|
|
|
Const(_) => return None, |
|
|
|
|
}; |
|
|
|
|
l = new_l; |
|
|
|
|
r = new_r; |
|
|
|
|
} |
|
|
|
|
l = new_l.distribute().simplify(); |
|
|
|
|
r = new_r.distribute().simplify(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -109,9 +120,9 @@ impl fmt::Display for Eqn {
@@ -109,9 +120,9 @@ impl fmt::Display for Eqn {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq)] |
|
|
|
|
pub struct Eqns(pub Vec<Eqn>); |
|
|
|
|
pub struct Eqns<'a>(pub Cow<'a, [Eqn]>); |
|
|
|
|
|
|
|
|
|
impl Unknowns for Eqns { |
|
|
|
|
impl<'a> Unknowns for Eqns<'a> { |
|
|
|
|
fn unknowns(&self) -> UnknownSet { |
|
|
|
|
self.0.iter().flat_map(|eqn: &Eqn| eqn.unknowns()).collect() |
|
|
|
|
} |
|
|
|
@ -123,11 +134,11 @@ impl Unknowns for Eqns {
@@ -123,11 +134,11 @@ impl Unknowns for Eqns {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl fmt::Display for Eqns { |
|
|
|
|
impl<'a> fmt::Display for Eqns<'a> { |
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
|
|
|
|
write!(f, "{{ "); |
|
|
|
|
write!(f, "{{ ")?; |
|
|
|
|
let mut first = true; |
|
|
|
|
for eq in &self.0 { |
|
|
|
|
for eq in (&self.0 as &Borrow<[Eqn]>).borrow() { |
|
|
|
|
if first { |
|
|
|
|
first = false; |
|
|
|
|
} else { |
|
|
|
@ -139,8 +150,91 @@ impl fmt::Display for Eqns {
@@ -139,8 +150,91 @@ impl fmt::Display for Eqns {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn solve_eqns<'a>(eqns: &Eqns<'a>, for_vars: &[Unknown]) -> Option<Eqns<'static>> { |
|
|
|
|
let eqn_unknowns = eqns.unknowns(); |
|
|
|
|
let has_all_vars = for_vars.iter().all(|u| eqn_unknowns.contains(u)); |
|
|
|
|
if !has_all_vars { |
|
|
|
|
// return None;
|
|
|
|
|
} |
|
|
|
|
let mut var_sols = BTreeMap::<Unknown, Vec<Expr>>::new(); |
|
|
|
|
for u in &eqn_unknowns { |
|
|
|
|
for eq in (&eqns.0 as &Borrow<[Eqn]>).borrow() { |
|
|
|
|
let sol = solve_eqn(eq, *u); |
|
|
|
|
if let Some(sol) = sol { |
|
|
|
|
//println!("sol {0} -> {2} from {1}", u, eq, sol);
|
|
|
|
|
match var_sols.entry(*u) { |
|
|
|
|
Entry::Vacant(vac) => { |
|
|
|
|
vac.insert(vec![sol]); |
|
|
|
|
} |
|
|
|
|
Entry::Occupied(mut occ) => { |
|
|
|
|
if !occ.get().contains(&sol) { |
|
|
|
|
occ.get_mut().push(sol); |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
} else { |
|
|
|
|
//println!("no sol for {0} in {1}", u, eq);
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
let mut new_eqns: Vec<Eqn> = Vec::new(); |
|
|
|
|
let mut all_have_sols = true; |
|
|
|
|
for e in &var_sols { |
|
|
|
|
let mut has_sol = false; |
|
|
|
|
let mut last_expr = Unkn(*e.0); |
|
|
|
|
println!("{}", e.0); |
|
|
|
|
for s in e.1 { |
|
|
|
|
println!(" == {}", s); |
|
|
|
|
new_eqns.push(Eqn(last_expr, s.clone())); |
|
|
|
|
last_expr = s.clone(); |
|
|
|
|
match s { |
|
|
|
|
Const(_) => { has_sol = true; } |
|
|
|
|
_ => {} |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
if !has_sol { |
|
|
|
|
all_have_sols = false |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
let mut new_eqns = Eqns(new_eqns.into()); |
|
|
|
|
println!("new eqns: {}", new_eqns); |
|
|
|
|
if all_have_sols { |
|
|
|
|
return Some(new_eqns); |
|
|
|
|
} |
|
|
|
|
return solve_eqns(&new_eqns, for_vars); |
|
|
|
|
/* |
|
|
|
|
let mut more_eqns: Vec<Eqn> = Vec::new(); |
|
|
|
|
let mut new_orig_eqns = eqns.clone(); |
|
|
|
|
for eq in new_orig_eqns.0.to_mut() { |
|
|
|
|
let u = match eq.0 { |
|
|
|
|
Unkn(u) => u, |
|
|
|
|
_ => continue, |
|
|
|
|
}; |
|
|
|
|
let my_new_eqns = Eqns( |
|
|
|
|
new_eqns |
|
|
|
|
.0 |
|
|
|
|
.iter() |
|
|
|
|
.cloned() |
|
|
|
|
.filter(|e| !e.1.has_unknown(u)) |
|
|
|
|
.collect::<Vec<_>>() |
|
|
|
|
.into(), |
|
|
|
|
); |
|
|
|
|
let r = |
|
|
|
|
eq.1.clone() |
|
|
|
|
.substitute(&my_new_eqns) |
|
|
|
|
.distribute() |
|
|
|
|
.simplify(); |
|
|
|
|
more_eqns.push(Eqn(Unkn(u), r)); |
|
|
|
|
} |
|
|
|
|
let mut more_eqns = Eqns(more_eqns.into()); |
|
|
|
|
println!("more eqns: {}", more_eqns); |
|
|
|
|
*/ |
|
|
|
|
None |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[cfg(test)] |
|
|
|
|
mod tests { |
|
|
|
|
use super::super::Scalar; |
|
|
|
|
use super::*; |
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
@ -171,7 +265,7 @@ mod tests {
@@ -171,7 +265,7 @@ mod tests {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
fn test_eqn_solve() { |
|
|
|
|
fn test_solve_eqn() { |
|
|
|
|
use Expr::*; |
|
|
|
|
let _ = env_logger::try_init(); |
|
|
|
|
let u1 = Unknown(1); |
|
|
|
@ -179,22 +273,22 @@ mod tests {
@@ -179,22 +273,22 @@ mod tests {
|
|
|
|
|
let e2 = Const(1.); |
|
|
|
|
|
|
|
|
|
let eqn = Eqn(e1.clone(), e2.clone()); |
|
|
|
|
assert_eq!(eqn.solve(u1), Some(Const(1.))); |
|
|
|
|
assert_eq!(solve_eqn(&eqn, u1), Some(Const(1.))); |
|
|
|
|
let eqn = Eqn(e2.clone(), e1.clone()); |
|
|
|
|
assert_eq!(eqn.solve(u1), Some(Const(1.))); |
|
|
|
|
assert_eq!(solve_eqn(&eqn, u1), Some(Const(1.))); |
|
|
|
|
|
|
|
|
|
let e3: Expr = Expr::from(1.) + 1. + 2.; |
|
|
|
|
let eqn = Eqn(e1.clone(), e3.clone()); |
|
|
|
|
assert_eq!(eqn.solve(u1), Some(Const(4.))); |
|
|
|
|
assert_eq!(solve_eqn(&eqn, u1), Some(Const(4.))); |
|
|
|
|
let e3 = Expr::from(1.) - 1.; |
|
|
|
|
let eqn = Eqn(e1.clone(), e3.clone()); |
|
|
|
|
assert_eq!(eqn.solve(u1), Some(Const(0.))); |
|
|
|
|
assert_eq!(solve_eqn(&eqn, u1), Some(Const(0.))); |
|
|
|
|
|
|
|
|
|
let e1 = Expr::from(2.) / (Expr::from(1.) - 4.); |
|
|
|
|
let e2 = Expr::new_minus(Const(1.), Unkn(u1)); |
|
|
|
|
let eqn = Eqn(e1, e2); |
|
|
|
|
info!("eqn: {} => {}", eqn, eqn.clone().simplify()); |
|
|
|
|
let e = eqn.solve(u1).unwrap(); |
|
|
|
|
let e = solve_eqn(&eqn, u1).unwrap(); |
|
|
|
|
assert!(const_expr(e.clone()).is_some()); |
|
|
|
|
assert!(relative_eq!(const_expr(e.clone()).unwrap(), 5. / 3.)); |
|
|
|
|
|
|
|
|
@ -208,7 +302,7 @@ mod tests {
@@ -208,7 +302,7 @@ mod tests {
|
|
|
|
|
e2.clone().simplify() |
|
|
|
|
); |
|
|
|
|
let eqn = Eqn(e1, e2); |
|
|
|
|
let e = eqn.solve(u1).unwrap(); |
|
|
|
|
let e = solve_eqn(&eqn, u1).unwrap(); |
|
|
|
|
assert!(const_expr(e.clone()).is_some()); |
|
|
|
|
assert!(relative_eq!(const_expr(e.clone()).unwrap(), -6.)); |
|
|
|
|
|
|
|
|
@ -229,7 +323,7 @@ mod tests {
@@ -229,7 +323,7 @@ mod tests {
|
|
|
|
|
e2.clone().distribute().simplify() |
|
|
|
|
); |
|
|
|
|
let eqn = Eqn(e1, e2); |
|
|
|
|
let e = eqn.solve(u1).unwrap(); |
|
|
|
|
let e = solve_eqn(&eqn, u1).unwrap(); |
|
|
|
|
assert!(const_expr(e.clone()).is_some()); |
|
|
|
|
assert!(relative_eq!(const_expr(e.clone()).unwrap(), -8.)); |
|
|
|
|
|
|
|
|
@ -240,16 +334,63 @@ mod tests {
@@ -240,16 +334,63 @@ mod tests {
|
|
|
|
|
e1, |
|
|
|
|
e2, |
|
|
|
|
e1.clone().distribute().simplify(), |
|
|
|
|
e2.clone().distribute().simplify().simplify() |
|
|
|
|
e2.clone().distribute().simplify() |
|
|
|
|
); |
|
|
|
|
let eqn = Eqn(e1, e2); |
|
|
|
|
let e = eqn.solve(u1).unwrap(); |
|
|
|
|
let e = solve_eqn(&eqn, u1).unwrap(); |
|
|
|
|
assert!(const_expr(e.clone()).is_some()); |
|
|
|
|
assert!(relative_eq!(const_expr(e.clone()).unwrap(), -9.)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
fn test_eqns_solve() { |
|
|
|
|
fn test_solve_eqn2() { |
|
|
|
|
let _ = env_logger::try_init(); |
|
|
|
|
|
|
|
|
|
let u1 = Unknown(1); |
|
|
|
|
let e1 = Expr::Unkn(u1); |
|
|
|
|
let e2 = (u1 * 2.) - 2.; |
|
|
|
|
info!( |
|
|
|
|
"e1==e2: {}=={} => {}=={}", |
|
|
|
|
e1, |
|
|
|
|
e2, |
|
|
|
|
e1.clone().distribute().simplify(), |
|
|
|
|
e2.clone().distribute().simplify(), |
|
|
|
|
); |
|
|
|
|
let eqn = Eqn(e1, e2); |
|
|
|
|
let e = solve_eqn(&eqn, u1).unwrap(); |
|
|
|
|
assert!(const_expr(e.clone()).is_some()); |
|
|
|
|
assert!(relative_eq!(const_expr(e.clone()).unwrap(), 2.)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
fn test_solve_equations() { |
|
|
|
|
let _ = env_logger::try_init(); |
|
|
|
|
|
|
|
|
|
use Expr::*; |
|
|
|
|
|
|
|
|
|
let x = Unknown(1); |
|
|
|
|
let y = Unknown(2); |
|
|
|
|
let t1 = Unknown(3); |
|
|
|
|
let t2 = Unknown(4); |
|
|
|
|
|
|
|
|
|
let eqns = Eqns( |
|
|
|
|
vec![ |
|
|
|
|
Eqn::new(x.into(), t1 * 1.), |
|
|
|
|
Eqn::new(y.into(), t1 / 2.), |
|
|
|
|
Eqn::new(x.into(), Const(0.0) + t2 / 2.), |
|
|
|
|
Eqn::new(y.into(), t2 / 2.), |
|
|
|
|
] |
|
|
|
|
.into(), |
|
|
|
|
); |
|
|
|
|
println!("eqns: {}", eqns); |
|
|
|
|
let sol = solve_eqns(&eqns, &[t1, t2]).unwrap(); |
|
|
|
|
println!("sols: {}", sol); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
fn test_solve_equations2() { |
|
|
|
|
let _ = env_logger::try_init(); |
|
|
|
|
|
|
|
|
|
use Expr::*; |
|
|
|
|
|
|
|
|
|
let x = Unknown(1); |
|
|
|
@ -257,14 +398,18 @@ mod tests {
@@ -257,14 +398,18 @@ mod tests {
|
|
|
|
|
let t1 = Unknown(3); |
|
|
|
|
let t2 = Unknown(4); |
|
|
|
|
|
|
|
|
|
let eqns = Eqns(vec![ |
|
|
|
|
Eqn::new(x.into(), t1 / 2.), |
|
|
|
|
let eqns = Eqns( |
|
|
|
|
vec![ |
|
|
|
|
Eqn::new(x.into(), t1 * 1.), |
|
|
|
|
Eqn::new(y.into(), t1 / 2.), |
|
|
|
|
Eqn::new(x.into(), Const(1.0) - t2 / 2.), |
|
|
|
|
Eqn::new(x.into(), Const(1.0) + t2 / 1.), |
|
|
|
|
Eqn::new(y.into(), t2 / 2.), |
|
|
|
|
]); |
|
|
|
|
] |
|
|
|
|
.into(), |
|
|
|
|
); |
|
|
|
|
println!("eqns: {}", eqns); |
|
|
|
|
let sol = eqns.solve(&[t1, t2]).unwrap(); |
|
|
|
|
let sol = solve_eqns(&eqns, &[t1, t2]).unwrap(); |
|
|
|
|
println!("sols: {}", sol); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|