1use std::num::NonZeroU32;
2
3#[cfg(feature = "mem_dbg")]
4use mem_dbg::{MemDbg, MemSize};
5use typed_index_collections::TiSlice;
6
7use crate::{
8 items::{
9 Assignment, Cdcl, CdclBacklink, CdclIdx, CdclKind, Conflict, ENodeIdx, InstIdx,
10 Justification, JustificationKind, LitIdx, Literal, StackIdx, TermIdx,
11 },
12 Error, FxHashMap, Result, TiVec,
13};
14
15use super::stack::Stack;
16
17#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
18#[derive(Debug, Default)]
19pub struct Literals {
20 literals: TiVec<LitIdx, Literal>,
21 #[cfg(any())]
23 pub lit_stack: SortedVec<LitIdx>,
24 pub assignments: FxHashMap<TermIdx, LitIdx>,
25
26 pub cdcl: CdclTree,
27}
28
29#[cfg(any())]
30#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
31#[derive(Debug)]
32pub struct LitStack {
33 global_lits: u32,
34 stack: Vec<LitIdx>,
35}
36
37impl Literals {
38 pub fn new_literal(
39 &mut self,
40 term: Assignment,
41 iblame: Option<InstIdx>,
42 enode: Option<ENodeIdx>,
43 stack: &Stack,
44 ) -> Result<LitIdx> {
45 let frame = stack.active_frame();
46 let lit = Literal {
47 term,
48 frame,
49 iblame,
50 enode,
51 justification: Default::default(),
52 };
53 self.literals.try_reserve(1)?;
54 let lit = self.literals.push_and_get_key(lit);
55 self.assignments.try_reserve(1)?;
56 self.assignments.insert(term.literal, lit);
57
58 #[cfg(any())]
60 self.lit_stack
61 .raw
62 .retain(|&l| stack.is_alive(self.literals[l].frame));
63 #[cfg(any())]
64 self.lit_stack.push_by(lit, |a, b| {
65 let a = &self.literals[*a];
66 let b = &self.literals[*b];
67 a.term.literal.cmp(&b.term.literal)
68 })?;
69 Ok(lit)
93 }
94
95 pub fn get_assign(&self, term: TermIdx, stack: &Stack) -> Option<LitIdx> {
96 let lit = *self.assignments.get(&term)?;
97 stack.is_alive(self.literals[lit].frame).then_some(lit)
98 }
99
100 pub fn justification(
103 &mut self,
104 lit: LitIdx,
105 kind: JustificationKind,
106 #[allow(unused)] blamed: impl Iterator<Item = Result<(Option<NonZeroU32>, bool)>>,
107 ) -> Result<&Justification> {
108 #[cfg(any())]
109 let mut literals = Vec::new();
110 #[cfg(any())]
111 let negated = matches!(kind, JustificationKind::Propagate);
112 #[cfg(any())]
113 for lit in blamed {
114 let lit = self.literal_to_term(lit?, negated);
115 literals.try_reserve(1)?;
116 literals.push(lit?);
117 }
118 let justification = Justification {
119 kind,
120 #[cfg(any())]
121 blamed: literals.into(),
122 };
123 let j = &mut self.literals[lit].justification;
124 *j = justification;
125 Ok(j)
126 }
127
128 #[cfg(any())]
130 pub fn literal_to_term(
132 &self,
133 (lit, value): (Option<NonZeroU32>, bool),
134 negated: bool,
135 ) -> Result<LitIdx> {
136 let lit = self.literal_to_term_inner(lit);
137 if (self.literals[lit].term.value == value) == negated {
138 return Err(Error::BoolLiteral);
139 }
140 if negated {
141 debug_assert_eq!(!self.literals[lit].term.value, value);
142 } else {
143 debug_assert_eq!(self.literals[lit].term.value, value);
144 }
145 Ok(lit)
146 }
147 #[cfg(any())]
148 fn literal_to_term_inner(&self, lit: Option<NonZeroU32>) -> LitIdx {
149 let lit = lit.unwrap().get() - 1; self.lit_stack[lit as usize]
151 }
159
160 pub(super) fn curr_to_root_unique(&self) -> bool {
161 let mut assigns = crate::FxHashSet::default();
162 self.cdcl
163 .curr_to_root()
164 .flat_map(|c| self.cdcl[c].get_assignments())
165 .all(|lit| assigns.insert(self[lit].term.literal))
166 }
167}
168
169#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
170#[derive(Debug)]
171pub struct CdclTree {
172 incremental_mode: bool,
173 cdcl: TiVec<CdclIdx, Cdcl>,
174 conflict: Option<Box<[Assignment]>>,
177}
178
179impl Default for CdclTree {
180 fn default() -> Self {
181 let mut cdcl = TiVec::default();
182 let zero = cdcl.push_and_get_key(Cdcl::root(Stack::ZERO_FRAME));
183 debug_assert_eq!(zero, CdclIdx::ZERO);
184 Self {
185 incremental_mode: false,
186 cdcl,
187 conflict: None,
188 }
189 }
190}
191
192impl CdclTree {
193 pub fn new_decision(&mut self, lit: LitIdx, stack: &Stack) -> Result<CdclIdx> {
194 debug_assert!(self.conflict.is_none());
195 self.check_frame_decision(stack)?;
196
197 let cdcl = Cdcl::new_decision(lit, stack.active_frame());
198 self.cdcl.raw.try_reserve(1)?;
199 Ok(self.cdcl.push_and_get_key(cdcl))
200 }
201
202 fn check_frame_decision(&mut self, stack: &Stack) -> Result<()> {
203 if stack.is_alive(self.cdcl.last().unwrap().frame) {
204 return Ok(());
205 }
206 let prev = stack.pre_active_frame();
210 self.insert_empty_frame(stack, prev)?;
211 Ok(())
212 }
213
214 pub fn new_conflict(&mut self, cut: Box<[Assignment]>, frame: StackIdx) {
215 debug_assert!(self.conflict.is_none());
216 debug_assert!(self.cdcl.last().is_some_and(|cdcl| cdcl.frame == frame));
217 self.cdcl.last_mut().unwrap().conflicts = true;
218 self.conflict = Some(cut);
219 }
220
221 pub fn backtrack(&mut self, stack: &Stack) -> Result<CdclIdx> {
222 let backtrack = self.last_active(stack);
223 debug_assert_ne!(backtrack, self.cdcl.last_key().unwrap());
224 let cut = self.conflict.take().ok_or(Error::NoConflict)?;
228 let conflict = Conflict { cut, backtrack };
229 let cdcl = Cdcl::new_conflict(conflict, stack.active_frame());
230 self.cdcl.raw.try_reserve(1)?;
231 Ok(self.cdcl.push_and_get_key(cdcl))
232 }
233
234 pub fn new_propagate(&mut self, lit: LitIdx, stack: &Stack) -> Result<()> {
235 debug_assert!(self.conflict.is_none());
236 let mut last = self.cdcl.last_mut().unwrap();
237 let frame = stack.active_frame();
238 if last.frame != frame {
239 last = self.insert_empty_frame(stack, frame)?;
240 }
241 last.propagates.try_reserve(1)?;
242 last.propagates.push(lit);
243 Ok(())
244 }
245
246 fn insert_empty_frame(&mut self, stack: &Stack, at: StackIdx) -> Result<&mut Cdcl> {
247 let parent = self.last_active(stack);
248 let empty = Cdcl::new_empty(parent, at);
249 self.cdcl.raw.try_reserve(1)?;
250 let new = self.cdcl.push_and_get_key(empty);
251 Ok(&mut self.cdcl[new])
252 }
253
254 pub fn begin_check(&mut self, incremental_mode: bool, stack: &Stack) -> Result<()> {
255 debug_assert!(self.conflict.is_none());
256 debug_assert!(!self.incremental_mode || incremental_mode);
257 self.incremental_mode = incremental_mode;
258 let parent = incremental_mode.then(|| self.last_active(stack));
259 let check = Cdcl::begin_check(parent, stack.active_frame());
260 self.cdcl.raw.try_reserve(1)?;
261 self.cdcl.push_and_get_key(check);
262 Ok(())
263 }
264
265 pub fn has_conflict(&self) -> bool {
266 self.conflict.is_some()
267 }
268
269 pub fn cdcls(&self) -> &TiSlice<CdclIdx, Cdcl> {
270 &self.cdcl
271 }
272
273 pub fn backlink(&self, cidx: CdclIdx) -> CdclBacklink {
274 self[cidx].backlink(cidx)
275 }
276
277 fn last_active(&self, stack: &Stack) -> CdclIdx {
278 let active = |i: &CdclIdx| stack.is_alive(self[*i].frame);
279 self.curr_to_root().find(active).unwrap()
280 }
281
282 fn curr_to_root(&self) -> impl Iterator<Item = CdclIdx> + '_ {
283 self.to_root(self.cdcl.last_key().unwrap())
284 }
285
286 fn to_root(&self, from: CdclIdx) -> impl Iterator<Item = CdclIdx> + '_ {
287 let mut curr = Some(from);
288 core::iter::from_fn(move || {
289 let cdcl = curr?;
290 let backlink = self.backlink(cdcl);
291 curr = backlink.to_root();
292 Some(cdcl)
293 })
294 }
295
296 pub fn dead_branches(&self) -> impl Iterator<Item = DeadBranch<'_>> + '_ {
298 self.cdcl
299 .iter_enumerated()
300 .filter_map(|(cidx, cdcl)| match &cdcl.kind {
301 CdclKind::Conflict(conflict) => Some(DeadBranch { cidx, conflict }),
302 _ => None,
303 })
304 }
305
306 pub fn dead_branch(&self, db: DeadBranch) -> impl Iterator<Item = CdclIdx> + '_ {
308 let conflict_leaf = usize::from(db.cidx).checked_sub(1).unwrap();
309 let conflict_leaf = CdclIdx::from(conflict_leaf);
310 let common_ancestor = db.conflict.backtrack;
311 debug_assert!(self.to_root(conflict_leaf).any(|c| c == common_ancestor));
312 self.to_root(conflict_leaf)
313 .take_while(move |&c| c != common_ancestor)
314 }
315}
316
317#[derive(Clone, Copy)]
318pub struct DeadBranch<'a> {
319 pub cidx: CdclIdx,
321 pub conflict: &'a Conflict,
322}
323
324impl std::ops::Index<LitIdx> for Literals {
325 type Output = Literal;
326 fn index(&self, idx: LitIdx) -> &Self::Output {
327 &self.literals[idx]
328 }
329}
330
331impl std::ops::Index<CdclIdx> for CdclTree {
332 type Output = Cdcl;
333 fn index(&self, idx: CdclIdx) -> &Self::Output {
334 &self.cdcl[idx]
335 }
336}