dancing_links/
solver.rs

1use crate::{
2    grid::{Column, Grid, Node},
3    ExactCover,
4};
5use core::iter;
6use std::collections::VecDeque;
7
8/// Solver that iteratively returns solutions to exact cover problems.
9#[derive(Debug)]
10pub struct Solver<'e, E: ExactCover> {
11    problem: &'e E,
12
13    // Values used to track the state of solving
14    grid: Grid,
15    partial_solution: Vec<usize>,
16    stack: Vec<Frame>,
17}
18
19#[derive(Debug)]
20enum FrameState {
21    // Before covering one of the rows
22    Cover,
23    // After checking, before uncovering
24    Uncover,
25}
26
27#[derive(Debug)]
28struct Frame {
29    #[allow(dead_code)]
30    min_column: *mut Column,
31    selected_rows: VecDeque<(usize, Vec<*mut Column>)>,
32    state: FrameState,
33}
34
35impl<'e, E> Solver<'e, E>
36where
37    E: ExactCover,
38{
39    /// Create a new `Solver` with the given instance of an exact cover problem.
40    pub fn new(problem: &'e E) -> Self {
41        let grid = Self::populate_grid(problem);
42
43        let mut solver = Self {
44            problem,
45
46            grid,
47            partial_solution: Vec::new(),
48            stack: Vec::new(),
49        };
50
51        // If the grid is already solved (no primary columns), don't bother to put a
52        // stack frame in
53        if !Self::solution_test(&solver.grid, solver.problem) {
54            let min_column = Self::choose_column(&mut solver.grid, solver.problem);
55            let selected_rows = Self::select_rows_from_column(min_column);
56
57            if !selected_rows.is_empty() {
58                solver.stack.push(Frame {
59                    state: FrameState::Cover,
60                    min_column,
61                    selected_rows,
62                });
63            }
64        }
65
66        solver
67    }
68
69    /// Reset all solver state except for the stored possibilities and
70    /// constraints.
71    pub fn reset(&mut self) {
72        self.grid = Self::populate_grid(self.problem);
73        self.partial_solution.clear();
74        self.stack.clear();
75    }
76
77    fn populate_grid(problem: &E) -> Grid {
78        let coordinates_iter = problem
79            .possibilities()
80            .iter()
81            .enumerate()
82            .flat_map({
83                move |(row_idx, poss)| {
84                    problem
85                        .constraints()
86                        .iter()
87                        .enumerate()
88                        .zip(iter::repeat((row_idx, poss)))
89                        .map({
90                            |((col_idx, cons), (row_idx, poss))| {
91                                ((row_idx + 1, col_idx + 1), poss, cons)
92                            }
93                        })
94                }
95            })
96            .filter_map(|(coord, poss, cons)| {
97                if problem.satisfies(poss, cons) {
98                    Some(coord)
99                } else {
100                    None
101                }
102            });
103
104        Grid::new(problem.constraints().len(), coordinates_iter)
105    }
106
107    fn solution_test(grid: &Grid, problem: &E) -> bool {
108        !grid
109            .uncovered_columns()
110            .any(|column| !problem.is_optional(&problem.constraints()[Column::index(column) - 1]))
111    }
112
113    fn choose_column(grid: &mut Grid, problem: &E) -> *mut Column {
114        grid.uncovered_columns_mut()
115            .filter(|column| {
116                !problem.is_optional(&problem.constraints()[Column::index(*column as *const _) - 1])
117            })
118            .min_by_key(|column_ptr| Column::size(*column_ptr))
119            .unwrap()
120    }
121
122    fn select_rows_from_column(min_column: *mut Column) -> VecDeque<(usize, Vec<*mut Column>)> {
123        Column::rows(min_column)
124            .map(|node_ptr| {
125                (
126                    Node::row_index(node_ptr),
127                    Node::neighbors(node_ptr)
128                        .map(Node::column_ptr)
129                        .chain(iter::once(Node::column_ptr(node_ptr)))
130                        .collect(),
131                )
132            })
133            .collect()
134    }
135
136    /// Return all possible solutions.
137    pub fn all_solutions(&mut self) -> Vec<Vec<&'e E::Possibility>> {
138        self.collect()
139    }
140
141    /// Compute up to the next solution, returning `None` if there are no more.
142    pub fn next_solution<'s>(&'s mut self) -> Option<Vec<&'e E::Possibility>>
143    where
144        'e: 's,
145    {
146        enum StackOp<T> {
147            Push(T),
148            Pop,
149            None,
150        }
151
152        while !self.stack.is_empty() {
153            let curr_frame = self.stack.last_mut().unwrap();
154
155            let (stack_op, possible_solution) = match curr_frame.state {
156                // for the current row of this frame, cover the selected columns and add the row
157                // to the solution.
158                FrameState::Cover => {
159                    let (row_index, columns) = curr_frame.selected_rows.front().unwrap();
160
161                    self.partial_solution.push(row_index - 1);
162                    for column_ptr in columns {
163                        Column::cover(*column_ptr);
164                    }
165
166                    // This is where the recursion happens, but we also have to check for the
167                    // solution here.
168                    let stack_op = if Self::solution_test(&self.grid, self.problem) {
169                        (StackOp::None, Some(self.partial_solution.clone()))
170                    } else {
171                        let min_column = Self::choose_column(&mut self.grid, self.problem);
172                        let selected_rows = Self::select_rows_from_column(min_column);
173
174                        if selected_rows.is_empty() {
175                            (StackOp::None, None)
176                        } else {
177                            (
178                                StackOp::Push(Frame {
179                                    state: FrameState::Cover,
180                                    min_column,
181                                    selected_rows,
182                                }),
183                                None,
184                            )
185                        }
186                    };
187
188                    curr_frame.state = FrameState::Uncover;
189                    stack_op
190                }
191                // Cleanup the current row, uncover the selected columns, remove the row from
192                // the solution.
193                FrameState::Uncover => {
194                    let (_row_index, columns) = curr_frame.selected_rows.pop_front().unwrap();
195
196                    for column_ptr in columns.into_iter().rev() {
197                        Column::uncover(column_ptr);
198                    }
199                    self.partial_solution.pop();
200
201                    if curr_frame.selected_rows.is_empty() {
202                        (StackOp::Pop, None)
203                    } else {
204                        curr_frame.state = FrameState::Cover;
205                        (StackOp::None, None)
206                    }
207                }
208            };
209
210            match stack_op {
211                StackOp::Push(val) => {
212                    self.stack.push(val);
213                }
214                StackOp::Pop => {
215                    self.stack.pop();
216                }
217                StackOp::None => {}
218            }
219
220            if let Some(solution) = possible_solution {
221                return Some(
222                    solution
223                        .into_iter()
224                        .map(|row_index| &self.problem.possibilities()[row_index])
225                        .collect(),
226                );
227            }
228        }
229
230        None
231    }
232}
233
234impl<'e, E> Iterator for Solver<'e, E>
235where
236    E: ExactCover,
237{
238    type Item = Vec<&'e E::Possibility>;
239
240    fn next(&mut self) -> Option<Self::Item> {
241        self.next_solution()
242    }
243}