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}