From 4bc04bd7e346bedb798ed8f9c8b801df21155036 Mon Sep 17 00:00:00 2001 From: artus40 Date: Fri, 15 Feb 2019 13:46:39 +0100 Subject: [PATCH] refactors Problem, adds Solution --- planner/src/bin/weekly.rs | 5 +-- planner/src/solver.rs | 84 +++++++++++++++++---------------------- 2 files changed, 38 insertions(+), 51 deletions(-) diff --git a/planner/src/bin/weekly.rs b/planner/src/bin/weekly.rs index ba046b2..fc5d23f 100644 --- a/planner/src/bin/weekly.rs +++ b/planner/src/bin/weekly.rs @@ -5,20 +5,19 @@ extern crate cookbook; use std::time; use std::fmt::Debug; -use std::fmt::Display; use std::hash::Hash; use cookbook::*; use planner::{ *, Value, solver::{ - Variables, + Solution, Domain, Problem } }; -fn pretty_output(res: &Variables) -> String { +fn pretty_output(res: &Solution) -> String { let mut repr = String::new(); for (var,value) in res { let value = match value { diff --git a/planner/src/solver.rs b/planner/src/solver.rs index c04f48a..ebc3ca9 100644 --- a/planner/src/solver.rs +++ b/planner/src/solver.rs @@ -7,7 +7,9 @@ use std::clone::Clone; use std::collections::HashMap; /// An assignments map of variables -pub type Variables<'a, V> = Vec>; +type Variables<'a, V> = Vec>; +/// A solution returned by [`Solver`] +pub type Solution<'a, V, K> = HashMap>; enum Assignment<'a, V> { Update(usize, &'a V), @@ -124,7 +126,7 @@ impl<'a, V, K: Eq + Hash + Clone> Problem<'a, V, K> { } pub fn from_template() -> Problem<'a, V, K> { - let mut builder = Self::build(); + let builder = Self::build(); builder.finish() } @@ -169,12 +171,8 @@ impl<'a, V, K: Eq + Hash + Clone> Problem<'a, V, K> { return true; } - /// Returns all complete solutions, after visiting all possible outcomes using a stack (DFS). - pub fn solve_all(&mut self) -> Vec> - where V: Clone + fmt::Debug, - K: Clone + fmt::Debug, - { - let mut solutions: Vec> = vec![]; + fn _solve(&mut self, limit: Option) -> 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); @@ -185,7 +183,15 @@ impl<'a, V, K: Eq + Hash + Clone> Problem<'a, V, K> { loop { let node = stack.pop(); + // There is no more combination to try out if node.is_none() { break; }; + // Exit early if we have enough solutions + if limit.is_some() + && solutions.len() == limit.unwrap() + { + break; + }; + match node.unwrap() { Assignment::Update(idx, val) => { // Assign the variable and open new branches, if any. @@ -196,7 +202,12 @@ impl<'a, V, K: Eq + Hash + Clone> Problem<'a, V, K> { } else { // Assignements are completed if self._is_valid() { - solutions.push(self.variables.clone()); + solutions.push( + // Builds Solution + self.keys.iter().cloned() + .zip(self.variables.iter().cloned()) + .collect() + ); }; }; }, @@ -207,44 +218,21 @@ impl<'a, V, K: Eq + Hash + Clone> Problem<'a, V, K> { }; }; solutions - } - pub fn solve_one(&mut self) -> Option> + } + /// Returns all complete solutions, after visiting all possible outcomes using a stack (DFS). + pub fn solve_all(&mut self) -> Vec> where V: Clone + fmt::Debug, K: Clone + fmt::Debug, { - let mut stack: Vec> = vec![]; - if let Some(mut init_updates) = self._push_updates() { - stack.append(&mut init_updates); - } else { - panic!("Could not initialize !"); - } + self._solve(None) // No limit + } - loop { - let node = stack.pop(); - if node.is_none() { - return None; - }; - match node.unwrap() { - Assignment::Update(idx, val) => { - // Assign the variable and open new branches, if any. - self.variables[idx] = Some(val); - // TODO: handle case of empty domain.values - if let Some(mut nodes) = self._push_updates() { - stack.append(&mut nodes); - } else { - // Assignements are completed - if self._is_valid() { - return Some(self.variables.clone()); - }; - }; - }, - Assignment::Clear(idx) => { - // We are closing this branch, unset the variable - self.variables[idx] = None; - }, - }; - } + pub fn solve_one(&mut self) -> Option> + where V: Clone + fmt::Debug, + K: Clone + fmt::Debug, + { + self._solve(Some(1)).pop() } } @@ -294,10 +282,10 @@ mod tests { }) .finish(); - 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(), + let solutions: Vec> = vec![ + [(String::from("Left"), Some(&3)), (String::from("Right"), Some(&3))].iter().cloned().collect(), + [(String::from("Left"), Some(&2)), (String::from("Right"), Some(&2))].iter().cloned().collect(), + [(String::from("Left"), Some(&1)), (String::from("Right"), Some(&1))].iter().cloned().collect(), ]; assert_eq!(problem.solve_all(), solutions); @@ -315,8 +303,8 @@ mod tests { }) .finish(); - let solutions: Vec> = vec![ - [Some(&2), Some(&2)].iter().cloned().collect(), + let solutions: Vec> = vec![ + [(String::from("Left"), Some(&2)), (String::from("Right"), Some(&2))].iter().cloned().collect(), ]; assert_eq!(problem.solve_all(), solutions);