Browse Source

Lots of work to make equation solving work better

eqn_relations
Alex Mikhalev 6 years ago
parent
commit
461088da3a
  1. 81
      src/math/eqn.rs
  2. 2
      src/math/mod.rs
  3. 16
      src/math/vec.rs
  4. 44
      src/relation.rs

81
src/math/eqn.rs

@ -96,19 +96,22 @@ fn remove_term(terms: &mut Vec<Expr>, term: &Expr) -> Option<Expr> {
} }
fn sum_fold(l: Expr, r: Expr) -> Expr { fn sum_fold(l: Expr, r: Expr) -> Expr {
use itertools::Itertools;
use Expr::*; use Expr::*;
match (l, r) { match (l, r) {
(Const(lc), Const(rc)) => Const(lc + rc), (Const(lc), Const(rc)) => Const(lc + rc),
(Const(c), o) | (o, Const(c)) if relative_eq!(c, 0.) => o, (Const(c), o) | (o, Const(c)) if relative_eq!(c, 0.) => o,
(Product(mut l), Product(mut r)) => { (Product(mut l), Product(mut r)) => {
let comm = remove_common_terms(&mut l, &mut r); let comm = remove_common_terms(&mut l, &mut r);
Expr::new_product(Sum(comm), Expr::new_sum(Product(l), Product(r))).simplify() if comm.is_empty() {
Expr::new_sum(Product(l), Product(r))
} else {
Expr::new_product(Product(comm), Expr::new_sum(Product(l), Product(r)))
}
} }
(Product(mut l), r) | (r, Product(mut l)) => { (Product(mut l), r) | (r, Product(mut l)) => {
let comm = remove_term(&mut l, &r); let comm = remove_term(&mut l, &r);
match comm { match comm {
Some(_) => Expr::new_product(r, Expr::new_sum(Product(l), Const(1.))).simplify(), Some(_) => Expr::new_product(r, Expr::new_sum(Product(l), Const(1.))),
None => Expr::new_sum(Product(l), r), None => Expr::new_sum(Product(l), r),
} }
} }
@ -143,6 +146,9 @@ fn group_sum(es: Exprs) -> Exprs {
} }
}; };
} }
for c in common.values() {
trace!("group sum value: {}", c);
}
common.into_iter().map(|(_, v)| v).collect() common.into_iter().map(|(_, v)| v).collect()
} }
@ -159,44 +165,49 @@ fn product_fold(l: Expr, r: Expr) -> Expr {
Expr::Div(Box::new(Expr::Product(vec![*num, mul])), den).simplify() Expr::Div(Box::new(Expr::Product(vec![*num, mul])), den).simplify()
} }
} }
(Product(mut ls), Product(mut rs)) => {
ls.append(&mut rs);
Product(ls)
},
(Product(mut ps), o) | (o, Product(mut ps)) => {
ps.push(o);
Product(ps)
},
(l, r) => Expr::new_product(l, r), (l, r) => Expr::new_product(l, r),
} }
} }
fn group_product(es: Exprs) -> Exprs { fn group_product(es: Exprs) -> Exprs {
use Expr::*; use Expr::*;
// let mut common: BTreeMap<UnknownSet, Expr> = BTreeMap::new(); let es2 = es.clone();
let mut common: Option<Expr> = None; let mut consts: Option<Scalar> = None;
let mut other = Exprs::new();
for e in es { for e in es {
let unkns = e.unknowns(); let unkns = e.unknowns();
// match common.get_mut(&unkns) {
match &mut common {
None => {
match e { match e {
Const(c) if relative_eq!(c, 1.) => (), Const(c) => match consts {
None => consts = Some(c),
Some(cs) => consts = Some(c * cs),
}
e => { e => {
// common.insert(unkns, e); other.push(e)
common = Some(e);
} }
};
} }
Some(existing) => {
match existing {
// Product(ref mut es) => {
// already failed at merging, so just add it to the list
// es.push(e);
// }
other => *other = product_fold(other.clone(), e),
};
} }
}; if let Some(cs) = consts {
if relative_eq!(cs, 0.0) {
other.clear();
other.push(Const(0.0))
} else if relative_ne!(cs, 1.0) {
other.push(Const(cs))
} }
// common.into_iter().map(|(_, v)| v).collect() };
common.into_iter().collect() trace!("group product: {:?} => {:?}", es2, other);
other
} }
fn distribute_product_sums(mut es: Exprs) -> Expr { fn distribute_product_sums(mut es: Exprs) -> Expr {
trace!("distribute_product_sums: {}", Product(es.clone())); let es_pre = es.clone();
use itertools::Itertools; use itertools::Itertools;
use Expr::*; use Expr::*;
for e in &mut es { for e in &mut es {
@ -209,14 +220,14 @@ fn distribute_product_sums(mut es: Exprs) -> Expr {
}) })
.map(|e| { .map(|e| {
trace!("sum in product: {}", e); trace!("sum in product: {}", e);
match e { match e.simplify() {
Sum(es) => es, Sum(es) => es,
_ => unreachable!(), o => vec![o],
} }
}); });
let products: Vec<_> = sums.multi_cartesian_product().collect(); let products: Vec<_> = sums.multi_cartesian_product().collect();
if products.is_empty() { if products.is_empty() {
trace!("no sums to distribute"); trace!("distribute_product_sums: no sums to distribute");
return Product(es); return Product(es);
} }
let sums = products let sums = products
@ -227,7 +238,9 @@ fn distribute_product_sums(mut es: Exprs) -> Expr {
Product(prod) Product(prod)
}) })
.collect(); .collect();
Sum(sums) let res = Sum(sums);
trace!("distribute_product_sums: {} => {}", Product(es_pre), res);
res
} }
impl Unknowns for Expr { impl Unknowns for Expr {
@ -336,6 +349,7 @@ impl Expr {
use Expr::*; use Expr::*;
match self { match self {
Sum(es) => { Sum(es) => {
let pre_new_es = es.clone();
let mut new_es: Vec<_> = es let mut new_es: Vec<_> = es
.into_iter() .into_iter()
.map(|e| e.simplify()) .map(|e| e.simplify())
@ -344,7 +358,6 @@ impl Expr {
other => vec![other], other => vec![other],
}) })
.collect(); .collect();
let pre_new_es = new_es.clone();
new_es = group_sum(new_es); new_es = group_sum(new_es);
trace!( trace!(
"simplify sum {} => {}", "simplify sum {} => {}",
@ -359,6 +372,7 @@ impl Expr {
} }
} }
Product(es) => { Product(es) => {
let pre_new_es = es.clone();
let new_es: Vec<_> = es let new_es: Vec<_> = es
.into_iter() .into_iter()
.map(|e| e.simplify()) .map(|e| e.simplify())
@ -367,7 +381,6 @@ impl Expr {
other => vec![other], other => vec![other],
}) })
.collect(); .collect();
let pre_new_es = new_es.clone();
let new_es = group_product(new_es); let new_es = group_product(new_es);
trace!( trace!(
"simplify product {} => {}", "simplify product {} => {}",
@ -388,7 +401,7 @@ impl Expr {
box Neg(v) => *v, box Neg(v) => *v,
box Product(mut es) => { box Product(mut es) => {
es.push(Const(-1.)); es.push(Const(-1.));
Product(es) Product(es).simplify()
} }
e => Product(vec![Const(-1.), *e]), e => Product(vec![Const(-1.), *e]),
} }
@ -428,13 +441,15 @@ impl Expr {
pub fn distribute(self) -> Expr { pub fn distribute(self) -> Expr {
use Expr::*; use Expr::*;
trace!("distribute {}", self);
match self { match self {
Sum(mut es) => { Sum(mut es) => {
let es_pre = es.clone();
for e in &mut es { for e in &mut es {
*e = e.clone().distribute(); *e = e.clone().distribute();
} }
Sum(es) let res = Sum(es);
trace!("distribute sum {} => {}", Sum(es_pre), res);
res
} }
Product(es) => distribute_product_sums(es), Product(es) => distribute_product_sums(es),
Div(mut num, mut den) => { Div(mut num, mut den) => {

2
src/math/mod.rs

@ -165,7 +165,7 @@ pub struct Line2 {
impl fmt::Display for Line2 { impl fmt::Display for Line2 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{{ (x, y) = {} + {} * {} }}", self.start, self.dir, self.extent) write!(f, "{{ <x, y> = {} + {} * {} }}", self.start, self.dir, self.extent)
} }
} }

16
src/math/vec.rs

@ -146,7 +146,7 @@ use std::fmt;
impl<T: fmt::Display> fmt::Display for Point2<T> { impl<T: fmt::Display> fmt::Display for Point2<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y) write!(f, "<{}, {}>", self.x, self.y)
} }
} }
@ -158,7 +158,7 @@ pub struct Rot2 {
impl fmt::Display for Rot2 { impl fmt::Display for Rot2 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})", self.cos, self.sin) write!(f, "<{}, {}>", self.cos, self.sin)
} }
} }
@ -167,6 +167,14 @@ impl Rot2 {
Self { cos, sin } Self { cos, sin }
} }
pub fn up() -> Self {
Self { cos: 0., sin: 1. }
}
pub fn right() -> Self {
Self { cos: 1., sin: 0. }
}
pub fn from_cos_sin(cos: Scalar, sin: Scalar) -> Self { pub fn from_cos_sin(cos: Scalar, sin: Scalar) -> Self {
Vec2 { x: cos, y: sin }.into() Vec2 { x: cos, y: sin }.into()
} }
@ -218,6 +226,10 @@ impl Rot2 {
sin: -self.sin, sin: -self.sin,
} }
} }
pub fn dot(self, v: Vec2<Value>) -> Value {
v.x * self.cos + v.y * self.sin
}
} }
impl From<Vec2<Scalar>> for Rot2 { impl From<Vec2<Scalar>> for Rot2 {

44
src/relation.rs

@ -64,7 +64,9 @@ impl Relation for PointAngle {
let (mut p1, mut p2) = (self.p1.borrow_mut(), self.p2.borrow_mut()); let (mut p1, mut p2) = (self.p1.borrow_mut(), self.p2.borrow_mut());
let constrain_line = |p1: &Point2<Value>, p2: &mut PointEntity| { let constrain_line = |p1: &Point2<Value>, p2: &mut PointEntity| {
let line = Region2::Line(Line2::new(p1.clone(), self.angle.clone(), Region1::Full)); let line = Region2::Line(Line2::new(p1.clone(), self.angle.clone(), Region1::Full));
trace!("PointAngle line: {}, p2 constraint: {}", line, p2.pos.constraints());
let new_constraint = p2.pos.constraints().clone().intersection(line).simplify(); let new_constraint = p2.pos.constraints().clone().intersection(line).simplify();
trace!("PointAngle new_constraint: {}", new_constraint);
p2.pos.reconstrain(new_constraint); p2.pos.reconstrain(new_constraint);
ResolveResult::from_r2(p2.pos.constraints()) ResolveResult::from_r2(p2.pos.constraints())
}; };
@ -74,7 +76,7 @@ impl Relation for PointAngle {
// if the angle p1 and p2 form is parallel to self.angle, the result // if the angle p1 and p2 form is parallel to self.angle, the result
// will have a y component of 0 // will have a y component of 0
let r = self.angle.clone().conj() * (p2.clone() - p1.clone()); let r = self.angle.clone().conj() * (p2.clone() - p1.clone());
println!("angle.cos: {}", r.x); trace!("angle.cos: {}", r.x);
// if relative_eq!(r.y, 0.) { // if relative_eq!(r.y, 0.) {
ResolveResult::Constrained ResolveResult::Constrained
// } else { // } else {
@ -88,34 +90,29 @@ impl Relation for PointAngle {
} }
} }
pub enum Axis {
Vertical,
Horizontal,
}
pub struct AlignedDistance { pub struct AlignedDistance {
pub p1: PointRef, pub p1: PointRef,
pub p2: PointRef, pub p2: PointRef,
pub axis: Axis, pub angle: Rot2,
pub distance: Scalar, pub distance: Scalar,
} }
impl AlignedDistance { impl AlignedDistance {
pub fn new(p1: PointRef, p2: PointRef, axis: Axis, distance: Scalar) -> Self { pub fn new(p1: PointRef, p2: PointRef, angle: Rot2, distance: Scalar) -> Self {
Self { Self {
p1, p1,
p2, p2,
axis, angle,
distance, distance,
} }
} }
pub fn new_vertical(p1: PointRef, p2: PointRef, distance: Scalar) -> Self { pub fn new_vertical(p1: PointRef, p2: PointRef, distance: Scalar) -> Self {
Self::new(p1, p2, Axis::Vertical, distance) Self::new(p1, p2, Rot2::up(), distance)
} }
pub fn new_horizontal(p1: PointRef, p2: PointRef, distance: Scalar) -> Self { pub fn new_horizontal(p1: PointRef, p2: PointRef, distance: Scalar) -> Self {
Self::new(p1, p2, Axis::Horizontal, distance) Self::new(p1, p2, Rot2::right(), distance)
} }
} }
@ -124,27 +121,20 @@ impl Relation for AlignedDistance {
use Region2::*; use Region2::*;
let (mut p1, mut p2) = (self.p1.borrow_mut(), self.p2.borrow_mut()); let (mut p1, mut p2) = (self.p1.borrow_mut(), self.p2.borrow_mut());
let constrain_line = |p1: Point2<Value>, p2: &mut PointEntity| { let constrain_line = |p1: Point2<Value>, p2: &mut PointEntity| {
let angle = match self.axis { let angle = self.angle + Rot2::up();
Axis::Horizontal => Rot2::from_cos_sin_unchecked((0.).into(), (1.).into()), let line = Region2::Line(Line2::new(p1.clone(), angle, Region1::Full)).simplify();
Axis::Vertical => Rot2::from_cos_sin_unchecked((1.).into(), (0.).into()), trace!("AlignedDistance line: {}, p2 constraint: {}", line, p2.pos.constraints());
};
let line = Region2::Line(Line2::new(p1.clone(), angle, Region1::Full));
let new_constraint = p2.pos.constraints().clone().intersection(line).simplify(); let new_constraint = p2.pos.constraints().clone().intersection(line).simplify();
trace!("AlignedDistance new_constraint: {}", new_constraint);
p2.pos.reconstrain(new_constraint); p2.pos.reconstrain(new_constraint);
ResolveResult::from_r2(p2.pos.constraints()) ResolveResult::from_r2(p2.pos.constraints())
}; };
let offset: Vec2<Scalar> = match self.axis { let offset: Vec2<Scalar> = self.angle * self.distance;
Axis::Horizontal => Vec2::new(self.distance.into(), (0.).into()),
Axis::Vertical => Vec2::new((0.).into(), self.distance.into()),
};
match (&mut p1.pos.constraints(), &mut p2.pos.constraints()) { match (&mut p1.pos.constraints(), &mut p2.pos.constraints()) {
(Empty, _) | (_, Empty) => ResolveResult::Overconstrained, (Empty, _) | (_, Empty) => ResolveResult::Overconstrained,
(Singleton(p1), Singleton(p2)) => { (Singleton(p1), Singleton(p2)) => {
let r = p2.clone() - p1.clone(); let r = p2.clone() - p1.clone();
let d = match self.axis { let d = self.angle.dot(r);
Axis::Horizontal => r.x,
Axis::Vertical => r.y,
};
// if relative_eq!(d, self.distance) { // if relative_eq!(d, self.distance) {
ResolveResult::Constrained ResolveResult::Constrained
// } else { // } else {
@ -157,3 +147,9 @@ impl Relation for AlignedDistance {
} }
} }
} }
pub struct Midpoint {
pub p1: PointRef,
pub p2: PointRef,
pub mid: PointRef,
}

Loading…
Cancel
Save