dlx_rs/solver.rs
1use std::collections::HashMap;
2use std::fmt::{self, Debug};
3type Index = usize;
4
5#[derive(Clone, Debug)]
6enum Link {
7 Spacer(Spacer),
8 Item(Item),
9 OptionElement(OptionElement),
10}
11
12#[derive(Clone, Debug)]
13struct OptionElement {
14 ulink: Index,
15 dlink: Index,
16 top: Index,
17}
18
19#[derive(Clone, Debug)]
20struct Spacer {
21 ulink: Index,
22 dlink: Index,
23}
24
25#[derive(Clone, Debug)]
26struct Item {
27 ulink: Index,
28 dlink: Index,
29 rlink: Index,
30 llink: Index,
31 l: usize,
32}
33
34/// Implements the linked lists, which are structured in the following way
35/// ```text
36/// i0 ⟷ i1 ⟷ i2 ⟷ i3 ⟷ i4
37/// ⥯ ⥯ ⥯ ⥯ s0
38/// o1 ⦿ ⦿ ⥯ ⥯ s1
39/// o2 ⥯ ⥯ ⦿ ⥯ s2
40/// o3 ⥯ ⦿ ⥯ ⦿ s3
41/// o4 ⦿ ⥯ ⥯ ⥯ s4
42/// ⥯ ⥯ ⥯ ⥯
43/// ```
44/// where arrows denote links.
45///
46/// The spacers s0,..., also form a doubly circularly linked list.
47///
48/// i0 is the root node for the linked list of items i1,...,.i4
49///
50/// s0 is the root node for the spacers which link vertically to each other
51///
52/// ⦿ denote the option elements which contain links up and down and also reference their "parent" item
53///
54/// We may set up and solve this problem with the following code
55/// ```
56///# use std::error::Error;
57///# use dlx_rs::solver::Solver;
58///# fn main() -> Result<(), Box<dyn Error>> {
59/// // Create Solver with 4 items
60/// let mut s = Solver::new(4);
61/// // Add options
62/// s.add_option("o1", &[1, 2])
63/// .add_option("o2", &[3])
64/// .add_option("o3", &[2, 4])
65/// .add_option("o4", &[1]);
66///
67/// // Iterate through all solutions
68/// if let Some(solution) = s.next() {
69/// assert_eq!(solution, ["o2","o3","o4"]);
70/// Ok(())
71/// }
72/// else {
73/// Err("No solution found".into())
74/// }
75///# }
76/// ```
77#[derive(Clone)]
78pub struct Solver<T>
79where
80 T: std::fmt::Debug + PartialEq + Clone,
81{
82 elements: Vec<Link>,
83 items: Index,
84 options: HashMap<Index, Vec<Index>>,
85 l: usize,
86 sol_vec: Vec<Index>,
87 yielding: bool,
88 idx: Index,
89 names: Vec<T>,
90 spacer_ids: HashMap<Index, usize>,
91 stage: Stage,
92 optional: Index,
93}
94
95/// enum used to determine which stage of the algorithm we are in
96///
97/// This approach avoids recursive function calls which, in very large problems, can cause a stack overflow
98#[derive(Clone)]
99enum Stage {
100 X2,
101 X3,
102 X5,
103 X6,
104 X8,
105}
106
107impl<T: std::fmt::Debug + PartialEq + Clone> fmt::Display for Solver<T> {
108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109 // First write columns
110 let mut last_col = 1;
111 let mut linked_items = HashMap::new();
112 let mut col_num = 0;
113
114 write!(f, " ").unwrap();
115 // First print only the linked items, and find their column numbers
116 let mut index = self.elements[0].r();
117 while index != 0 {
118 linked_items.insert(index, col_num);
119 col_num += 1;
120 write!(f, "{} ", index).unwrap();
121 index = self.elements[index].r();
122 }
123
124 // println!("Linked items: {:?}",linked_items);
125 // println!("Linked items: {:?}",linked_items.keys());
126
127 for i in self.elements.iter().skip(1 + self.items) {
128 match *i {
129 Link::Item(_) => {}
130 Link::Spacer(_) => {
131 writeln!(f).unwrap();
132 last_col = 0;
133 }
134 Link::OptionElement(_) => {
135 if let Some(&cur_col) = linked_items.get(&i.top()) {
136 // println!("Cur_col: {}, last col: {}", cur_col, last_col);
137 let del = 2 * (1 + cur_col - last_col);
138 // println!("del: {}",del);
139 write!(f, "{:del$}", i.top()).unwrap();
140 last_col = cur_col + 1;
141 };
142 }
143 };
144 }
145
146 write!(f, "")
147 }
148}
149impl Link {
150 fn u(&self) -> Index {
151 match self {
152 Link::Spacer(x) => x.ulink,
153 Link::OptionElement(x) => x.ulink,
154 Link::Item(x) => x.ulink,
155 }
156 }
157 fn d(&self) -> Index {
158 match self {
159 Link::Spacer(x) => x.dlink,
160 Link::OptionElement(x) => x.dlink,
161 Link::Item(x) => x.dlink,
162 }
163 }
164 fn r(&self) -> Index {
165 match self {
166 Link::Spacer(_) => 0,
167 Link::OptionElement(_) => 0,
168 Link::Item(x) => x.rlink,
169 }
170 }
171 fn l(&self) -> Index {
172 match self {
173 Link::Spacer(_) => 0,
174 Link::OptionElement(_) => 0,
175 Link::Item(x) => x.llink,
176 }
177 }
178 fn set_u(&mut self, u: Index) {
179 match self {
180 Link::Spacer(x) => x.ulink = u,
181 Link::OptionElement(x) => x.ulink = u,
182 Link::Item(x) => x.ulink = u,
183 }
184 }
185 fn set_d(&mut self, d: Index) {
186 match self {
187 Link::Spacer(x) => x.dlink = d,
188 Link::OptionElement(x) => x.dlink = d,
189 Link::Item(x) => x.dlink = d,
190 }
191 }
192 fn set_r(&mut self, u: Index) {
193 match self {
194 Link::Spacer(_) => {}
195 Link::OptionElement(_) => {}
196 Link::Item(x) => x.rlink = u,
197 }
198 }
199 fn set_l(&mut self, d: Index) {
200 match self {
201 Link::Spacer(_) => {}
202 Link::OptionElement(_) => {}
203 Link::Item(x) => x.llink = d,
204 }
205 }
206 fn top(&self) -> Index {
207 match self {
208 Link::Spacer(_) => 0,
209 Link::OptionElement(x) => x.top,
210 Link::Item(_) => 0,
211 }
212 }
213 fn inc_l(&mut self) {
214 match self {
215 Link::Spacer(_) => {}
216 Link::OptionElement(_) => {}
217 Link::Item(x) => x.l += 1,
218 }
219 }
220 fn dec_l(&mut self) {
221 match self {
222 Link::Spacer(_) => {}
223 Link::OptionElement(_) => {}
224 Link::Item(x) => x.l -= 1,
225 }
226 }
227 fn get_l(&self) -> usize {
228 match self {
229 Link::Spacer(_) => 0,
230 Link::OptionElement(_) => 0,
231 Link::Item(x) => x.l,
232 }
233 }
234}
235/*
236impl Link for Spacer {
237 fn clone_dyn(&self) -> Box<dyn Link> {
238 Box::new(self.clone())
239 }
240}
241*/
242
243impl<T: PartialEq + Debug + Clone> Solver<T> {
244 /// Returns a solver with `n` items, all of which must be covered exactly
245 /// once
246 pub fn new(n: Index) -> Self {
247 Self::new_optional(n, 0)
248 }
249
250 /// Returns a solver with `n` mandatory items and `m` optional items to be covered
251 /// This allows us to include items which may or may not be covered (but
252 /// still may not be covered more than once)
253 ///
254 /// Example, where optional elements are after |
255 /// ```text
256 /// i1 i2 i3 i4 | i5
257 /// o1 1 0 1 0 | 0
258 /// o2 0 1 0 1 | 0
259 /// o3 1 0 0 0 | 1
260 /// o4 0 0 1 0 | 0
261 /// o5 0 0 1 0 | 1
262 /// ```
263 /// Here we can see taking \[o1,o2\] works, as does \[o2,o3,o4\], but *not*
264 /// \[o2,o3,o5\], because then i4 would be double covered
265 ///
266 /// The code that does this is
267 /// ```
268 ///# use dlx_rs::solver::Solver;
269 ///
270 /// let mut s = Solver::new_optional(4,1);
271 ///
272 /// s.add_option("o1", &[1, 3])
273 /// .add_option("o2", &[2, 4])
274 /// .add_option("o3", &[1, 5])
275 /// .add_option("o4", &[3])
276 /// .add_option("o5", &[3, 5]);
277 ///
278 /// let s1 = s.next().unwrap_or_default();
279 /// let s2 = s.next().unwrap_or_default();
280 /// let s3 = s.next();
281 /// assert_eq!(s1,["o2","o1"]);
282 /// assert_eq!(s2,["o2","o3","o4"]);
283 /// assert_eq!(s3,None);
284 /// ```
285 ///
286 pub fn new_optional(mandatory: Index, opt: Index) -> Self {
287 // optional stores the index where the optional parameters begin: this
288 // is required for both checking completeness of solution (in step X2)
289 // and also in choosing MRV (step X3)
290 let optional = mandatory + 1;
291 let n = mandatory + opt;
292 // First add null at element 0 (allows us to traverse items list)
293 let mut elements: Vec<Link> = vec![Link::Item(Item {
294 ulink: 0,
295 dlink: 0,
296 rlink: 1,
297 llink: n,
298 l: 0,
299 })];
300 // Now add items
301 for i in 1..=n {
302 let rlink = match i {
303 _ if i < n => i + 1,
304 _ if i == n => 0,
305 _ => panic!("Invalid index"),
306 };
307 elements.push(Link::Item(Item {
308 ulink: i,
309 dlink: i,
310 llink: i - 1,
311 rlink,
312 l: 0,
313 }));
314 }
315
316 // Add first spacer
317 let spacer_index = elements.len();
318 assert_eq!(spacer_index, n + 1);
319 let spacer = Link::Spacer(Spacer {
320 ulink: spacer_index,
321 dlink: spacer_index,
322 });
323 elements.push(spacer);
324
325 Solver {
326 optional,
327 elements,
328 items: n,
329 options: HashMap::new(),
330 l: 0,
331 sol_vec: vec![],
332 names: vec![],
333 spacer_ids: HashMap::new(),
334 yielding: true,
335 idx: 0,
336 stage: Stage::X2,
337 }
338 }
339
340 /// Adds an option which would cover items defined by `option`, and with name `name
341 /// Specifically if our problems looks like
342 ///
343 /// ```text
344 /// i0 ⟷ i1 ⟷ i2 ⟷ i3 ⟷ i4
345 /// ⥯ ⥯ ⥯ ⥯ s0
346 /// o1 ⦿ ⦿ ⥯ ⥯ s1
347 /// o2 ⥯ ⥯ ⦿ ⥯ s2
348 /// o3 ⥯ ⦿ ⥯ ⦿ s3
349 /// o4 ⦿ ⥯ ⥯ ⥯ s4
350 /// ⥯ ⥯ ⥯ ⥯
351 /// ```
352 /// then `add_option("o5", &[1,2])` would take it to
353 /// ```text
354 /// i0 ⟷ i1 ⟷ i2 ⟷ i3 ⟷ i4
355 /// ⥯ ⥯ ⥯ ⥯ s0
356 /// o1 ⦿ ⦿ ⥯ ⥯ s1
357 /// o2 ⥯ ⥯ ⦿ ⥯ s2
358 /// o3 ⥯ ⦿ ⥯ ⦿ s3
359 /// o4 ⦿ ⥯ ⥯ ⥯ s4
360 /// o5 ⦿ ⦿ ⥯ ⥯ s5
361 /// ⥯ ⥯ ⥯ ⥯
362 /// ```
363 pub fn add_option(&mut self, name: T, option: &[Index]) -> &mut Self {
364 // Increase max depth, come back to this later
365 self.sol_vec.push(0);
366 // self.sol_vec.push(0);
367
368 // Now add elements from the option
369
370 for &item_id in option {
371 let new_ulink = self.elements[item_id].u();
372 let new_id = self.elements.len();
373 self.elements[new_ulink].set_d(new_id);
374 self.elements[item_id].set_u(new_id);
375 self.elements[item_id].inc_l();
376 let new_node = Link::OptionElement(OptionElement {
377 ulink: new_ulink,
378 dlink: item_id,
379 top: item_id,
380 });
381
382 self.elements.push(new_node);
383 }
384
385 //Add spacer at the end
386 //Create new spacer
387 let spacer_index = self.elements.len();
388 let root_spacer_index = self.items + 1;
389 let bottom_spacer_index = self.elements[root_spacer_index].u();
390 let new_spacer = Link::Spacer(Spacer {
391 dlink: root_spacer_index,
392 ulink: bottom_spacer_index,
393 });
394 self.elements.push(new_spacer);
395 // Patch old spacers
396 //Old bottom dlink = new spacer
397 self.elements[bottom_spacer_index].set_d(spacer_index);
398 // Patch root ulink
399 self.elements[root_spacer_index].set_u(spacer_index);
400
401 // Add the entry to the hash table
402 self.options.insert(spacer_index, option.to_vec());
403 self.names.push(name.clone());
404 self.spacer_ids.insert(spacer_index, self.names.len() - 1);
405
406 self
407 }
408
409 /// Covers item in column `i`
410 /// i.e. `cover(2)` would transform
411 ///
412 /// ```text
413 /// i0 ⟷ i1 ⟷ i2 ⟷ i3 ⟷ i4
414 /// ⥯ ⥯ ⥯ ⥯ s0
415 /// o1 ⦿ ⦿ ⥯ ⥯ s1
416 /// o2 ⥯ ⥯ ⦿ ⥯ s2
417 /// o3 ⥯ ⦿ ⥯ ⦿ s3
418 /// o4 ⦿ ⥯ ⥯ ⥯ s4
419 /// ⥯ ⥯ ⥯ ⥯
420 /// ```
421 /// into
422 ///
423 /// ```text
424 /// i0 ⟷ i1 ⟷ ⟷ ⟷ i3 ⟷ i4
425 /// ⥯ ⥯ ⥯ s0
426 /// o1 ⦿ ⥯ ⥯ s1
427 /// o2 ⥯ ⦿ ⥯ s2
428 /// o3 ⥯ ⥯ ⦿ s3
429 /// o4 ⦿ ⥯ ⥯ s4
430 /// ⥯ ⥯ ⥯
431 /// ```
432 pub fn cover(&mut self, i: Index) -> Result<(), &'static str> {
433 let col = &mut self.elements[i];
434 match col {
435 Link::Item(_) => {}
436 _ => return Err("Can only cover items"),
437 };
438 // Hide all of the options in col i
439 let mut p = col.d();
440 while p != i {
441 self.hide(p)?;
442 p = self.elements[p].d();
443 }
444
445 // Unlink item
446 self.unlink_item(i);
447 //let l = self.elements[i].l();
448 //let r = self.elements[i].r();
449 //self.elements[l].set_r(r);
450 //self.elements[r].set_l(l);
451
452 Ok(())
453 }
454
455 /// Unlinks an item from the horizontally linked list
456 fn unlink_item(&mut self, i: Index) {
457 let l = self.elements[i].l();
458 let r = self.elements[i].r();
459 self.elements[l].set_r(r);
460 self.elements[r].set_l(l);
461 }
462
463 /// Relinks an item into the horizontally linked list
464 ///
465 /// Must be done in the reverse order to unlinking
466 fn relink_item(&mut self, i: Index) {
467 let l = self.elements[i].l();
468 let r = self.elements[i].r();
469 self.elements[l].set_r(i);
470 self.elements[r].set_l(i);
471 }
472
473 /// When selecting an option, this runs through all of the items it covers
474 /// and unlinks those OptionElements vertically
475 fn hide(&mut self, p: Index) -> Result<(), &'static str> {
476 let mut q = p + 1;
477 while q != p {
478 let x = self.elements[q].top();
479 let u = self.elements[q].u();
480 let d = self.elements[q].d();
481
482 match self.elements[q] {
483 Link::Item(_) => return Err("Hide encountered and item"),
484 Link::Spacer(_) => q = u,
485 Link::OptionElement(_) => {
486 self.elements[u].set_d(d);
487 self.elements[d].set_u(u);
488 self.elements[x].dec_l();
489 }
490 };
491 q += 1;
492 }
493
494 Ok(())
495 }
496
497 /// Reverse of function [cover](crate::solver::Solver::cover)
498 pub fn uncover(&mut self, i: Index) -> Result<(), &'static str> {
499 // Relink item
500 self.relink_item(i);
501 //let l = self.elements[i].l();
502 //let r = self.elements[i].r();
503 //self.elements[l].set_r(i);
504 //self.elements[r].set_l(i);
505
506 let col = &mut self.elements[i];
507
508 match col {
509 Link::Item(_) => {}
510 _ => return Err("Can only uncover items"),
511 };
512
513 // Hide all of the options in col i
514 let mut p = col.u();
515 while p != i {
516 self.unhide(p)?;
517 p = self.elements[p].u();
518 }
519
520 Ok(())
521 }
522
523 /// Reverse of function [hide](crate::solver::Solver::hide)
524 fn unhide(&mut self, p: Index) -> Result<(), &'static str> {
525 let mut q = p - 1;
526 while q != p {
527 let x = self.elements[q].top();
528 let u = self.elements[q].u();
529 let d = self.elements[q].d();
530
531 match self.elements[q] {
532 Link::Item(_) => return Err("Hide encountered and item"),
533 Link::Spacer(_) => q = d,
534 Link::OptionElement(_) => {
535 self.elements[u].set_d(q);
536 self.elements[d].set_u(q);
537 self.elements[x].inc_l();
538 }
539 };
540 q -= 1;
541 }
542
543 Ok(())
544 }
545
546 /// Implements algorithm X as a finite state machine
547 #[allow(dead_code)]
548 pub fn solve(&mut self) -> Option<Vec<T>> {
549 // Follows stages of algorithm description in Fasc 5c, Knuth
550
551 // The only ways to break this loop are to yield a solution via X2 or to
552 // have exhausted all solutions via X8
553 loop {
554 match self.stage {
555 Stage::X2 => {
556 if let Some(z) = self.x2() {
557 return Some(z);
558 }
559 }
560 Stage::X3 => {
561 self.x3x4();
562 }
563 Stage::X5 => {
564 self.x5();
565 }
566 Stage::X6 => {
567 self.x6();
568 }
569 Stage::X8 => match self.x8() {
570 true => {}
571 false => {
572 return None;
573 }
574 },
575 };
576 }
577 }
578
579 /// Returns a solution in a human-understandable form
580 ///
581 /// The solution vector `sol_vec` stores each of the OptionElements which
582 /// were used to cover the items in the solution. To turn this into
583 /// something understandable we find the spacer to its right, and use this
584 /// with a lookup table created earlier to map this to the names of options
585 ///
586 // TODO: Is it useful to have the double map? We don't used spacer_ids for
587 // anything else, so could condense it into a single HashMap
588 pub fn output(&self) -> Vec<T> {
589 let to_return = self
590 .sol_vec
591 .iter()
592 .take(self.l)
593 .map(|&x| self.spacer_for(x))
594 .map(|x| self.spacer_ids[&x])
595 .map(|x| self.names[x].clone())
596 .collect();
597 to_return
598 }
599
600 /// Stage X2 of Algorithm X
601 /// If rlink(0) = 0, then all items are covered, so return current solution
602 /// and also go to X8
603 fn x2(&mut self) -> Option<Vec<T>> {
604 //println!("State:");
605 //println!("{}",self);
606 //println!("RLINK: {}",self.elements[0].r());
607 if self.elements[0].r() == 0 || self.elements[0].r() >= self.optional {
608 if self.yielding {
609 self.yielding = false;
610 return Some(self.output());
611 } else {
612 self.yielding = true;
613 self.stage = Stage::X8;
614 return None;
615 }
616 }
617 self.stage = Stage::X3;
618 None
619 }
620
621 /// Stages X3 and X4 of algorithm X
622 ///
623 /// X3: Choose item `min_idx`, use MRV heuristic (i.e. smallest remaining value)
624 ///
625 /// X4: Cover item `min_idx`
626 fn x3x4(&mut self) -> Option<Vec<String>> {
627 // X3
628 // Heuristic we choose is MRV
629
630 // Walk along items and find minimum l
631 let mut idx = self.elements[0].r();
632 let mut min_idx = self.elements[0].r();
633 let mut min_l = self.elements[idx].get_l();
634 while idx != 0 && idx < self.optional {
635 let l = self.elements[idx].get_l();
636 if l < min_l {
637 min_l = l;
638 min_idx = idx;
639 }
640 idx = self.elements[idx].r();
641 }
642
643 // Now select the item which is covered by the minimum number of options
644 self.idx = min_idx;
645
646 // X4
647 // Cover i
648
649 //println!("Covering item X4: {}", self.idx);
650 self.cover(self.idx).unwrap();
651
652 // Set x_l <- DLINK(i)
653 let x_l = self.elements[self.idx].d();
654
655 // Save x_l in current guesses
656 // println!("self.l: {}",self.l);
657 self.sol_vec[self.l] = x_l;
658
659 self.stage = Stage::X5;
660 None
661 }
662
663 /// Stages X5 and X7 of Algorithm X
664 ///
665 /// Try x_l
666 ///
667 /// If x_l = i, then we are out of options and execute X7: backtrack
668 ///
669 /// Otherwise, cover all other items in option x_l, increase level and go back to X2
670 ///
671 fn x5(&mut self) -> Option<Vec<String>> {
672 // X5
673 // Try x_l
674 // If x_l = i, then we are out of options and go to X7
675 // Otherwise, cover all other items in option x_l, increase level and go back to X2
676 // println!("Partial sol: {:?}", &self.sol_vec[..self.l]);
677
678 // Try xl
679 let x_l = self.sol_vec[self.l];
680 // println!("Trying x_{}= {}", self.l, x_l);
681 // println!("idx: {}", self.idx);
682
683 // If out of options (x_l reads downwards from self.idx, so have looped back around), backtrack
684 if x_l == self.idx {
685 // X7
686 // Backtrack: Uncover item (i)
687
688 // println!("Uncovering X7: {}", x_l);
689 self.uncover(x_l).unwrap();
690 self.stage = Stage::X8;
691 return None;
692 }
693
694 let mut p = x_l + 1;
695 while p != x_l {
696 // println!("p: {}", p);
697
698 match &self.elements[p] {
699 Link::Spacer(_) => {
700 // If a spacer, then hop up one link
701 p = self.elements[p].u();
702 }
703 op @ Link::OptionElement(_) => {
704 // println!("Covering X5: {}", j);
705 // println!("State:");
706 // println!("{}", self);
707 let j = op.top();
708
709 self.cover(j).unwrap();
710 }
711 Link::Item(x) => {
712 panic!("Trying an item {:?}", x);
713 }
714 };
715 p += 1;
716 }
717 // println!("--");
718
719 self.l += 1;
720 self.stage = Stage::X2;
721 None
722 }
723
724 /// Stage X6 of Algorithm X
725 ///
726 /// Try again
727 ///
728 /// Uncover items != i in option x_l, then set x_l = DLINK(x_l): this is how we move through all of the options
729 fn x6(&mut self) -> Option<Vec<String>> {
730 let x_l = self.sol_vec[self.l];
731 let mut p = x_l - 1;
732
733 while p != x_l {
734 let j = self.elements[p].top();
735 if j == 0 {
736 p = self.elements[p].d();
737 } else {
738 // println!("Uncovering X6: {}",j);
739 self.uncover(j).unwrap();
740 }
741 p -= 1;
742 }
743 self.idx = self.elements[x_l].top();
744 self.sol_vec[self.l] = self.elements[x_l].d();
745
746 self.stage = Stage::X5;
747 None
748 }
749
750 /// Stage X8 of Algorithm X
751 /// Leave level l
752 /// Terminate if l=0, otherwise l=l-1, go to X6
753 fn x8(&mut self) -> bool {
754 // X8
755 match self.l {
756 0 => false,
757 _ => {
758 self.l -= 1;
759 self.stage = Stage::X6;
760 true
761 }
762 }
763 }
764
765 /// Takes in a non-item node and steps rightwards along `self.elements` the
766 /// until a spacer is found, upon which the index is returned
767 fn spacer_for(&self, x: Index) -> Index {
768 let mut p = x;
769 loop {
770 match self.elements[p] {
771 Link::Spacer(_) => return p,
772 Link::OptionElement(_) => p += 1,
773 Link::Item(_) => panic!("Somehow ended up on an item"),
774 };
775 }
776 }
777
778 /// Selects an option with the name `name` When setting up a general
779 /// constraint solution, this is how to search for specific answers e.g. a
780 /// Sudoku has all the constraints (items and options), and then the squares
781 /// filled out in the specific problem need to be selected
782 ///
783 /// So for the problem
784 ///
785 /// ```text
786 /// i1 i2 i3
787 /// o1 1 0 0
788 /// o2 1 0 0
789 /// o3 0 1 1
790 /// ```
791 /// Clearly *both* \[o1,o3\] and \[o2,o3\] are solutions, but if we select o1, then only one solution remains
792 ///
793 /// ```
794 ///# use dlx_rs::solver::Solver;
795 ///
796 /// let mut s = Solver::new(3);
797 ///
798 /// s.add_option("o1", &[1])
799 /// .add_option("o2", &[1])
800 /// .add_option("o3", &[2, 3]);
801 ///
802 /// // First get all solutions
803 /// let sols: Vec<Vec<&str>> = s.clone().collect();
804 /// assert_eq!(sols.len(), 2);
805 /// assert_eq!( vec!["o3", "o1"], sols[0]);
806 /// assert_eq!( vec!["o3", "o2"], sols[1]);
807 ///
808 ///
809 /// // Now select o1 and get all solutions
810 /// s.select("o1");
811 /// assert_eq!( vec!["o3"], s.next().unwrap());
812 /// ```
813 pub fn select(&mut self, name: T) -> Result<(), &'static str> {
814 // This selects an option by doing the followings
815
816 // First get the spacer position of the option by firstly finding which
817 // option it was
818 let id = match self.names.iter().position(|x| x == &name) {
819 Some(z) => z,
820 None => return Err("Invalid option specified"),
821 };
822
823 // Now find the spacer id by going this many links down the chain
824 // Start at root spacer node
825 let mut spacer_id = self.items + 1;
826 for _ in 0..id {
827 spacer_id = self.elements[spacer_id].d();
828 }
829 // println!("Spacer id: {}", spacer_id);
830
831 // Now have the spacer node: cycle around and hide everything until we are at the next spacer mode
832 let mut p = spacer_id + 1;
833
834 loop {
835 match self.elements[p] {
836 Link::OptionElement(_) => {
837 self.cover(self.elements[p].top()).unwrap();
838 p += 1;
839 }
840 Link::Spacer(_) => break,
841 Link::Item(_) => break,
842 };
843 }
844
845 Ok(())
846 }
847}
848
849impl<T: Debug + PartialEq + Clone> Iterator for Solver<T> {
850 type Item = Vec<T>;
851 /// Produces next solution by following algorithm X
852 /// as described in tAoCP in Fasc 5c, Dancing Links, Knuth
853 ///
854 /// Returns `Some` containing a vector of items if a solution remains, or
855 /// `None` when no more solutions remaining
856 fn next(&mut self) -> Option<Self::Item> {
857 self.solve()
858 }
859}
860
861#[cfg(test)]
862mod tests {
863
864 use super::*;
865
866 #[test]
867 fn spacer_for() {
868 let mut s = Solver::new(4);
869 s.add_option("o1", &[1, 2])
870 .add_option("o2", &[2, 3])
871 .add_option("o3", &[3, 4])
872 .add_option("o4", &[1, 4]);
873
874 // This creates a vec which looks like
875 // [i0, i1, i2, i3, i4, s0
876 // x x s1
877 // x x s2
878 // x x s3
879 // x x s4]
880 //
881
882 let spacer_answers = HashMap::from([
883 (6, 8),
884 (7, 8),
885 (8, 8),
886 (9, 11),
887 (10, 11),
888 (11, 11),
889 (12, 14),
890 (13, 14),
891 (14, 14),
892 (15, 17),
893 (16, 17),
894 (17, 17),
895 ]);
896
897 for i in 6..=17 {
898 assert_eq!(s.spacer_for(i), spacer_answers[&i]);
899 }
900 }
901}