1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
//! `backtrack` lets you solve [backtracking](https://en.wikipedia.org/wiki/Backtracking) problems //! simply and generically. //! //! Problems are defined by their *scope* and *checks* against possible solutions. //! //! A [Scope](crate::problem::Scope) determines length and allowed values of a solution. //! The domain defaults to `usize`, but any `T` works if it lives as long as its `Scope`, including references. //! //! The [Check](crate::problem::Check) or [CheckInc](crate::problem::CheckInc) trait determines whether //! a particular combination of values is satisfying. //! //! //! ## Usage //! //! It is required that solutions shorter than the entire scope, i.e. partial //! solutions must satisfy if the completed solutions should as well. //! //! [Solvers](crate::solvers) borrow a problem in search for //! [candidate solutions](crate::solve::CandidateSolution). //! //! ### Checks //! We define the problem of counting down with a limited set of numbers and solve iteratively. //! ```rust //! use backtrack::problem::{Check, Scope}; //! use backtrack::solvers::IterSolveNaive; //! // helper trait to filter solutions of interest //! use backtrack::solve::IterSolveExt; //! //! /// Obtain permutations of some 3 descending numbers //! struct CountDown {} //! //! impl Scope<'_> for CountDown { //! fn size(&self) -> usize { 3 } //! fn value(&self, index: usize) -> usize { index } //! fn len(&self) -> usize { 4 } //! } //! //! impl Check for CountDown{ //! fn extends_sat(&self, solution: &[usize], x: &usize) -> bool { //! solution.last().map_or(true, |last| *last > *x) //! } //! } //! //! let solver = IterSolveNaive::new(&CountDown{}); //! let mut sats = solver.sat_iter(); //! //! assert_eq!(sats.next(), Some(vec![2, 1, 0])); //! assert_eq!(sats.next(), Some(vec![3, 1, 0])); //! assert_eq!(sats.next(), Some(vec![3, 2, 0])); //! assert_eq!(sats.next(), Some(vec![3, 2, 1])); //! assert_eq!(sats.next(), None); //! ``` //! ### Incremental Checks //! If your checks can be formulated against a reduced solution, //! implement [CheckInc](crate::problem::CheckInc) instead. //! //! The same result as above can be obtained by first computing //! intermediate values for any given sat check. Such an approach makes sense if //! work between prior candidate values should be reused. //! //! ```rust //! use backtrack::problem::{CheckInc, Scope}; //! use backtrack::solvers::{IterSolveCached}; //! // ... //! # use backtrack::solve::IterSolveExt; //! # //! # struct CountDown {} //! # //! # impl Scope<'_> for CountDown { //! # fn size(&self) -> usize { 3 } //! # fn value(&self, index: usize) -> usize { index } //! # fn len(&self) -> usize { 4 } //! # } //! # //! impl CheckInc for CountDown{ //! type Accumulator = (usize, bool); //! //! fn fold_acc(&self, accu: Option<Self::Accumulator>, x: &usize, _position: usize) -> Self::Accumulator { //! // remember last value and if it was larger than current one //! accu.map_or_else(||(*x, true), |last| (*x, last.0 > *x)) //! } //! //! fn accu_sat(&self, accu: &Self::Accumulator, _x: &usize, _position: usize) -> bool { //! accu.1 //! } //! } //! // since `CheckInc` works from accumulated state, a solver that caches them should be used //! let mut sats = IterSolveCached::new(&CountDown{}).sat_iter(); //! // ... gives the same results as above //! # //! # assert_eq!(sats.next(), Some(vec![2, 1, 0])); //! # assert_eq!(sats.next(), Some(vec![3, 1, 0])); //! # assert_eq!(sats.next(), Some(vec![3, 2, 0])); //! # assert_eq!(sats.next(), Some(vec![3, 2, 1])); //! # assert_eq!(sats.next(), None); //! ``` pub mod problem; pub mod problems; pub mod solve; pub mod solvers;