got more stuff to work?
This commit is contained in:
		
							parent
							
								
									067f868222
								
							
						
					
					
						commit
						ce4a662847
					
				| @ -44,7 +44,7 @@ impl<T: Clone, TRegion: Region<T> + Clone> Constrainable<T, TRegion> { | ||||
|     } | ||||
| 
 | ||||
|     pub fn resolve_with(&mut self, eqns: &Eqns) -> bool { | ||||
|         let resolved_constraints = self.constraints.clone().evaluate_with(eqns).simplify(); | ||||
|         let resolved_constraints = self.constraints.clone().substitute(eqns).simplify(); | ||||
|         if let Some(n) = resolved_constraints.nearest(&self.value) { | ||||
|             self.value = n; | ||||
|             true | ||||
| @ -54,7 +54,7 @@ impl<T: Clone, TRegion: Region<T> + Clone> Constrainable<T, TRegion> { | ||||
|     } | ||||
| 
 | ||||
|     pub fn evaluate_with(&mut self, eqns: &Eqns) -> bool { | ||||
|         self.constraints = self.constraints.clone().evaluate_with(eqns).simplify(); | ||||
|         self.constraints = self.constraints.clone().substitute(eqns).simplify(); | ||||
|         if let Some(n) = self.constraints.nearest(&self.value) { | ||||
|             self.value = n; | ||||
|             true | ||||
|  | ||||
| @ -103,7 +103,7 @@ fn main() { | ||||
|     } | ||||
|     let e1 = Eqn::new(Expr::Unkn(u1), Expr::Const(1.)); | ||||
|     let e2 = Eqn::new(Expr::Unkn(u2), Expr::Const(1.)); | ||||
|     let eqns = Eqns(vec![e1, e2]); | ||||
|     let eqns = Eqns(vec![e1, e2].into()); | ||||
|     for p in &mut points { | ||||
|         p.borrow_mut().resolve_with(&eqns); | ||||
|     } | ||||
|  | ||||
							
								
								
									
										227
									
								
								src/math/eqn.rs
									
									
									
									
									
								
							
							
						
						
									
										227
									
								
								src/math/eqn.rs
									
									
									
									
									
								
							| @ -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 { | ||||
|         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 { | ||||
|                     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 { | ||||
|                     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 { | ||||
|             } | ||||
|             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 { | ||||
| } | ||||
| 
 | ||||
| #[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 { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 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 { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 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 { | ||||
|     } | ||||
| 
 | ||||
|     #[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 { | ||||
|         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 { | ||||
|             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 { | ||||
|             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,38 @@ 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); | ||||
| @ -257,14 +373,43 @@ 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(0.0) + t2 / 2.), | ||||
|                 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); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn test_solve_equations2() { | ||||
|         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(1.0) + t2 / 1.), | ||||
|                 Eqn::new(y.into(), t2 / 2.), | ||||
|             ] | ||||
|             .into(), | ||||
|         ); | ||||
|         println!("eqns: {}", eqns); | ||||
|         let sol = solve_eqns(&eqns, &[t1, t2]).unwrap(); | ||||
|         println!("sols: {}", sol); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
							
								
								
									
										214
									
								
								src/math/expr.rs
									
									
									
									
									
								
							
							
						
						
									
										214
									
								
								src/math/expr.rs
									
									
									
									
									
								
							| @ -1,9 +1,11 @@ | ||||
| use std::borrow::Borrow; | ||||
| use std::collections::BTreeMap; | ||||
| use std::fmt; | ||||
| 
 | ||||
| use super::eqn::Eqns; | ||||
| use super::eqn::{Eqn, Eqns}; | ||||
| use super::unknown::{Unknown, UnknownSet, Unknowns}; | ||||
| use super::Scalar; | ||||
| use std::f64::NAN; | ||||
| 
 | ||||
| #[derive(Clone, Debug, PartialEq)] | ||||
| pub enum Expr { | ||||
| @ -29,9 +31,9 @@ impl Unknowns for Exprs { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn write_separated_exprs(es: &Exprs, f: &mut fmt::Formatter, sep: &str) -> fmt::Result { | ||||
|     let mut is_first = true; | ||||
| fn write_separated_exprs(es: &[Expr], f: &mut fmt::Formatter, sep: &str) -> fmt::Result { | ||||
|     write!(f, "(")?; | ||||
|     let mut is_first = es.len() > 1; | ||||
|     for e in es { | ||||
|         if is_first { | ||||
|             is_first = false; | ||||
| @ -66,16 +68,24 @@ fn sum_fold(l: Expr, r: Expr) -> Expr { | ||||
|             if comm.is_empty() { | ||||
|                 Expr::new_sum(Product(l), Product(r)) | ||||
|             } else { | ||||
|                 Expr::new_product(Product(comm), Expr::new_sum(Product(l), Product(r))) | ||||
|                 Expr::new_product(Product(comm), Expr::new_sum(Product(l), Product(r)).collapse()) | ||||
|             } | ||||
|         } | ||||
|         (Product(mut l), r) | (r, Product(mut l)) => { | ||||
|             let comm = remove_term(&mut l, &r); | ||||
|             match comm { | ||||
|                 Some(_) => Expr::new_product(r, Expr::new_sum(Product(l), Const(1.))), | ||||
|                 Some(_) => Expr::new_product(r, Expr::new_sum(Product(l), Const(1.))).collapse(), | ||||
|                 None => Expr::new_sum(Product(l), r), | ||||
|             } | ||||
|         } | ||||
|         (Div(box ln, box ld), Div(box rn, box rd)) => { | ||||
|             if ld == rd { | ||||
|                 Expr::new_div(Expr::new_sum(ln, rn), ld).collapse() | ||||
|             } else { | ||||
|                 Expr::new_div(Expr::new_sum(Expr::new_product(ln, rd.clone()), Expr::new_product(rn, ld.clone())), | ||||
|                     Expr::new_product(ld, rd)).collapse() | ||||
|             } | ||||
|         } | ||||
|         (l, r) => Expr::new_sum(l, r), | ||||
|     } | ||||
| } | ||||
| @ -84,16 +94,17 @@ fn group_sum(es: Exprs) -> Exprs { | ||||
|     use Expr::*; | ||||
|     let mut common: BTreeMap<UnknownSet, Expr> = BTreeMap::new(); | ||||
|     for e in es { | ||||
|         match e { | ||||
|             Const(c) if relative_eq!(c, 0.) => { | ||||
|                 continue; | ||||
|             } | ||||
|             _ => (), | ||||
|         }; | ||||
|         let unkns = e.unknowns(); | ||||
|         match common.get_mut(&unkns) { | ||||
|             None => { | ||||
|                 match e { | ||||
|                     Const(c) if relative_eq!(c, 0.) => (), | ||||
|                     e => { | ||||
|                 common.insert(unkns, e); | ||||
|             } | ||||
|                 }; | ||||
|             } | ||||
|             Some(existing) => { | ||||
|                 match existing { | ||||
|                     Sum(ref mut es) => { | ||||
| @ -110,7 +121,14 @@ 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) | ||||
|         .filter(|e| match e { | ||||
|             Const(c) if relative_eq!(*c, 0.) => false, | ||||
|             _ => true, | ||||
|         }) | ||||
|         .collect() | ||||
| } | ||||
| 
 | ||||
| fn product_fold(l: Expr, r: Expr) -> Expr { | ||||
| @ -255,25 +273,25 @@ impl Expr { | ||||
|         Expr::new_div(Expr::Const(1.), den) | ||||
|     } | ||||
| 
 | ||||
|     pub fn is_zero(self) -> bool { | ||||
|     pub fn is_zero(&self) -> bool { | ||||
|         use Expr::*; | ||||
|         match self.simplify() { | ||||
|         match self.clone().simplify() { | ||||
|             Const(c) => relative_eq!(c, 0.), | ||||
|             _ => false, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn is_one(self) -> bool { | ||||
|     pub fn is_one(&self) -> bool { | ||||
|         use Expr::*; | ||||
|         match self.simplify() { | ||||
|         match self.clone().simplify() { | ||||
|             Const(c) => relative_eq!(c, 1.), | ||||
|             _ => false, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn evaluate_with(self, eqns: &Eqns) -> Expr { | ||||
|     pub fn substitute<'a>(self, eqns: &Eqns<'a>) -> Expr { | ||||
|         use Expr::*; | ||||
|         for eqn in &eqns.0 { | ||||
|         for eqn in (&eqns.0 as &Borrow<[Eqn]>).borrow() { | ||||
|             if self == eqn.0 { | ||||
|                 return eqn.1.clone(); | ||||
|             } | ||||
| @ -281,29 +299,129 @@ impl Expr { | ||||
|         match self { | ||||
|             Sum(mut es) => { | ||||
|                 for e in &mut es { | ||||
|                     *e = e.clone().evaluate_with(eqns); | ||||
|                     *e = e.clone().substitute(eqns); | ||||
|                 } | ||||
|                 Sum(es) | ||||
|             } | ||||
|             Product(mut es) => { | ||||
|                 for e in &mut es { | ||||
|                     *e = e.clone().evaluate_with(eqns); | ||||
|                     *e = e.clone().substitute(eqns); | ||||
|                 } | ||||
|                 Product(es) | ||||
|             } | ||||
|             Neg(mut e) => { | ||||
|                 *e = e.evaluate_with(eqns); | ||||
|                 *e = e.substitute(eqns); | ||||
|                 Neg(e) | ||||
|             } | ||||
|             Div(mut num, mut den) => { | ||||
|                 *num = num.evaluate_with(eqns); | ||||
|                 *den = den.evaluate_with(eqns); | ||||
|                 *num = num.substitute(eqns); | ||||
|                 *den = den.substitute(eqns); | ||||
|                 Div(num, den) | ||||
|             } | ||||
|             other => other, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn collapse(self) -> Expr { | ||||
|         use Expr::*; | ||||
|         match self { | ||||
|             Sum(es) => { | ||||
|                 let mut new_es: Vec<_> = es | ||||
|                     .into_iter() | ||||
|                     .map(|e| e.collapse()) | ||||
|                     .flat_map(|e| match e { | ||||
|                         Sum(more_es) => more_es, | ||||
|                         other => vec![other], | ||||
|                     }) | ||||
|                     .collect(); | ||||
| 
 | ||||
|                 let consts = new_es.drain_filter(|e| match e { | ||||
|                     Const(_) => true, | ||||
|                     _ => false | ||||
|                 }).fold(Const(0.), |l, r| match (l, r) { | ||||
|                     (Const(lc), Const(rc)) => Const(lc + rc), | ||||
|                     _ => unreachable!(), | ||||
|                 }); | ||||
|                 new_es.push(consts); | ||||
| 
 | ||||
|                 match new_es.len() { | ||||
|                     0 => Const(0.),                          // none
 | ||||
|                     1 => new_es.into_iter().next().unwrap(), // one
 | ||||
|                     _ => Sum(new_es),                        // many
 | ||||
|                 } | ||||
|             } | ||||
|             Product(es) => { | ||||
|                 let new_es: Vec<_> = es | ||||
|                     .into_iter() | ||||
|                     .map(|e| e.collapse()) | ||||
|                     .flat_map(|e| match e { | ||||
|                         Product(more_es) => more_es, | ||||
|                         other => vec![other], | ||||
|                     }) | ||||
|                     .collect(); | ||||
|                 match new_es.len() { | ||||
|                     0 => Const(1.),                          // none
 | ||||
|                     1 => new_es.into_iter().next().unwrap(), // one
 | ||||
|                     _ => { | ||||
|                         if new_es.iter().any(|e| e.is_zero()) { | ||||
|                             Const(0.) | ||||
|                         } else { | ||||
|                             Product(new_es) | ||||
|                         } | ||||
|                     },                    // many
 | ||||
|                 } | ||||
|             } | ||||
|             Neg(mut v) => { | ||||
|                 *v = v.collapse(); | ||||
|                 match v { | ||||
|                     box Const(c) => Const(-c), | ||||
|                     box Neg(v) => *v, | ||||
|                     box Product(mut es) => { | ||||
|                         es.push(Const(-1.)); | ||||
|                         Product(es).collapse() | ||||
|                     } | ||||
|                     e => Product(vec![Const(-1.), *e]).collapse(), | ||||
|                 } | ||||
|             } | ||||
|             Div(mut num, mut den) => { | ||||
|                 *num = num.collapse(); | ||||
|                 *den = den.collapse(); | ||||
|                 match (num, den) { | ||||
|                     (box Const(num), box Const(den)) => Const(num / den), | ||||
|                     (box Const(num), den) => { | ||||
|                         if relative_eq!(num, 0.) { | ||||
|                             Const(0.) | ||||
|                         } else { | ||||
|                             Div(Box::new(Const(num)), den) | ||||
|                         } | ||||
|                     } | ||||
|                     (num, box Const(den)) => { | ||||
|                         if relative_eq!(den, 1.) { | ||||
|                             *num | ||||
|                         } else { | ||||
|                             Expr::new_product(*num, Const(1. / den)).collapse() | ||||
|                         } | ||||
|                     } | ||||
|                     (num, box Div(dennum, denden)) => { | ||||
|                         Div(Box::new(Product(vec![*num, *denden])), dennum).collapse() | ||||
|                     } | ||||
|                     (box Product(mut es), box den) => match es.remove_item(&den) { | ||||
|                         Some(_) => Product(es), | ||||
|                         None => Expr::new_div(Product(es), den), | ||||
|                     }, | ||||
|                     (num, den) => { | ||||
|                         if num == den { | ||||
|                             Expr::Const(1.) | ||||
|                         } else { | ||||
|                             Div(num, den) | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             e => e, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn simplify(self) -> Expr { | ||||
|         use Expr::*; | ||||
|         match self { | ||||
| @ -362,7 +480,7 @@ impl Expr { | ||||
|                         es.push(Const(-1.)); | ||||
|                         Product(es).simplify() | ||||
|                     } | ||||
|                     e => Product(vec![Const(-1.), *e]), | ||||
|                     e => Product(vec![Const(-1.), *e]).simplify(), | ||||
|                 } | ||||
|             } | ||||
|             Div(mut num, mut den) => { | ||||
| @ -375,14 +493,14 @@ impl Expr { | ||||
|                         if relative_eq!(den, 1.) { | ||||
|                             *num | ||||
|                         } else { | ||||
|                             Expr::new_product(*num, Const(1. / den)) | ||||
|                             Expr::new_product(*num, Const(1. / den)).simplify() | ||||
|                         } | ||||
|                     } | ||||
|                     (num, box Div(dennum, denden)) => { | ||||
|                         Div(Box::new(Product(vec![*num, *denden])), dennum).simplify() | ||||
|                     } | ||||
|                     (box Product(mut es), box den) => match es.remove_item(&den) { | ||||
|                         Some(_) => Product(es), | ||||
|                         Some(_) => Product(es).simplify(), | ||||
|                         None => Expr::new_div(Product(es), den), | ||||
|                     }, | ||||
|                     (num, den) => { | ||||
| @ -394,6 +512,10 @@ impl Expr { | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             Const(c) => if c.is_nan() { | ||||
|                 println!("NAN!"); | ||||
|                 Const(c) | ||||
|             } else { Const(c) }, | ||||
|             e => e, | ||||
|         } | ||||
|     } | ||||
| @ -411,34 +533,34 @@ impl Expr { | ||||
|                 res | ||||
|             } | ||||
|             Product(es) => distribute_product_sums(es), | ||||
|             Div(mut num, mut den) => { | ||||
|                 *num = num.distribute(); | ||||
|                 *den = den.distribute(); | ||||
|                 match (num, den) { | ||||
|             Div(num, den) => match (num, den) { | ||||
|                 (box Sum(es), box den) => Sum(es | ||||
|                     .into_iter() | ||||
|                         .map(|e| Expr::new_div(e, den.clone())) | ||||
|                     .map(|e| Expr::new_div(e, den.clone()).distribute()) | ||||
|                     .collect()), | ||||
|                     (mut num, mut den) => Div(num, den), | ||||
|                 } | ||||
|             } | ||||
|                 (num, den) => Div(num, den), | ||||
|             }, | ||||
|             Neg(v) => match v { | ||||
|                 // box Sum(mut l, mut r) => {
 | ||||
|                 //     *l = Neg(l.clone()).distribute();
 | ||||
|                 //     *r = Neg(r.clone()).distribute();
 | ||||
|                 //     Sum(l, r)
 | ||||
|                 // }
 | ||||
|                 // box Product(mut l, r) => {
 | ||||
|                 //     *l = Neg(l.clone()).distribute();
 | ||||
|                 //     Product(l, r)
 | ||||
|                 // }
 | ||||
|                 box Const(c) => Const(-c), | ||||
|                 box Sum(mut es) => { | ||||
|                     for e in &mut es { | ||||
|                         *e = Expr::new_neg(e.clone()).distribute(); | ||||
|                     } | ||||
|                     Sum(es) | ||||
|                 } | ||||
|                 box Product(mut es) => { | ||||
|                     for e in &mut es { | ||||
|                         *e = e.clone().distribute(); | ||||
|                     } | ||||
|                     es.push(Const(-1.)); | ||||
|                     Product(es) | ||||
|                 } | ||||
|                 box Neg(v) => v.distribute(), | ||||
|                 box Div(mut num, mut den) => { | ||||
|                     *num = Neg(num.clone()).distribute(); | ||||
|                     *den = Neg(den.clone()).distribute(); | ||||
|                     Div(num, den) | ||||
|                     *num = Neg(num.clone()); | ||||
|                     Div(num, den).distribute() | ||||
|                 } | ||||
|                 e => Neg(e), | ||||
|                 e => Neg(Box::new(e.distribute())), | ||||
|             }, | ||||
|             e => e, | ||||
|         } | ||||
|  | ||||
| @ -11,7 +11,7 @@ pub trait GenericRegion { | ||||
|     fn full() -> Self; | ||||
|     fn intersection(self, other: Self) -> Self; | ||||
|     fn simplify(self) -> Self; | ||||
|     fn evaluate_with(self, eqns: &eqn::Eqns) -> Self; | ||||
|     fn substitute(self, eqns: &eqn::Eqns) -> Self; | ||||
| } | ||||
| 
 | ||||
| pub trait Region<T>: GenericRegion { | ||||
| @ -63,12 +63,12 @@ impl GenericRegion for Region1 { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn evaluate_with(self, eqns: &eqn::Eqns) -> Self { | ||||
|     fn substitute(self, eqns: &eqn::Eqns) -> Self { | ||||
|         use Region1::*; | ||||
|         match self { | ||||
|             Singleton(n) => Singleton(n.evaluate_with(eqns)), | ||||
|             Range(l, u) => Range(l.evaluate_with(eqns), u.evaluate_with(eqns)), | ||||
|             Intersection(r1, r2) => r1.evaluate_with(eqns).intersection(r2.evaluate_with(eqns)), | ||||
|             Singleton(n) => Singleton(n.substitute(eqns)), | ||||
|             Range(l, u) => Range(l.substitute(eqns), u.substitute(eqns)), | ||||
|             Intersection(r1, r2) => r1.substitute(eqns).intersection(r2.substitute(eqns)), | ||||
|             other => other, | ||||
|         } | ||||
|     } | ||||
| @ -162,7 +162,7 @@ impl Line2 { | ||||
|     } | ||||
| 
 | ||||
|     pub fn evaluate(&self, t: Value) -> Point2<Value> { | ||||
|         self.start.clone() + self.dir.clone() * t | ||||
|         self.start.clone() + self.dir * t | ||||
|     } | ||||
| 
 | ||||
|     pub fn evaluate_extent(&self) -> Option<Point2<Value>> { | ||||
| @ -182,7 +182,7 @@ impl Line2 { | ||||
| 
 | ||||
|     pub fn nearest(&self, p: &Point2<Value>) -> Point2<Value> { | ||||
|         // rotate angle 90 degrees
 | ||||
|         let perp_dir = self.dir.clone() + Rot2::cardinal(1); | ||||
|         let perp_dir = self.dir + Rot2::cardinal(1); | ||||
|         let perp = Line2::new(p.clone(), perp_dir, Region1::Full); | ||||
|         match self.intersect(&perp) { | ||||
|             Region2::Singleton(np) => np, | ||||
| @ -193,7 +193,7 @@ impl Line2 { | ||||
| 
 | ||||
|     pub fn intersect(&self, other: &Line2) -> Region2 { | ||||
|         // if the two lines are parallel...
 | ||||
|         let dirs = self.dir.clone() - other.dir.clone(); | ||||
|         let dirs = self.dir - other.dir; | ||||
|         if relative_eq!(dirs.sin(), 0.) { | ||||
|             let starts = self.dir.conj() * (other.start.clone() - self.start.clone()); | ||||
|             return if starts.y.simplify().is_zero() { | ||||
| @ -208,16 +208,16 @@ impl Line2 { | ||||
|         let (a, b) = (self, other); | ||||
|         let (a_0, a_v, b_0, b_v) = ( | ||||
|             a.start.clone(), | ||||
|             a.dir.clone(), | ||||
|             a.dir, | ||||
|             b.start.clone(), | ||||
|             b.dir.clone(), | ||||
|             b.dir, | ||||
|         ); | ||||
|         let (a_c, a_s, b_c, b_s) = (a_v.cos(), a_v.sin(), b_v.cos(), b_v.sin()); | ||||
|         let t_b = (a_0.x.clone() * a_s.clone() | ||||
|             - a_0.y.clone() * a_c.clone() | ||||
|             - b_0.x.clone() * a_s.clone() | ||||
|             + b_0.y.clone() * a_c.clone()) | ||||
|             / (a_s.clone() * b_c.clone() - a_c.clone() * b_s.clone()); | ||||
|         let t_b = (a_0.x.clone() * a_s | ||||
|             - a_0.y.clone() * a_c | ||||
|             - b_0.x.clone() * a_s | ||||
|             + b_0.y.clone() * a_c) | ||||
|             / (a_s * b_c - a_c * b_s); | ||||
|         // Region2::Singleton(b.evaluate(t_b))
 | ||||
|         trace!("intersect a: {}, b: {}, t_b = {}", a, b, t_b); | ||||
|         let res = Region2::Line(b.clone().with_extent(Region1::Singleton(t_b.simplify()))); | ||||
| @ -242,11 +242,11 @@ impl Line2 { | ||||
|         Region2::Line(new_l) | ||||
|     } | ||||
| 
 | ||||
|     pub fn evaluate_with(self, eqns: &eqn::Eqns) -> Self { | ||||
|     pub fn substitute(self, eqns: &eqn::Eqns) -> Self { | ||||
|         Line2 { | ||||
|             start: self.start.evaluate_with(eqns), | ||||
|             start: self.start.substitute(eqns), | ||||
|             dir: self.dir, | ||||
|             extent: self.extent.evaluate_with(eqns), | ||||
|             extent: self.extent.substitute(eqns), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -300,12 +300,12 @@ impl GenericRegion for Region2 { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn evaluate_with(self, eqns: &eqn::Eqns) -> Self { | ||||
|     fn substitute(self, eqns: &eqn::Eqns) -> Self { | ||||
|         use Region2::*; | ||||
|         match self { | ||||
|             Singleton(n) => Singleton(n.evaluate_with(eqns)), | ||||
|             Line(l) => Line(l.evaluate_with(eqns)), | ||||
|             Intersection(r1, r2) => r1.evaluate_with(eqns).intersection(r2.evaluate_with(eqns)), | ||||
|             Singleton(n) => Singleton(n.substitute(eqns)), | ||||
|             Line(l) => Line(l.substitute(eqns)), | ||||
|             Intersection(r1, r2) => r1.substitute(eqns).intersection(r2.substitute(eqns)), | ||||
|             other => other, | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -98,10 +98,10 @@ impl Point2<Value> { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn evaluate_with(self, eqns: &Eqns) -> Self { | ||||
|     pub fn substitute(self, eqns: &Eqns) -> Self { | ||||
|         Self { | ||||
|             x: self.x.evaluate_with(eqns), | ||||
|             y: self.y.evaluate_with(eqns), | ||||
|             x: self.x.substitute(eqns), | ||||
|             y: self.y.substitute(eqns), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -184,8 +184,8 @@ impl Rot2 { | ||||
| 
 | ||||
|     pub fn from_angle(angle: Scalar) -> Self { | ||||
|         Self { | ||||
|             cos: angle.cos().into(), | ||||
|             sin: angle.sin().into(), | ||||
|             cos: angle.cos(), | ||||
|             sin: angle.sin(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -195,22 +195,10 @@ impl Rot2 { | ||||
| 
 | ||||
|     pub fn cardinal(index: i64) -> Self { | ||||
|         match index % 4 { | ||||
|             0 => Rot2 { | ||||
|                 cos: (1.).into(), | ||||
|                 sin: (0.).into(), | ||||
|             }, | ||||
|             1 => Rot2 { | ||||
|                 cos: (0.).into(), | ||||
|                 sin: (1.).into(), | ||||
|             }, | ||||
|             2 => Rot2 { | ||||
|                 cos: (-1.).into(), | ||||
|                 sin: (0.).into(), | ||||
|             }, | ||||
|             3 => Rot2 { | ||||
|                 cos: (0.).into(), | ||||
|                 sin: (-1.).into(), | ||||
|             }, | ||||
|             0 => Rot2 { cos: 1., sin: 0. }, | ||||
|             1 => Rot2 { cos: 0., sin: 1. }, | ||||
|             2 => Rot2 { cos: -1., sin: 0. }, | ||||
|             3 => Rot2 { cos: 0., sin: -1. }, | ||||
|             _ => unreachable!(), | ||||
|         } | ||||
|     } | ||||
| @ -266,7 +254,7 @@ impl ops::Add<Rot2> for Rot2 { | ||||
|     type Output = Rot2; | ||||
|     fn add(self, rhs: Rot2) -> Rot2 { | ||||
|         Rot2 { | ||||
|             cos: self.cos.clone() * rhs.cos.clone() - self.sin.clone() * rhs.sin.clone(), | ||||
|             cos: self.cos * rhs.cos - self.sin * rhs.sin, | ||||
|             sin: self.cos * rhs.sin + self.sin * rhs.cos, | ||||
|         } | ||||
|     } | ||||
| @ -276,7 +264,7 @@ impl ops::Sub<Rot2> for Rot2 { | ||||
|     type Output = Rot2; | ||||
|     fn sub(self, rhs: Rot2) -> Rot2 { | ||||
|         Rot2 { | ||||
|             cos: self.cos.clone() * rhs.cos.clone() + self.sin.clone() * rhs.sin.clone(), | ||||
|             cos: self.cos * rhs.cos + self.sin * rhs.sin, | ||||
|             sin: self.sin * rhs.cos - self.cos * rhs.sin, | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -58,7 +58,7 @@ impl PointAngle { | ||||
|         Self::new( | ||||
|             p1, | ||||
|             p2, | ||||
|             Rot2::from_cos_sin_unchecked((1.).into(), (0.).into()), | ||||
|             Rot2::from_cos_sin_unchecked(1., 0.), | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
| @ -66,7 +66,7 @@ impl PointAngle { | ||||
|         Self::new( | ||||
|             p1, | ||||
|             p2, | ||||
|             Rot2::from_cos_sin_unchecked((0.).into(), (1.).into()), | ||||
|             Rot2::from_cos_sin_unchecked(0., 1.), | ||||
|         ) | ||||
|     } | ||||
| } | ||||
| @ -76,7 +76,7 @@ impl Relation for PointAngle { | ||||
|         use Region2::*; | ||||
|         let (mut p1, mut p2) = (self.p1.borrow_mut(), self.p2.borrow_mut()); | ||||
|         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, Region1::Full)); | ||||
|             trace!( | ||||
|                 "PointAngle line: {}, p2 constraint: {}", | ||||
|                 line, | ||||
| @ -92,7 +92,7 @@ impl Relation for PointAngle { | ||||
|             (Singleton(p1), Singleton(p2)) => { | ||||
|                 // if the angle p1 and p2 form is parallel to self.angle, the result
 | ||||
|                 // will have a y component of 0
 | ||||
|                 let r = self.angle.clone().conj() * (p2.clone() - p1.clone()); | ||||
|                 let r = self.angle.conj() * (p2.clone() - p1.clone()); | ||||
|                 trace!("angle.cos: {}", r.x); | ||||
|                 // if relative_eq!(r.y, 0.) {
 | ||||
|                 ResolveResult::Constrained | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user