From 4b21fd873bdbcb5243a4021742ec60fb01578e3d Mon Sep 17 00:00:00 2001 From: artus40 Date: Thu, 14 Feb 2019 21:50:19 +0100 Subject: [PATCH] breaking things up, refactors Problem with vectors... --- planner/src/solver.rs | 90 +++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/planner/src/solver.rs b/planner/src/solver.rs index e5d4607..c04f48a 100644 --- a/planner/src/solver.rs +++ b/planner/src/solver.rs @@ -7,11 +7,11 @@ use std::clone::Clone; use std::collections::HashMap; /// An assignments map of variables -pub type Variables<'a, V, K> = HashMap>; +pub type Variables<'a, V> = Vec>; -enum Assignment<'a, V, K> { - Update(K, &'a V), - Clear(K) +enum Assignment<'a, V> { + Update(usize, &'a V), + Clear(usize) } /// Collection of references to values owned by a domain. @@ -99,7 +99,7 @@ impl fmt::Debug for Domain { } -pub type Constraint<'a,V, K> = fn(&Variables<'a,V, K>) -> bool; +pub type Constraint<'a,V> = fn(&Variables<'a,V>) -> bool; /// Could be more efficient to just use fixed array of options as variables, @@ -108,12 +108,13 @@ pub type Constraint<'a,V, K> = fn(&Variables<'a,V, K>) -> bool; /// It makes sense with an array where indexing is O(1) pub struct Problem<'a, V, K> { + keys: Vec, /// The initial assignements map - variables: Variables<'a, V, K>, + variables: Variables<'a, V>, /// Each variable has its associated domain - domains: HashMap>, + domains: Vec>, /// Set of constraints to validate - constraints: Vec>, + constraints: Vec>, } impl<'a, V, K: Eq + Hash + Clone> Problem<'a, V, K> { @@ -130,7 +131,7 @@ impl<'a, V, K: Eq + Hash + Clone> Problem<'a, V, K> { /// Returns all possible Updates for next assignements, prepended with /// a Clear to ensure the variable is unset before when leaving the branch. - fn _push_updates(&self) -> Option>> { + fn _push_updates(&self) -> Option>> { // TODO: should be able to inject a choosing strategy if let Some(key) = self._next_assign() { let domain_values = self.domains @@ -142,10 +143,7 @@ impl<'a, V, K: Eq + Hash + Clone> Problem<'a, V, K> { // TODO: should be able to filter domain values (inference, pertinence) domain_values.iter().for_each(|value| { updates.push( - Assignment::Update( - key.clone(), - *value - ) + Assignment::Update(key, *value) ); }); Some(updates) @@ -154,11 +152,11 @@ impl<'a, V, K: Eq + Hash + Clone> Problem<'a, V, K> { } } - fn _next_assign(&self) -> Option<&K> { - self.variables - .iter() - .find_map(|(key, val)| { - if val.is_none() { Some(key) } + fn _next_assign(&self) -> Option { + self.variables.iter() + .enumerate() + .find_map(|(idx, val)| { + if val.is_none() { Some(idx) } else { None } }) } @@ -172,12 +170,12 @@ impl<'a, V, K: Eq + Hash + Clone> Problem<'a, V, K> { } /// Returns all complete solutions, after visiting all possible outcomes using a stack (DFS). - pub fn solve_all(&mut self) -> Vec> + pub fn solve_all(&mut self) -> Vec> where V: Clone + fmt::Debug, K: Clone + fmt::Debug, { - let mut solutions: Vec> = vec![]; - let mut stack: Vec> = vec![]; + let mut solutions: Vec> = vec![]; + let mut stack: Vec> = vec![]; if let Some(mut init_updates) = self._push_updates() { stack.append(&mut init_updates); } else { @@ -189,9 +187,9 @@ impl<'a, V, K: Eq + Hash + Clone> Problem<'a, V, K> { let node = stack.pop(); if node.is_none() { break; }; match node.unwrap() { - Assignment::Update(key, val) => { + Assignment::Update(idx, val) => { // Assign the variable and open new branches, if any. - *self.variables.get_mut(&key).unwrap() = Some(val); + self.variables[idx] = Some(val); // TODO: handle case of empty domain.values if let Some(mut nodes) = self._push_updates() { stack.append(&mut nodes); @@ -202,20 +200,20 @@ impl<'a, V, K: Eq + Hash + Clone> Problem<'a, V, K> { }; }; }, - Assignment::Clear(key) => { + Assignment::Clear(idx) => { // We are closing this branch, unset the variable - *self.variables.get_mut(&key).unwrap() = None; + self.variables[idx] = None; }, }; }; solutions } - pub fn solve_one(&mut self) -> Option> + pub fn solve_one(&mut self) -> Option> where V: Clone + fmt::Debug, K: Clone + fmt::Debug, { - let mut stack: Vec> = vec![]; + let mut stack: Vec> = vec![]; if let Some(mut init_updates) = self._push_updates() { stack.append(&mut init_updates); } else { @@ -228,9 +226,9 @@ impl<'a, V, K: Eq + Hash + Clone> Problem<'a, V, K> { return None; }; match node.unwrap() { - Assignment::Update(key, val) => { + Assignment::Update(idx, val) => { // Assign the variable and open new branches, if any. - *self.variables.get_mut(&key).unwrap() = Some(val); + self.variables[idx] = Some(val); // TODO: handle case of empty domain.values if let Some(mut nodes) = self._push_updates() { stack.append(&mut nodes); @@ -241,9 +239,9 @@ impl<'a, V, K: Eq + Hash + Clone> Problem<'a, V, K> { }; }; }, - Assignment::Clear(key) => { + Assignment::Clear(idx) => { // We are closing this branch, unset the variable - *self.variables.get_mut(&key).unwrap() = None; + self.variables[idx] = None; }, }; } @@ -256,20 +254,22 @@ impl<'a, V, K: Eq + Hash + Clone> ProblemBuilder<'a, V, K> { fn new() -> ProblemBuilder<'a, V, K> { ProblemBuilder( Problem{ + keys: Vec::new(), variables: Variables::new(), - domains: HashMap::new(), + domains: Vec::new(), constraints: Vec::new(), }) } pub fn add_variable(mut self, name: K, domain: Vec<&'a V>, value: Option<&'a V>) -> Self { - self.0.variables.insert(name.clone(), value); - self.0.domains.insert(name, domain); + self.0.keys.push(name); + self.0.variables.push(value); + self.0.domains.push(domain); self } - pub fn add_constraint(mut self, cons: Constraint<'a,V, K>) -> Self { + pub fn add_constraint(mut self, cons: Constraint<'a,V>) -> Self { self.0.constraints.push(cons); self } @@ -289,15 +289,15 @@ mod tests { let mut problem: Problem<_, _> = Problem::build() .add_variable(String::from("Left"), domain.all(), None) .add_variable(String::from("Right"), domain.all(), None) - .add_constraint(|assign: &Variables| { - assign.get("Left").unwrap() == assign.get("Right").unwrap() + .add_constraint(|assign: &Variables| { + assign[0] == assign[1] }) .finish(); - let solutions: Vec> = vec![ - [("Left".to_string(), Some(&3)), ("Right".to_string(), Some(&3)),].iter().cloned().collect(), - [("Left".to_string(), Some(&2)), ("Right".to_string(), Some(&2)),].iter().cloned().collect(), - [("Left".to_string(), Some(&1)), ("Right".to_string(), Some(&1)),].iter().cloned().collect(), + let solutions: Vec> = vec![ + [Some(&3), Some(&3)].iter().cloned().collect(), + [Some(&2), Some(&2)].iter().cloned().collect(), + [Some(&1), Some(&1)].iter().cloned().collect(), ]; assert_eq!(problem.solve_all(), solutions); @@ -310,13 +310,13 @@ mod tests { let mut problem: Problem<_, _> = Problem::build() .add_variable("Left".to_string(), domain.all(), None) .add_variable("Right".to_string(), domain.all(), Some(&2)) - .add_constraint( |assign: &Variables| { - assign.get("Left").unwrap() == assign.get("Right").unwrap() + .add_constraint( |assign: &Variables| { + assign[0] == assign[1] }) .finish(); - let solutions: Vec> = vec![ - [("Left".to_string(), Some(&2)), ("Right".to_string(), Some(&2)),].iter().cloned().collect(), + let solutions: Vec> = vec![ + [Some(&2), Some(&2)].iter().cloned().collect(), ]; assert_eq!(problem.solve_all(), solutions);