splr/processor/
heap.rs

1/// Module `eliminator` implements clause subsumption and var elimination.
2use {
3    crate::{assign::AssignIF, types::*},
4    std::fmt,
5};
6
7pub trait VarOrderIF {
8    fn clear(&mut self, asg: &mut impl AssignIF);
9    fn len(&self) -> usize;
10    fn insert(&mut self, occur: &[LitOccurs], vi: VarId, upward: bool);
11    fn is_empty(&self) -> bool;
12    fn select_var(&mut self, occur: &[LitOccurs], asg: &impl AssignIF) -> Option<VarId>;
13    fn rebuild(&mut self, asg: &impl AssignIF, occur: &[LitOccurs]);
14}
15
16/// Mapping from Literal to Clauses.
17#[derive(Clone, Debug, Default)]
18pub struct LitOccurs {
19    pub aborted: bool,
20    pub pos_occurs: Vec<ClauseId>,
21    pub neg_occurs: Vec<ClauseId>,
22}
23
24impl LitOccurs {
25    /// return a new vector of $n$ `LitOccurs`s.
26    pub fn new(n: usize) -> Vec<LitOccurs> {
27        let mut vec = Vec::with_capacity(n + 1);
28        for _ in 0..=n {
29            vec.push(LitOccurs::default());
30        }
31        vec
32    }
33    pub fn clear(&mut self) {
34        self.aborted = false;
35        self.pos_occurs.clear();
36        self.neg_occurs.clear();
37    }
38    pub fn activity(&self) -> usize {
39        if self.aborted {
40            std::usize::MAX
41        } else {
42            self.pos_occurs.len().min(self.neg_occurs.len())
43        }
44    }
45    pub fn is_empty(&self) -> bool {
46        self.pos_occurs.is_empty() && self.neg_occurs.is_empty()
47    }
48    pub fn len(&self) -> usize {
49        self.pos_occurs.len() + self.neg_occurs.len()
50    }
51}
52
53/// Var heap structure based on the number of occurrences
54/// # Note
55/// - both fields has a fixed length. Don't use push and pop.
56/// - `idxs[0]` contains the number of alive elements
57///   `indx` is positions. So the unused field 0 can hold the last position as a special case.
58#[derive(Clone, Debug)]
59pub struct VarOccHeap {
60    pub heap: Vec<u32>, // order : usize -> VarId::from
61    pub idxs: Vec<u32>, // VarId : -> order : usize::from
62}
63
64impl VarOccHeap {
65    pub fn new(n: usize, init: usize) -> Self {
66        let mut heap = Vec::with_capacity(n + 1);
67        let mut idxs = Vec::with_capacity(n + 1);
68        heap.push(0);
69        idxs.push(n as u32);
70        for i in 1..=n {
71            heap.push(i as u32);
72            idxs.push(i as u32);
73        }
74        idxs[0] = init as u32;
75        VarOccHeap { heap, idxs }
76    }
77}
78
79impl VarOrderIF for VarOccHeap {
80    fn insert(&mut self, occur: &[LitOccurs], vi: VarId, upward: bool) {
81        debug_assert!(vi < self.heap.len());
82        if self.contains(vi) {
83            let i = self.idxs[vi];
84            if upward {
85                self.percolate_up(occur, i);
86            } else {
87                self.percolate_down(occur, i);
88            }
89            return;
90        }
91        let i = self.idxs[vi];
92        let n = self.idxs[0] + 1;
93        let vn = self.heap[n as usize];
94        self.heap.swap(i as usize, n as usize);
95        self.idxs.swap(vi, vn as usize);
96        debug_assert!((n as usize) < self.heap.len());
97        self.idxs[0] = n;
98        self.percolate_up(occur, n);
99    }
100    fn clear(&mut self, asg: &mut impl AssignIF) {
101        for v in &mut self.heap[0..self.idxs[0] as usize] {
102            asg.var_mut(*v as usize).turn_off(FlagVar::ENQUEUED);
103        }
104        self.reset()
105    }
106    fn len(&self) -> usize {
107        self.idxs[0] as usize
108    }
109    fn is_empty(&self) -> bool {
110        self.idxs[0] == 0
111    }
112    fn select_var(&mut self, occur: &[LitOccurs], asg: &impl AssignIF) -> Option<VarId> {
113        loop {
114            let vi = self.get_root(occur);
115            if vi == 0 {
116                return None;
117            }
118            if !asg.var(vi).is(FlagVar::ELIMINATED) {
119                return Some(vi);
120            }
121        }
122    }
123    fn rebuild(&mut self, asg: &impl AssignIF, occur: &[LitOccurs]) {
124        self.reset();
125        for (vi, v) in asg.var_iter().enumerate().skip(1) {
126            if asg.assign(vi).is_none() && !v.is(FlagVar::ELIMINATED) {
127                self.insert(occur, vi, true);
128            }
129        }
130    }
131}
132
133impl VarOccHeap {
134    fn contains(&self, v: VarId) -> bool {
135        self.idxs[v] <= self.idxs[0]
136    }
137    fn reset(&mut self) {
138        for i in 0..self.idxs.len() {
139            self.idxs[i] = i as u32;
140            self.heap[i] = i as u32;
141        }
142    }
143    fn get_root(&mut self, occur: &[LitOccurs]) -> VarId {
144        let s = 1;
145        let vs = self.heap[s];
146        let n = self.idxs[0];
147        debug_assert!((n as usize) < self.heap.len());
148        if n == 0 {
149            return 0;
150        }
151        let vn = self.heap[n as usize];
152        debug_assert!(vn != 0, "Invalid VarId for heap");
153        debug_assert!(vs != 0, "Invalid VarId for heap");
154        self.heap.swap(n as usize, s);
155        self.idxs.swap(vn as usize, vs as usize);
156        self.idxs[0] -= 1;
157        if 1 < self.idxs[0] {
158            self.percolate_down(occur, 1);
159        }
160        vs as usize
161    }
162    fn percolate_up(&mut self, occur: &[LitOccurs], start: u32) {
163        let mut q = start;
164        let vq = self.heap[q as usize];
165        debug_assert!(0 < vq, "size of heap is too small");
166        let aq = occur[vq as usize].activity();
167        loop {
168            let p = q / 2;
169            if p == 0 {
170                self.heap[q as usize] = vq;
171                debug_assert!(vq != 0, "Invalid index in percolate_up");
172                self.idxs[vq as usize] = q;
173                return;
174            } else {
175                let vp = self.heap[p as usize];
176                let ap = occur[vp as usize].activity();
177                if ap > aq {
178                    // move down the current parent, and make it empty
179                    self.heap[q as usize] = vp;
180                    debug_assert!(vq != 0, "Invalid index in percolate_up");
181                    self.idxs[vp as usize] = q;
182                    q = p;
183                } else {
184                    self.heap[q as usize] = vq;
185                    debug_assert!(vq != 0, "Invalid index in percolate_up");
186                    self.idxs[vq as usize] = q;
187                    return;
188                }
189            }
190        }
191    }
192    fn percolate_down(&mut self, occur: &[LitOccurs], start: u32) {
193        let n = self.len();
194        let mut i = start;
195        let vi = self.heap[i as usize];
196        let ai = occur[vi as usize].activity();
197        loop {
198            let l = 2 * i; // left
199            if l < (n as u32) {
200                let vl = self.heap[l as usize];
201                let al = occur[vl as usize].activity();
202                let r = l + 1; // right
203                let (target, vc, ac) =
204                    if r < (n as u32) && al > occur[self.heap[r as usize] as usize].activity() {
205                        let vr = self.heap[r as usize];
206                        (r, vr, occur[vr as usize].activity())
207                    } else {
208                        (l, vl, al)
209                    };
210                if ai > ac {
211                    self.heap[i as usize] = vc;
212                    self.idxs[vc as usize] = i;
213                    i = target;
214                } else {
215                    self.heap[i as usize] = vi;
216                    debug_assert!(vi != 0, "invalid index");
217                    self.idxs[vi as usize] = i;
218                    return;
219                }
220            } else {
221                self.heap[i as usize] = vi;
222                debug_assert!(vi != 0, "invalid index");
223                self.idxs[vi as usize] = i;
224                return;
225            }
226        }
227    }
228    /* #[allow(dead_code)]
229    fn peek(&self) -> VarId {
230        self.heap[1]
231    }
232    #[allow(dead_code)]
233    fn remove(&mut self, occur: &[LitOccurs], vs: VarId) {
234        let s = self.idxs[vs];
235        let n = self.idxs[0];
236        if n < s {
237            return;
238        }
239        let vn = self.heap[n];
240        self.heap.swap(n, s);
241        self.idxs.swap(vn, vs);
242        self.idxs[0] -= 1;
243        if 1 < self.idxs[0] {
244            self.percolate_down(occur, 1);
245        }
246    }
247    #[allow(dead_code)]
248    fn check(&self, s: &str) {
249        let h = &mut self.heap.clone()[1..];
250        let d = &mut self.idxs.clone()[1..];
251        h.sort();
252        d.sort();
253        for i in 0..h.len() {
254            if h[i] != i + 1 {
255                panic!("heap {} {} {:?}", i, h[i], h);
256            }
257            if d[i] != i + 1 {
258                panic!("idxs {} {} {:?}", i, d[i], d);
259            }
260        }
261        println!(" - pass var_order test at {}", s);
262    } */
263}
264
265impl fmt::Display for VarOccHeap {
266    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
267        write!(
268            f,
269            " - seek pointer - nth -> var: {:?}\n - var -> nth: {:?}",
270            self.heap, self.idxs,
271        )
272    }
273}