1use crate::literal::Lit;
7#[allow(unused_imports)]
8use crate::prelude::*;
9
10#[cfg(test)]
11use crate::literal::Var;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
15pub struct AssumptionLevel(pub u32);
16
17impl AssumptionLevel {
18 pub const fn new(level: u32) -> Self {
20 Self(level)
21 }
22
23 pub const fn root() -> Self {
25 Self(0)
26 }
27}
28
29#[derive(Debug, Clone)]
31pub struct Assumption {
32 pub lit: Lit,
34 pub level: AssumptionLevel,
36 pub user_data: Option<u64>,
38}
39
40impl Assumption {
41 pub fn new(lit: Lit, level: AssumptionLevel) -> Self {
43 Self {
44 lit,
45 level,
46 user_data: None,
47 }
48 }
49
50 pub fn with_data(lit: Lit, level: AssumptionLevel, data: u64) -> Self {
52 Self {
53 lit,
54 level,
55 user_data: Some(data),
56 }
57 }
58}
59
60pub struct AssumptionStack {
62 assumptions: Vec<Assumption>,
64 current_level: AssumptionLevel,
66 lit_to_index: HashMap<Lit, usize>,
68 conflict_set: Vec<Lit>,
70}
71
72impl AssumptionStack {
73 pub fn new() -> Self {
75 Self {
76 assumptions: Vec::new(),
77 current_level: AssumptionLevel::root(),
78 lit_to_index: HashMap::new(),
79 conflict_set: Vec::new(),
80 }
81 }
82
83 pub fn push(&mut self, lit: Lit) -> Result<(), String> {
85 if self.lit_to_index.contains_key(&lit.negate()) {
87 return Err(format!(
88 "Conflicting assumption: {:?} conflicts with existing assumption",
89 lit
90 ));
91 }
92
93 let assumption = Assumption::new(lit, self.current_level);
94 self.lit_to_index.insert(lit, self.assumptions.len());
95 self.assumptions.push(assumption);
96 Ok(())
97 }
98
99 pub fn push_with_data(&mut self, lit: Lit, data: u64) -> Result<(), String> {
101 if self.lit_to_index.contains_key(&lit.negate()) {
102 return Err(format!(
103 "Conflicting assumption: {:?} conflicts with existing assumption",
104 lit
105 ));
106 }
107
108 let assumption = Assumption::with_data(lit, self.current_level, data);
109 self.lit_to_index.insert(lit, self.assumptions.len());
110 self.assumptions.push(assumption);
111 Ok(())
112 }
113
114 pub fn new_level(&mut self) {
116 self.current_level = AssumptionLevel::new(self.current_level.0 + 1);
117 }
118
119 pub fn pop_level(&mut self) {
121 if self.current_level.0 == 0 {
122 return;
123 }
124
125 self.assumptions.retain(|a| {
127 let keep = a.level < self.current_level;
128 if !keep {
129 self.lit_to_index.remove(&a.lit);
130 }
131 keep
132 });
133
134 self.current_level = AssumptionLevel::new(self.current_level.0 - 1);
136 }
137
138 pub fn clear(&mut self) {
140 self.assumptions.clear();
141 self.lit_to_index.clear();
142 self.current_level = AssumptionLevel::root();
143 self.conflict_set.clear();
144 }
145
146 pub fn get_all(&self) -> &[Assumption] {
148 &self.assumptions
149 }
150
151 pub fn get_literals(&self) -> Vec<Lit> {
153 self.assumptions.iter().map(|a| a.lit).collect()
154 }
155
156 pub fn get_at_level(&self, level: AssumptionLevel) -> Vec<&Assumption> {
158 self.assumptions
159 .iter()
160 .filter(|a| a.level == level)
161 .collect()
162 }
163
164 pub fn is_assumed(&self, lit: Lit) -> bool {
166 self.lit_to_index.contains_key(&lit)
167 }
168
169 pub fn get_level(&self, lit: Lit) -> Option<AssumptionLevel> {
171 self.lit_to_index
172 .get(&lit)
173 .and_then(|&idx| self.assumptions.get(idx))
174 .map(|a| a.level)
175 }
176
177 pub fn set_conflict(&mut self, core: Vec<Lit>) {
179 self.conflict_set = core;
180 }
181
182 pub fn get_conflict(&self) -> &[Lit] {
184 &self.conflict_set
185 }
186
187 pub fn current_level(&self) -> AssumptionLevel {
189 self.current_level
190 }
191
192 pub fn len(&self) -> usize {
194 self.assumptions.len()
195 }
196
197 pub fn is_empty(&self) -> bool {
199 self.assumptions.is_empty()
200 }
201}
202
203impl Default for AssumptionStack {
204 fn default() -> Self {
205 Self::new()
206 }
207}
208
209pub struct AssumptionCoreMinimizer {
211 fixed_assumptions: HashSet<Lit>,
213}
214
215impl AssumptionCoreMinimizer {
216 pub fn new() -> Self {
218 Self {
219 fixed_assumptions: HashSet::new(),
220 }
221 }
222
223 pub fn add_fixed(&mut self, lit: Lit) {
225 self.fixed_assumptions.insert(lit);
226 }
227
228 pub fn minimize_deletion(&self, core: &[Lit]) -> Vec<Lit> {
230 let mut minimal = core.to_vec();
233 minimal.retain(|&lit| self.fixed_assumptions.contains(&lit));
234 minimal
235 }
236
237 pub fn minimize_quickxplain(&self, core: &[Lit]) -> Vec<Lit> {
239 core.to_vec()
242 }
243
244 pub fn is_fixed(&self, lit: Lit) -> bool {
246 self.fixed_assumptions.contains(&lit)
247 }
248}
249
250impl Default for AssumptionCoreMinimizer {
251 fn default() -> Self {
252 Self::new()
253 }
254}
255
256pub struct AssumptionContext {
258 stack: AssumptionStack,
260 minimizer: AssumptionCoreMinimizer,
262 stats: AssumptionStats,
264}
265
266impl AssumptionContext {
267 pub fn new() -> Self {
269 Self {
270 stack: AssumptionStack::new(),
271 minimizer: AssumptionCoreMinimizer::new(),
272 stats: AssumptionStats::default(),
273 }
274 }
275
276 pub fn stack(&self) -> &AssumptionStack {
278 &self.stack
279 }
280
281 pub fn stack_mut(&mut self) -> &mut AssumptionStack {
283 &mut self.stack
284 }
285
286 pub fn minimizer(&self) -> &AssumptionCoreMinimizer {
288 &self.minimizer
289 }
290
291 pub fn minimizer_mut(&mut self) -> &mut AssumptionCoreMinimizer {
293 &mut self.minimizer
294 }
295
296 pub fn stats(&self) -> &AssumptionStats {
298 &self.stats
299 }
300
301 pub fn record_solve(&mut self, num_assumptions: usize, is_sat: bool) {
303 self.stats.total_calls += 1;
304 self.stats.total_assumptions += num_assumptions;
305 if !is_sat {
306 self.stats.unsat_calls += 1;
307 }
308 }
309
310 pub fn record_core(&mut self, core_size: usize, original_size: usize) {
312 self.stats.core_extractions += 1;
313 self.stats.total_core_size += core_size;
314 self.stats.total_original_size += original_size;
315 }
316}
317
318impl Default for AssumptionContext {
319 fn default() -> Self {
320 Self::new()
321 }
322}
323
324#[derive(Debug, Clone, Default)]
326pub struct AssumptionStats {
327 pub total_calls: u64,
329 pub unsat_calls: u64,
331 pub total_assumptions: usize,
333 pub core_extractions: u64,
335 pub total_core_size: usize,
337 pub total_original_size: usize,
339}
340
341impl AssumptionStats {
342 pub fn avg_assumptions(&self) -> f64 {
344 if self.total_calls == 0 {
345 return 0.0;
346 }
347 self.total_assumptions as f64 / self.total_calls as f64
348 }
349
350 pub fn avg_core_size(&self) -> f64 {
352 if self.core_extractions == 0 {
353 return 0.0;
354 }
355 self.total_core_size as f64 / self.core_extractions as f64
356 }
357
358 pub fn avg_minimization_ratio(&self) -> f64 {
360 if self.total_original_size == 0 {
361 return 1.0;
362 }
363 self.total_core_size as f64 / self.total_original_size as f64
364 }
365}
366
367#[cfg(test)]
368mod tests {
369 use super::*;
370
371 #[test]
372 fn test_assumption_stack_basic() {
373 let mut stack = AssumptionStack::new();
374
375 let lit = Lit::pos(Var(0));
376 assert!(stack.push(lit).is_ok());
377 assert_eq!(stack.len(), 1);
378 assert!(stack.is_assumed(lit));
379 }
380
381 #[test]
382 fn test_assumption_stack_conflict() {
383 let mut stack = AssumptionStack::new();
384
385 let lit = Lit::pos(Var(0));
386 stack.push(lit).expect("First assumption push must succeed");
387
388 let neg_lit = Lit::neg(Var(0));
389 assert!(stack.push(neg_lit).is_err());
390 }
391
392 #[test]
393 fn test_assumption_levels() {
394 let mut stack = AssumptionStack::new();
395
396 let lit1 = Lit::pos(Var(0));
397 stack
398 .push(lit1)
399 .expect("First assumption push must succeed");
400
401 stack.new_level();
402 let lit2 = Lit::pos(Var(1));
403 stack
404 .push(lit2)
405 .expect("Second assumption push must succeed");
406
407 assert_eq!(stack.len(), 2);
408
409 stack.pop_level();
410 assert_eq!(stack.len(), 1);
411 assert!(stack.is_assumed(lit1));
412 assert!(!stack.is_assumed(lit2));
413 }
414
415 #[test]
416 fn test_assumption_with_data() {
417 let mut stack = AssumptionStack::new();
418
419 let lit = Lit::pos(Var(0));
420 stack
421 .push_with_data(lit, 42)
422 .expect("Assumption push with data must succeed");
423
424 assert_eq!(stack.assumptions[0].user_data, Some(42));
425 }
426
427 #[test]
428 fn test_assumption_context() {
429 let mut ctx = AssumptionContext::new();
430
431 ctx.record_solve(5, false);
432 ctx.record_core(3, 5);
433
434 assert_eq!(ctx.stats().total_calls, 1);
435 assert_eq!(ctx.stats().unsat_calls, 1);
436 assert_eq!(ctx.stats().avg_core_size(), 3.0);
437 }
438}