1use crate::{
2 common::{ActivityTable, Clause, Literal, Phases, Variable, Watches},
3 constants::SATResult,
4};
5
6#[derive(Debug, Clone, Default)]
8pub struct Statistics {
9 pub conflicts: usize,
11 pub decisions: usize,
13 pub propagations: usize,
15 pub assignments: usize,
17}
18
19pub struct Kernel {
27 pub assignment: Vec<i8>,
29 pub vars: Vec<Variable>,
31 pub clauses: Vec<Clause>,
33 pub watches: Vec<Vec<Watches>>,
35 pub trail: Vec<Literal>,
37 pub vsids: ActivityTable,
39 pub phases: Phases,
41 pub result: SATResult,
43
44 pub level: usize,
46 pub backtrack_level: usize,
48 pub propagated: usize,
50 pub assigned: usize,
52
53 pub conflict: Option<(usize, Literal)>,
55 pub lemma: Vec<Literal>,
57 pub learnt: (Literal, Option<usize>),
59
60 pub statistics: Statistics,
62 mark_table: Vec<usize>,
64 mark_epoch: usize,
66 pending_clause: Vec<Literal>,
68}
69
70impl Kernel {
71 pub fn new(max_vars: usize) -> Self {
73 Self {
74 assignment: vec![0; max_vars + 1],
76 vars: vec![Variable::default(); max_vars + 1],
77 clauses: vec![],
78 watches: vec![Vec::new(); max_vars * 2],
79 trail: vec![],
80 vsids: ActivityTable::new(max_vars),
81 phases: Phases::new(max_vars),
82 result: SATResult::UNKNOWN,
83 level: 0,
84 backtrack_level: 0,
85 propagated: 0,
86 assigned: 0,
87 conflict: None,
88 lemma: Vec::new(),
89 learnt: (0, None),
90 pending_clause: Vec::new(),
91 statistics: Statistics::default(),
92 mark_table: vec![0; max_vars + 1],
93 mark_epoch: 1,
94 }
95 }
96
97 pub fn add(&mut self, lit: Option<Literal>) {
102 if let Some(lit) = lit {
103 self.pending_clause.push(lit);
104 } else {
105 let literals = std::mem::take(&mut self.pending_clause);
106 let clause = Clause::new().with_literals(literals).with_lbd(0);
107 let clause_id = self.clauses.len();
108 self.clauses.push(clause);
109 self.attach_clause_watchers(clause_id);
110 }
111 }
112
113 #[inline]
114 pub fn value(&self, lit: Literal) -> i8 {
121 assert_ne!(lit, 0);
122 assert!(lit.unsigned_abs() < self.assignment.len());
123 let value = self.assignment[lit.unsigned_abs()];
124 if lit > 0 { value } else { -value }
125 }
126
127 #[inline]
137 fn watcher_index(&self, lit: Literal) -> usize {
138 assert_ne!(lit, 0);
139 assert!(lit.unsigned_abs() < self.assignment.len());
140 let var = lit.unsigned_abs();
141 ((var - 1) << 1) | usize::from(lit < 0)
142 }
143
144 #[inline]
149 pub fn add_watch(&mut self, watched_lit: Literal, watch: Watches) {
150 let idx = self.watcher_index(watched_lit);
151 self.watches[idx].push(watch);
152 }
153
154 fn attach_clause_watchers(&mut self, clause_id: usize) {
167 let Some(clause) = self.clauses.get(clause_id) else {
168 return;
169 };
170
171 let literals = clause.literals();
172 assert_ne!(literals.len(), 0);
173 if literals.len() == 1 {
174 let lit = literals[0];
175 self.add_watch(-lit, Watches { clause_id, blocker: lit });
176 } else {
177 let lit0 = literals[0];
178 let lit1 = literals[1];
179 self.add_watch(-lit0, Watches { clause_id, blocker: lit1 });
180 self.add_watch(-lit1, Watches { clause_id, blocker: lit0 });
181 }
182 }
183
184 pub fn watches(&mut self, lit: Literal) -> Vec<Watches> {
188 let idx = self.watcher_index(lit);
189 std::mem::take(&mut self.watches[idx])
190 }
191
192 pub fn set_watches(&mut self, lit: Literal, ws: Vec<Watches>) {
194 let idx = self.watcher_index(lit);
195 self.watches[idx] = ws;
196 }
197
198 pub fn assign(&mut self, var_id: usize, lit: Literal, reason: Option<usize>) {
206 assert!(var_id > 0 && var_id < self.assignment.len());
207 let mut var = self.vars[var_id];
208 self.trail.push(lit);
209 var.level = self.level;
210 var.trail_index = self.trail.len();
211 var.reason = reason;
212 self.vars[var_id] = var;
213 self.assignment[var_id] = if lit > 0 { 1 } else { -1 };
214 self.phases.save_phase_for_variable(var_id, lit > 0);
215 self.assigned += 1;
216 }
217
218 #[inline]
219 pub fn reset_value(&mut self, var_id: usize) {
221 assert!(var_id > 0 && var_id < self.assignment.len());
222 self.phases.save_phase_for_variable(var_id, self.assignment[var_id] > 0);
223 self.assignment[var_id] = 0;
224 self.assigned -= 1;
225 }
226
227 #[inline]
228 pub fn next_mark_epoch(&mut self) -> usize {
232 self.mark_epoch = self.mark_epoch.wrapping_add(1);
233 if self.mark_epoch == 0 {
234 self.mark_epoch = 1;
235 self.mark_table.fill(0);
236 }
237 self.mark_epoch
238 }
239
240 #[inline]
241 pub fn mark_at(&self, idx: usize) -> usize {
243 self.mark_table.get(idx).copied().unwrap_or(0)
244 }
245
246 #[inline]
247 pub fn set_mark_at(&mut self, idx: usize, stamp: usize) {
249 if idx >= self.mark_table.len() {
250 self.mark_table.resize(idx + 1, 0);
251 }
252 self.mark_table[idx] = stamp;
253 }
254
255 pub fn add_learned_clause_with_lbd(&mut self, literals: Vec<Literal>, lbd: u32) -> usize {
257 assert!(!literals.is_empty(), "learned clause should not be empty");
258 let clause = Clause::new().with_ordered_literals(literals).with_lbd(lbd);
259 let clause_id = self.clauses.len();
260 self.clauses.push(clause);
261 self.attach_clause_watchers(clause_id);
262 clause_id
263 }
264
265 pub fn satisfied(&self) -> bool {
267 self.assigned + 1 == self.assignment.len()
268 }
269}