exact_cover/problem.rs
1//! Provides a generic problem type that defines constraints and subsets.
2//!
3//! Every complex exact cover problem (such as polyomino packing or Sudoku) first generates
4//! this basic [`Problem`] instance before handing it to a solver.
5//! To see examples of more complex problems, see [`problems`](crate::problems) module.
6
7use std::hash::Hash;
8use indexmap::{IndexMap, IndexSet};
9
10/// Base trait for subset names and constraints.
11pub trait Value: Clone + Hash + Eq {}
12impl<T: Clone + Hash + Eq> Value for T {}
13
14/// An exact cover problem instance.
15///
16/// The subsets are identified with a name with a type `N`.
17/// The elements of the set are called constraints and have a type `C`.
18///
19/// # Order
20///
21/// The order of subsets and constraints is determined by the insertion order.
22/// It uses [`IndexMap`] and [`IndexSet`] internally to keep track of the order.
23///
24/// The subset order can affect the order of the solutions and
25/// the algorithm performance, but it would not be a significant effect
26/// as our algorithm uses the MRV heuristic.
27#[derive(Clone)]
28#[cfg_attr(test, derive(Debug))]
29pub struct Problem<N: Value, C: Value> { // TOOD: Constraint will be more complex type
30 constraints: IndexSet<C>,
31 subsets: IndexMap<N, Vec<C>>,
32}
33
34impl<N: Value, C: Value> Default for Problem<N, C> {
35 fn default() -> Self {
36 Problem {
37 constraints: Default::default(),
38 subsets: Default::default(),
39 }
40 }
41}
42
43impl<N: Value, C: Value> Problem<N, C> {
44 // TODO: hide IndexMap/IndexSet from API
45 /// Returns a reference to the subsets of the problem.
46 pub fn subsets(&self) -> &IndexMap<N, Vec<C>> { &self.subsets }
47 /// Returns a reference to the constraints of the problem.
48 pub fn constraints(&self) -> &IndexSet<C> { &self.constraints }
49
50 /// Adds a subset to the problem.
51 ///
52 /// If the subset name already exists,
53 /// it updates the subset of that name with the given new subset.
54 pub fn add_subset(&mut self, name: N, subset: Vec<C>) {
55 self.subsets.insert(name, subset);
56 }
57
58 /// Adds a constraint (set element) to the problem.
59 pub fn add_constraint(&mut self, constraint: C) {
60 self.constraints.insert(constraint);
61 }
62
63 /// Adds several constraints to the problem.
64 pub fn add_constraints<I: IntoIterator<Item = C>>(&mut self, constraints: I) {
65 for constraint in constraints {
66 self.constraints.insert(constraint);
67 }
68 }
69}
70
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn problem_can_be_created() {
78 let mut prob = Problem::default();
79 prob.add_constraints(1..=7);
80 prob.add_subset("A", vec![3, 5, 6]);
81 prob.add_subset("B", vec![1, 4, 7]);
82 prob.add_subset("C", vec![2, 3, 6]);
83 prob.add_subset("D", vec![1, 4]);
84 prob.add_subset("E", vec![2, 7]);
85 prob.add_subset("F", vec![4, 5, 7]);
86 }
87}