cadical_sys/lib.rs
1//! Rust bindings for the `CaDiCaL` SAT Solver, providing low-level access to one of the most efficient Boolean Satisfiability (SAT) solving libraries.
2//!
3//! # Overview
4//!
5//! `cadical-sys` offers complete Rust bindings to the `CaDiCaL` SAT solver using the `cxx` crate, enabling seamless interoperability between Rust and C++ SAT solving capabilities.
6//!
7//! ## What is a SAT Solver?
8//!
9//! A SAT (Boolean Satisfiability) solver is a computational tool that determines whether there exists an assignment of boolean variables that makes a given boolean formula true. SAT solvers are crucial in:
10//! - Formal verification
11//! - Hardware design
12//! - AI planning
13//! - Cryptanalysis
14//! - Constraint solving
15//!
16//! ## About `CaDiCaL`
17//!
18//! [CaDiCaL](https://github.com/arminbiere/cadical) is a state-of-the-art, modern SAT solver developed by Armin Biere. Known for its:
19//! - High performance
20//! - Extensive features
21//! - Compact implementation
22//! - Advanced conflict-driven clause learning (CDCL) techniques
23//!
24//! # Features
25//!
26//! - Complete binding of `CaDiCaL` C++ API
27//! - Safe Rust wrappers using `cxx` (where possible)
28//! - Support for:
29//! - Adding clauses
30//! - Solving boolean satisfiability problems
31//! - Assumption handling
32//! - Advanced solver configuration
33//! - Proof tracing
34//! - Incremental solving
35//!
36//! # Installation
37//!
38//! Add to your `Cargo.toml`:
39//!
40//! ```toml
41//! [dependencies]
42//! cadical-sys = "0.1.0" # Replace with most recent version
43//! ```
44//!
45//! # Usage Examples
46//!
47//! ## Basic SAT solving example
48//! ```rust
49//! use cadical_sys::Status;
50//! use cadical_sys::CaDiCal;
51//!
52//! // Create a new solver instance
53//! let mut solver = CaDiCal::new();
54//!
55//! // Add clauses (representing a simple propositional logic problem)
56//! // For example, (x1 OR x2) AND (NOT x1 OR x3) AND (NOT x2 OR NOT x3)
57//! solver.clause2(1, 2); // x1 OR x2
58//! solver.clause2(-1, 3); // NOT x1 OR x3
59//! solver.clause2(-2, -3); // NOT x2 OR NOT x3
60//!
61//! // Solve the problem
62//! let status = solver.solve();
63//! match status {
64//! Status::SATISFIABLE => {
65//! // Get variable assignments
66//! println!("x1: {}", solver.val(1));
67//! println!("x2: {}", solver.val(2));
68//! println!("x3: {}", solver.val(3));
69//! },
70//! Status::UNSATISFIABLE => println!("No solution exists"),
71//! Status::UNKNOWN => println!("Solution status unknown")
72//! }
73//! ```
74//!
75//! ## Advanced example with assumptions and configuration
76//! ```rust
77//! use cadical_sys::Status;
78//! use cadical_sys::CaDiCal;
79//!
80//! let mut solver = CaDiCal::new();
81//!
82//! // Configure the solver
83//! solver.configure("plain".to_string());
84//!
85//! // Set some options
86//! solver.set("verbose".to_string(), 1);
87//!
88//! // Add complex clauses
89//! solver.clause3(1, 2, 3); // x1 OR x2 OR x3
90//! solver.clause3(-1, -2, -3); // NOT x1 OR NOT x2 OR NOT x3
91//!
92//! // Make assumptions
93//! solver.assume(1); // Assume x1 is true
94//!
95//! // Solve with assumptions
96//! let status = solver.solve();
97//!
98//! // Check solving results
99//! if status == Status::SATISFIABLE {
100//! // Interact with solved model
101//! let num_vars = solver.vars();
102//! for var in 1..=num_vars {
103//! println!("Variable {}: {}", var, solver.val(var));
104//! }
105//! }
106//! ```
107//!
108//! ## Example of reading DIMACS file and solving
109//! ```rust
110//! use cadical_sys::Status;
111//! use cadical_sys::CaDiCal;
112//!
113//! let mut solver = CaDiCal::new();
114//! let mut var_count = 0;
115//!
116//! // Read a DIMACS CNF file
117//! let result = solver.read_dimacs1(
118//! "./tests/problem.cnf".to_string(),
119//! "my_problem".to_string(),
120//! &mut var_count,
121//! 0
122//! );
123//!
124//! // Solve the problem from the file
125//! let status = solver.solve();
126//!
127//! // Write out results or extension
128//! if status == Status::SATISFIABLE {
129//! solver.write_extension("/tmp/solution.ext".to_string());
130//! }
131//! ```
132//!
133//! ## Demonstrating advanced solver interactions
134//! ```rust
135//! use cadical_sys::CaDiCal;
136//!
137//! let mut solver = CaDiCal::new();
138//!
139//! // Reserve variable space
140//! solver.reserve(1000);
141//!
142//! // Add observed variables for tracking
143//! solver.add_observed_var(42);
144//!
145//! // Perform simplification
146//! let simplify_status = solver.simplify(2);
147//!
148//! // Get solver statistics
149//! solver.statistics();
150//! solver.resources();
151//! ```
152//!
153//! # Performance Considerations
154//!
155//! - `CaDiCaL` is highly optimized for complex boolean satisfiability problems
156//! - Recommended for problems with thousands to millions of variables
157//! - Lower overhead compared to many other SAT solvers
158//!
159//! # Limitations
160//!
161//! - Requires understanding of boolean logic and SAT solving
162//! - Performance depends on problem complexity
163//! - Advanced features require deep knowledge of SAT solving techniques
164//!
165//! # Contributing
166//!
167//! Contributions are welcome! Please file issues or submit pull requests on the GitHub repository.
168//!
169//! # License
170//!
171//! `CaDiCaL` is distributed under the MIT License. Check the original repository for detailed licensing information.
172//!
173//! # References
174//!
175//! - [CaDiCaL GitHub Repository](https://github.com/arminbiere/cadical)
176//! - [cxx Rust Bindings](https://cxx.rs/)
177//! - [SAT Solver Overview](https://en.wikipedia.org/wiki/Boolean_satisfiability_problem)
178//!
179//! # Acknowledgments
180//!
181//! Special thanks to Armin Biere for developing and maintaining `CaDiCaL`.
182
183use bridge::ffi;
184use cxx::UniquePtr;
185
186/// This module contains the FFI bindings to the `CaDiCaL` SAT solver.
187/// Some functions are unsafe due to necessity.
188pub mod bridge;
189
190/// The SAT competition standardized the exit code of SAT solvers to the
191/// following which then is also used return code for 'solve' functions.
192/// In the following example we use those constants for brevity though.
193#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
194pub enum Status {
195 SATISFIABLE = 10,
196 UNSATISFIABLE = 20,
197 UNKNOWN = 0,
198}
199
200impl From<i32> for Status {
201 fn from(val: i32) -> Self {
202 match val {
203 10 => Status::SATISFIABLE,
204 20 => Status::UNSATISFIABLE,
205 0 => Status::UNKNOWN,
206 _ => unreachable!(),
207 }
208 }
209}
210
211/// States are represented by a bit-set in order to combine them.
212#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
213pub enum State {
214 /// during initialization (invalid)
215 INITIALIZING = 1,
216 /// configure options (with 'set')
217 CONFIGURING = 2,
218 /// ready to call 'solve'
219 STEADY = 4,
220 /// adding clause literals (zero missing)
221 ADDING = 8,
222 /// while solving (within 'solve')
223 SOLVING = 16,
224 /// satisfiable allows 'val'
225 SATISFIED = 32,
226 /// unsatisfiable allows 'failed'
227 UNSATISFIED = 64,
228 /// during and after deletion (invalid)
229 DELETING = 128,
230
231 /// These combined states are used to check contracts.
232 /// CONFIGURING | STEADY | SATISFIED | UNSATISFIED,
233 READY = 102,
234 /// READY | ADDING
235 VALID = 110,
236 /// INITIALIZING | DELETING
237 INVALID = 129,
238}
239
240impl From<i32> for State {
241 fn from(val: i32) -> Self {
242 match val {
243 1 => State::INITIALIZING,
244 2 => State::CONFIGURING,
245 4 => State::STEADY,
246 8 => State::ADDING,
247 16 => State::SOLVING,
248 32 => State::SATISFIED,
249 64 => State::UNSATISFIED,
250 128 => State::DELETING,
251 102 => State::READY,
252 110 => State::VALID,
253 129 => State::INVALID,
254 _ => unreachable!(),
255 }
256 }
257}
258
259pub struct CaDiCal {
260 solver: UniquePtr<ffi::Solver>,
261 last_terminator: Option<UniquePtr<ffi::Terminator>>,
262 last_learner: Option<UniquePtr<ffi::Learner>>,
263}
264
265impl Clone for CaDiCal {
266 fn clone(&self) -> Self {
267 let mut r = Self::new();
268 Self::copy(self, &mut r);
269 r
270 }
271}
272
273impl Default for CaDiCal {
274 fn default() -> Self {
275 Self::new()
276 }
277}
278
279impl CaDiCal {
280 #[must_use]
281 #[inline]
282 pub fn new() -> Self {
283 Self {
284 solver: ffi::constructor(),
285 last_terminator: None,
286 last_learner: None,
287 }
288 }
289
290 /// Core functionality as in the IPASIR incremental SAT solver interface.
291 /// (recall 'READY = CONFIGURING | STEADY | SATISFIED | UNSATISFIED').
292 /// Further note that 'lit' is required to be different from '`INT_MIN`' and
293 /// different from '0' except for 'add'.
294 ///
295 /// Add valid literal to clause or zero to terminate clause.
296 ///
297 /// require (VALID) recall 'VALID = READY | ADDING'
298 ///
299 /// if (lit) ensure (ADDING) and thus VALID but not READY
300 ///
301 /// if (!lit) ensure (STEADY ) and thus READY
302 ///
303 #[inline]
304 pub fn add(&mut self, lit: i32) {
305 ffi::add(&mut self.solver, lit);
306 }
307
308 /// Here are functions simplifying clause addition. The given literals
309 /// should all be valid (different from '`INT_MIN`' and different from '0').
310 ///
311 /// require (VALID)
312 /// ensure (STEADY )
313 ///
314 #[inline]
315 pub fn clause1(&mut self, l1: i32) {
316 ffi::clause1(&mut self.solver, l1);
317 }
318
319 #[inline]
320 pub fn clause2(&mut self, l1: i32, l2: i32) {
321 ffi::clause2(&mut self.solver, l1, l2);
322 }
323
324 #[inline]
325 pub fn clause3(&mut self, l1: i32, l2: i32, l3: i32) {
326 ffi::clause3(&mut self.solver, l1, l2, l3);
327 }
328
329 #[inline]
330 pub fn clause4(&mut self, l1: i32, l2: i32, l3: i32, l4: i32) {
331 ffi::clause4(&mut self.solver, l1, l2, l3, l4);
332 }
333
334 #[inline]
335 pub fn clause5(&mut self, l1: i32, l2: i32, l3: i32, l4: i32, l5: i32) {
336 ffi::clause5(&mut self.solver, l1, l2, l3, l4, l5);
337 }
338
339 #[inline]
340 pub fn clause6(&mut self, v: &[i32]) {
341 ffi::clause6(&mut self.solver, v);
342 }
343
344 /// This function can be used to check if the formula is already
345 /// inconsistent (contains the empty clause or was proven to be
346 /// root-level unsatisfiable).
347 #[inline]
348 pub fn inconsistent(&mut self) -> bool {
349 ffi::inconsistent(&mut self.solver)
350 }
351
352 /// Assume valid non zero literal for next call to 'solve'. These
353 /// assumptions are reset after the call to 'solve' as well as after
354 /// returning from 'simplify' and 'lookahead.
355 ///
356 /// require (READY)
357 /// ensure (STEADY )
358 ///
359 #[inline]
360 pub fn assume(&mut self, lit: i32) {
361 ffi::assume(&mut self.solver, lit);
362 }
363
364 /// Try to solve the current formula. Returns
365 ///
366 /// 0 = UNKNOWN (limit reached or interrupted through 'terminate')
367 /// 10 = SATISFIABLE
368 /// 20 = UNSATISFIABLE
369 ///
370 /// require (READY)
371 /// ensure (STEADY | SATISFIED | UNSATISFIED)
372 ///
373 /// Note, that while in this call the solver actually transitions to state
374 /// 'SOLVING', which however is only visible from a different context,
375 /// i.e., from a different thread or from a signal handler. Only right
376 /// before returning from this call it goes into a 'READY' state.
377 ///
378 #[inline]
379 pub fn solve(&mut self) -> Status {
380 ffi::solve(&mut self.solver).into()
381 }
382
383 /// Get value (-lit=false, lit=true) of valid non-zero literal.
384 ///
385 /// require (SATISFIED)
386 /// ensure (SATISFIED)
387 ///
388 #[inline]
389 pub fn val(&mut self, lit: i32) -> i32 {
390 ffi::val(&mut self.solver, lit)
391 }
392
393 /// Try to flip the value of the given literal without falsifying the
394 /// formula. Returns 'true' if this was successful. Otherwise the model is
395 /// not changed and 'false' is returned. If a literal was eliminated or
396 /// substituted flipping will fail on that literal and in particular the
397 /// solver will not taint it nor restore any clauses.
398 ///
399 /// The 'flip' function can only flip the value of a variables not acting
400 /// as witness on the reconstruction stack.
401 ///
402 /// As a side effect of calling this function first all assigned variables
403 /// are propagated again without using blocking literal. Thus the first
404 /// call to this function after obtaining a model adds a substantial
405 /// overhead. Subsequent calls will not need to properly propagate again.
406 ///
407 /// Furthermore if the reconstruction stack is non-empty and has been
408 /// traversed to reconstruct a full extended model for eliminated
409 /// variables (and to satisfy removed blocked clauses), the values of these
410 /// witness variables obtained via 'val' before become invalid. The user
411 /// thus will need to call 'val' again after calling 'flip' which will
412 /// trigger then a traversal of the reconstruction stack.
413 ///
414 /// So try to avoid mixing 'flip' and 'val' (for efficiency only).
415 /// Further, this functionality is currently not supported in the presence
416 /// of an external propagator.
417 ///
418 /// require (SATISFIED)
419 /// ensure (SATISFIED)
420 ///
421 #[inline]
422 pub fn flip(&mut self, lit: i32) -> bool {
423 ffi::flip(&mut self.solver, lit)
424 }
425
426 /// Same as 'flip' without actually flipping it. This functionality is
427 /// currently not supported in the presence of an external propagator.
428 ///
429 /// require (SATISFIED)
430 /// ensure (SATISFIED)
431 ///
432 #[inline]
433 pub fn flippable(&mut self, lit: i32) -> bool {
434 ffi::flippable(&mut self.solver, lit)
435 }
436
437 /// Determine whether the valid non-zero literal is in the core.
438 /// Returns 'true' if the literal is in the core and 'false' otherwise.
439 /// Note that the core does not have to be minimal.
440 ///
441 /// require (UNSATISFIED)
442 /// ensure (UNSATISFIED)
443 ///
444 #[inline]
445 pub fn failed(&mut self, lit: i32) -> bool {
446 ffi::failed(&mut self.solver, lit)
447 }
448
449 /// Add call-back which is checked regularly for termination. There can
450 /// only be one terminator connected. If a second (non-zero) one is added
451 /// the first one is implicitly disconnected.
452 ///
453 /// require (VALID)
454 /// ensure (VALID)
455 ///
456 #[inline]
457 #[allow(clippy::missing_panics_doc)]
458 pub fn connect_terminator<'a, 'b: 'a, T: Terminator>(&'a mut self, terminator: &'b mut T) {
459 fn f<T: Terminator>(state: *mut u8) -> bool {
460 let ptr: *mut T = state.cast::<T>();
461 let i = unsafe { &mut *ptr };
462 i.terminated()
463 }
464 let terminator =
465 unsafe { ffi::new_terminator(std::ptr::from_mut(terminator).cast::<u8>(), f::<T>) };
466 self.last_terminator = Some(terminator);
467 ffi::connect_terminator(&mut self.solver, self.last_terminator.as_mut().unwrap());
468 }
469
470 #[inline]
471 pub fn disconnect_terminator(&mut self) {
472 ffi::disconnect_terminator(&mut self.solver);
473 self.last_terminator = None;
474 }
475
476 /// Add call-back which allows to export learned clauses.
477 ///
478 /// require (VALID)
479 /// ensure (VALID)
480 ///
481 #[inline]
482 #[allow(clippy::missing_panics_doc)]
483 pub fn connect_learner<'a, 'b: 'a, T: Learner>(&'a mut self, learner: &'b mut T) {
484 fn learning<T: Learner>(state: *mut u8, size: i32) -> bool {
485 let ptr: *mut T = state.cast::<T>();
486 let i = unsafe { &mut *ptr };
487 i.learning(size)
488 }
489
490 fn learn<T: Learner>(state: *mut u8, lit: i32) {
491 let ptr: *mut T = state.cast::<T>();
492 let i = unsafe { &mut *ptr };
493 i.learn(lit);
494 }
495
496 let learner = unsafe {
497 ffi::new_learner(
498 std::ptr::from_mut(learner).cast::<u8>(),
499 learning::<T>,
500 learn::<T>,
501 )
502 };
503 self.last_learner = Some(learner);
504 ffi::connect_learner(&mut self.solver, self.last_learner.as_mut().unwrap());
505 }
506
507 #[inline]
508 pub fn disconnect_learner(&mut self) {
509 ffi::disconnect_learner(&mut self.solver);
510 self.last_learner = None;
511 }
512
513 // /// Add call-back which allows to observe when a variable is fixed.
514 // ///
515 // /// require (VALID)
516 // /// ensure (VALID)
517 // ///
518 // pub fn connect_fixed_listener<F: FixedAssignmentListener>(&mut self, _fixed_listener: F) {
519 // todo!()
520 // }
521 #[inline]
522 pub fn disconnect_fixed_listener(&mut self) {
523 ffi::disconnect_fixed_listener(&mut self.solver);
524 }
525
526 // /// Add call-back which allows to learn, propagate and backtrack based on
527 // /// external constraints. Only one external propagator can be connected
528 // /// and after connection every related variables must be 'observed' (use
529 // /// 'add_observed_var' function).
530 // /// Disconnection of the external propagator resets all the observed
531 // /// variables.
532 // ///
533 // /// require (VALID)
534 // /// ensure (VALID)
535 // ///
536 // pub fn connect_external_propagator<P: ExternalPropagator>(&mut self, propagator: P) {
537 // todo!()
538 // }
539 // pub fn disconnect_external_propagator(&mut self) {
540 // ffi::disconnect_external_propagator(&mut self.solver);
541 // }
542
543 /// Mark as 'observed' those variables that are relevant to the external
544 /// propagator. External propagation, clause addition during search and
545 /// notifications are all over these observed variabes.
546 /// A variable can not be observed witouth having an external propagator
547 /// connected. Observed variables are "frozen" internally, and so
548 /// inprocessing will not consider them as candidates for elimination.
549 /// An observed variable is allowed to be a fresh variable and it can be
550 /// added also during solving.
551 ///
552 /// require (`VALID_OR_SOLVING`)
553 /// ensure (`VALID_OR_SOLVING`)
554 ///
555 #[inline]
556 pub fn add_observed_var(&mut self, var: i32) {
557 ffi::add_observed_var(&mut self.solver, var);
558 }
559
560 /// Removes the 'observed' flag from the given variable. A variable can be
561 /// set unobserved only between solve calls, not during it (to guarantee
562 /// that no yet unexplained external propagation involves it).
563 ///
564 /// require (VALID)
565 /// ensure (VALID)
566 ///
567 #[inline]
568 pub fn remove_observed_var(&mut self, var: i32) {
569 ffi::remove_observed_var(&mut self.solver, var);
570 }
571
572 /// Removes all the 'observed' flags from the variables. Disconnecting the
573 /// propagator invokes this step as well.
574 ///
575 /// require (VALID)
576 /// ensure (VALID)
577 ///
578 #[inline]
579 pub fn reset_observed_vars(&mut self) {
580 ffi::reset_observed_vars(&mut self.solver);
581 }
582
583 /// Get reason of valid observed literal (true = it is an observed variable
584 /// and it got assigned by a decision during the CDCL loop. Otherwise:
585 /// false.
586 ///
587 /// require (`VALID_OR_SOLVING`)
588 /// ensure (`VALID_OR_SOLVING`)
589 ///
590 #[inline]
591 pub fn is_decision(&mut self, lit: i32) -> bool {
592 ffi::is_decision(&mut self.solver, lit)
593 }
594
595 /// Force solve to backtrack to certain decision level. Can be called only
596 /// during '`cb_decide`' of a connected External Propagator.
597 /// Invoking in any other time will not have an effect.
598 /// If the call had an effect, the External Propagator will be notified about
599 /// the backtrack via '`notify_backtrack`'.
600 ///
601 /// require (SOLVING)
602 /// ensure (SOLVING)
603 ///
604 #[inline]
605 pub fn force_backtrack(&mut self, new_level: usize) {
606 ffi::force_backtrack(&mut self.solver, new_level);
607 }
608
609 //------------------------------------------------------------------------
610 /// Adds a literal to the constraint clause. Same functionality as 'add'
611 /// but the clause only exists for the next call to solve (same lifetime as
612 /// assumptions). Only one constraint may exists at a time. A new
613 /// constraint replaces the old. The main application of this functonality
614 /// is the model checking algorithm IC3. See our FMCAD'21 paper
615 /// [FroleyksBiere-FMCAD'19] for more details.
616 ///
617 /// Add valid literal to the constraint clause or zero to terminate it.
618 ///
619 /// require (VALID) /// recall 'VALID = READY |
620 /// ADDING' if (lit) ensure (ADDING) /// and thus VALID but not
621 /// READY if (!lit) && !`adding_clause` ensure (STEADY ) // and thus READY
622 ///
623 #[inline]
624 pub fn constrain(&mut self, lit: i32) {
625 ffi::constrain(&mut self.solver, lit);
626 }
627
628 /// Determine whether the constraint was used to proof the
629 /// unsatisfiability. Note that the formula might still be unsatisfiable
630 /// without the constraint.
631 ///
632 /// require (UNSATISFIED)
633 /// ensure (UNSATISFIED)
634 ///
635 #[inline]
636 pub fn constraint_failed(&mut self) -> bool {
637 ffi::constraint_failed(&mut self.solver)
638 }
639
640 //------------------------------------------------------------------------
641 /// This function determines a good splitting literal. The result can be
642 /// zero if the formula is proven to be satisfiable or unsatisfiable. This
643 /// can then be checked by 'state ()'. If the formula is empty and
644 /// the function is not able to determine satisfiability also zero is
645 /// returned but the state remains steady.
646 ///
647 /// require (READY)
648 /// ensure (STEADY |SATISFIED|UNSATISFIED)
649 ///
650 #[inline]
651 pub fn lookahead(&mut self) -> i32 {
652 ffi::lookahead(&mut self.solver)
653 }
654
655 #[inline]
656 pub fn generate_cubes(&mut self, x: i32, min_depth: i32, result_cubes: &mut Vec<i32>) -> i32 {
657 ffi::generate_cubes(&mut self.solver, x, min_depth, result_cubes)
658 }
659
660 #[inline]
661 pub fn reset_assumptions(&mut self) {
662 ffi::reset_assumptions(&mut self.solver);
663 }
664
665 #[inline]
666 pub fn reset_constraint(&mut self) {
667 ffi::reset_constraint(&mut self.solver);
668 }
669
670 /// Return the current state of the solver as defined above.
671 ///
672 #[must_use]
673 #[inline]
674 pub fn state(&self) -> State {
675 ffi::state(&self.solver).into()
676 }
677
678 /// Similar to 'state ()' but using the staddard competition exit codes of
679 /// '10' for 'SATISFIABLE', '20' for 'UNSATISFIABLE' and '0' otherwise.
680 ///
681 #[must_use]
682 #[inline]
683 pub fn status(&self) -> Status {
684 ffi::status(&self.solver).into()
685 }
686
687 /// return version string
688 #[must_use]
689 #[inline]
690 pub fn version() -> String {
691 ffi::version()
692 }
693
694 /*----------------------------------------------------------------------*/
695 /// Copy 'this' into a fresh 'other'. The copy procedure is not a deep
696 /// clone, but only copies irredundant clauses and units. It also makes
697 /// sure that witness reconstruction works with the copy as with the
698 /// original formula such that both solvers have the same models.
699 /// Assumptions are not copied. Options however are copied as well as
700 /// flags which remember the current state of variables in preprocessing.
701 ///
702 /// require (READY) /// for 'this'
703 /// ensure (READY) /// for 'this'
704 ///
705 /// other.require (CONFIGURING)
706 /// other.ensure (CONFIGURING | STEADY )
707 ///
708 #[inline]
709 pub fn copy(source: &CaDiCal, destination: &mut CaDiCal) {
710 ffi::copy(&source.solver, &mut destination.solver);
711 }
712
713 /*----------------------------------------------------------------------*/
714 /// Variables are usually added and initialized implicitly whenever a
715 /// literal is used as an argument except for the functions 'val', 'fixed',
716 /// 'failed' and 'frozen'. However, the library internally keeps a maximum
717 /// variable index, which can be queried.
718 ///
719 /// require (VALID | SOLVING)
720 /// ensure (VALID | SOLVING)
721 ///
722 #[inline]
723 pub fn vars(&mut self) -> i32 {
724 ffi::vars(&mut self.solver)
725 }
726
727 /// Increase the maximum variable index explicitly. This function makes
728 /// sure that at least '`min_max_var`' variables are initialized. Since it
729 /// might need to reallocate tables, it destroys a satisfying assignment
730 /// and has the same state transition and conditions as 'assume' etc.
731 ///
732 /// require (READY)
733 /// ensure (STEADY )
734 ///
735 #[inline]
736 pub fn reserve(&mut self, min_max_var: i32) {
737 ffi::reserve(&mut self.solver, min_max_var);
738 }
739
740 // pub fn `trace_api_calls(&mut` self, file: String);
741
742 //------------------------------------------------------------------------
743 /// Option handling.
744 /// Determine whether 'name' is a valid option name.
745 ///
746 #[must_use]
747 #[inline]
748 pub fn is_valid_option(name: String) -> bool {
749 ffi::is_valid_option(name)
750 }
751
752 /// Determine whether 'name' enables a specific preprocessing technique.
753 ///
754 #[must_use]
755 #[inline]
756 pub fn is_preprocessing_option(name: String) -> bool {
757 ffi::is_preprocessing_option(name)
758 }
759
760 /// Determine whether 'arg' is a valid long option of the form '--<name>',
761 /// '--<name>=<val>' or '--no-<name>' similar to '`set_long_option`' below.
762 /// Legal values are 'true', 'false', or '[-]<mantissa>[e<exponent>]'.
763 #[must_use]
764 #[inline]
765 pub fn is_valid_long_option(arg: String) -> bool {
766 ffi::is_valid_long_option(arg)
767 }
768
769 /// Get the current value of the option 'name'. If 'name' is invalid then
770 /// zero is returned. Here '--...' arguments as invalid options.
771 ///
772 #[inline]
773 pub fn get(&mut self, name: String) -> i32 {
774 ffi::get(&mut self.solver, name)
775 }
776
777 /// Set the default verbose message prefix (default "c ").
778 ///
779 #[inline]
780 pub fn prefix(&mut self, verbose_message_prefix: String) {
781 ffi::prefix(&mut self.solver, verbose_message_prefix);
782 }
783
784 /// Explicit version of setting an option. If the option '<name>' exists
785 /// and '<val>' can be parsed then 'true' is returned. If the option value
786 /// is out of range the actual value is computed as the closest (minimum or
787 /// maximum) value possible, but still 'true' is returned.
788 ///
789 /// require (CONFIGURING)
790 /// ensure (CONFIGURING)
791 ///
792 /// Thus options can only bet set right after initialization.
793 ///
794 #[inline]
795 pub fn set(&mut self, name: String, val: i32) -> bool {
796 ffi::set(&mut self.solver, name, val)
797 }
798
799 /// This function accepts options in command line syntax:
800 ///
801 /// '--<name>=<val>', '--<name>', or '--no-<name>'
802 ///
803 /// It actually calls the previous 'set' function after parsing 'arg'. The
804 /// same values are expected as for '`is_valid_long_option`' above and as
805 /// with 'set' any value outside of the range of legal values for a
806 /// particular option are set to either the minimum or maximum depending on
807 /// which side of the valid interval they lie.
808 ///
809 /// require (CONFIGURING)
810 /// ensure (CONFIGURING)
811 ///
812 #[inline]
813 pub fn set_long_option(&mut self, arg: String) -> bool {
814 ffi::set_long_option(&mut self.solver, arg)
815 }
816
817 /// Determine whether 'name' is a valid configuration.
818 ///
819 #[must_use]
820 #[inline]
821 pub fn is_valid_configuration(name: String) -> bool {
822 ffi::is_valid_configuration(name)
823 }
824
825 /// Overwrite (some) options with the forced values of the configuration.
826 /// The result is 'true' iff the 'name' is a valid configuration.
827 ///
828 /// require (CONFIGURING)
829 /// ensure (CONFIGURING)
830 ///
831 #[inline]
832 pub fn configure(&mut self, name: String) -> bool {
833 ffi::configure(&mut self.solver, name)
834 }
835
836 /// Increase preprocessing and inprocessing limits by '10^<val>'. Values
837 /// below '0' are ignored and values above '9' are reduced to '9'.
838 ///
839 /// require (READY)
840 /// ensure (READY)
841 ///
842 #[inline]
843 pub fn optimize(&mut self, val: i32) {
844 ffi::optimize(&mut self.solver, val);
845 }
846
847 /// Specify search limits, where currently 'name' can be "conflicts",
848 /// "decisions", "preprocessing", or "localsearch". The first two limits
849 /// are unbounded by default. Thus using a negative limit for conflicts or
850 /// decisions switches back to the default of unlimited search (for that
851 /// particular limit). The preprocessing limit determines the number of
852 /// preprocessing rounds, which is zero by default. Similarly, the local
853 /// search limit determines the number of local search rounds (also zero by
854 /// default). As with 'set', the return value denotes whether the limit
855 /// 'name' is valid. These limits are only valid for the next 'solve' or
856 /// 'simplify' call and reset to their default after 'solve' returns (as
857 /// well as overwritten and reset during calls to 'simplify' and
858 /// 'lookahead'). We actually also have an internal "terminate" limit
859 /// which however should only be used for testing and debugging.
860 ///
861 /// require (READY)
862 /// ensure (READY)
863 ///
864 #[inline]
865 pub fn limit(&mut self, arg: String, val: i32) -> bool {
866 ffi::limit(&mut self.solver, arg, val)
867 }
868 #[inline]
869 pub fn is_valid_limit(&mut self, arg: String) -> bool {
870 ffi::is_valid_limit(&mut self.solver, arg)
871 }
872
873 /// The number of currently active variables and clauses can be queried by
874 /// these functions. Variables become active if a clause is added with it.
875 /// They become inactive if they are eliminated or fixed at the root level
876 /// Clauses become inactive if they are satisfied, subsumed, eliminated.
877 /// Redundant clauses are reduced regularly and thus the 'redundant'
878 /// function is less useful.
879 ///
880 /// require (VALID)
881 /// ensure (VALID)
882 ///
883 /// Number of active variables.
884 #[must_use]
885 #[inline]
886 pub fn active(&self) -> i32 {
887 ffi::active(&self.solver)
888 }
889
890 /// Number of active redundant clauses.
891 #[must_use]
892 #[inline]
893 pub fn redundant(&self) -> i64 {
894 ffi::redundant(&self.solver)
895 }
896
897 /// Number of active irredundant clauses.
898 #[must_use]
899 #[inline]
900 pub fn irredundant(&self) -> i64 {
901 ffi::irredundant(&self.solver)
902 }
903
904 //------------------------------------------------------------------------
905 /// This function executes the given number of preprocessing rounds. It is
906 /// similar to 'solve' with 'limits ("preprocessing", rounds)' except that
907 /// no CDCL nor local search, nor lucky phases are executed. The result
908 /// values are also the same: 0=UNKNOWN, 10=SATISFIABLE, 20=UNSATISFIABLE.
909 /// As 'solve' it resets current assumptions and limits before returning.
910 /// The numbers of rounds should not be negative. If the number of rounds
911 /// is zero only clauses are restored (if necessary) and top level unit
912 /// propagation is performed, which both take some time.
913 ///
914 /// require (READY)
915 /// ensure (STEADY | SATISFIED | UNSATISFIED)
916 ///
917 #[inline]
918 pub fn simplify(&mut self, rounds: i32) -> Status {
919 ffi::simplify(&mut self.solver, rounds).into()
920 }
921
922 //------------------------------------------------------------------------
923 /// Force termination of 'solve' asynchronously.
924 ///
925 /// require (SOLVING | READY)
926 /// ensure (STEADY ) /// actually not immediately (synchronously)
927 ///
928 #[inline]
929 pub fn terminate(&mut self) {
930 ffi::terminate(&mut self.solver);
931 }
932
933 //------------------------------------------------------------------------
934
935 /// We have the following common reference counting functions, which avoid
936 /// to restore clauses but require substantial user guidance. This was the
937 /// only way to use inprocessing in incremental SAT solving in Lingeling
938 /// (and before in `MiniSAT`'s 'freeze' / 'thaw') and which did not use
939 /// automatic clause restoring. In general this is slower than
940 /// restoring clauses and should not be used.
941 ///
942 /// In essence the user freezes variables which potentially are still
943 /// needed in clauses added or assumptions used after the next 'solve'
944 /// call. As in Lingeling you can freeze a variable multiple times, but
945 /// then have to melt it the same number of times again in order to enable
946 /// variable eliminating on it etc. The arguments can be literals
947 /// (negative indices) but conceptually variables are frozen.
948 ///
949 /// In the old way of doing things without restore you should not use a
950 /// variable incrementally (in 'add' or 'assume'), which was used before
951 /// and potentially could have been eliminated in a previous 'solve' call.
952 /// This can lead to spurious satisfying assignment. In order to check
953 /// this API contract one can use the 'checkfrozen' option. This has the
954 /// drawback that restoring clauses implicitly would fail with a fatal
955 /// error message even if in principle the solver could just restore
956 /// clauses. Thus this option is disabled by default.
957 ///
958 /// See our SAT'19 paper [FazekasBiereScholl-SAT'19] for more details.
959 ///
960 /// require (VALID)
961 /// ensure (VALID)
962 ///
963 #[must_use]
964 #[inline]
965 pub fn frozen(&self, lit: i32) -> bool {
966 ffi::frozen(&self.solver, lit)
967 }
968
969 #[inline]
970 pub fn freeze(&mut self, lit: i32) {
971 ffi::freeze(&mut self.solver, lit);
972 }
973
974 #[inline]
975 pub fn melt(&mut self, lit: i32) {
976 ffi::melt(&mut self.solver, lit);
977 }
978
979 //------------------------------------------------------------------------
980 /// Root level assigned variables can be queried with this function.
981 /// It returns '1' if the literal is implied by the formula, '-1' if its
982 /// negation is implied, or '0' if this is unclear at this point.
983 ///
984 /// require (VALID)
985 /// ensure (VALID)
986 ///
987 #[must_use]
988 #[inline]
989 pub fn fixed(&self, lit: i32) -> i32 {
990 ffi::fixed(&self.solver, lit)
991 }
992
993 //------------------------------------------------------------------------
994 /// Force the default decision phase of a variable to a certain value.
995 ///
996 #[inline]
997 pub fn phase(&mut self, lit: i32) {
998 ffi::phase(&mut self.solver, lit);
999 }
1000
1001 #[inline]
1002 pub fn unphase(&mut self, lit: i32) {
1003 ffi::unphase(&mut self.solver, lit);
1004 }
1005
1006 //------------------------------------------------------------------------
1007 /// Enables clausal proof tracing in DRAT format and returns 'true' if
1008 /// successfully opened for writing. Writing proofs has to be enabled
1009 /// before calling 'solve', 'add' and 'dimacs', that is in state
1010 /// 'CONFIGURING'. Otherwise only partial proofs would be written.
1011 ///
1012 /// require (CONFIGURING)
1013 /// ensure (CONFIGURING)
1014 ///
1015 /// Write DRAT proof.
1016 #[inline]
1017 pub fn trace_proof1(&mut self, file: String, name: String) -> bool {
1018 ffi::trace_proof1(&mut self.solver, file, name)
1019 }
1020
1021 /// Open & write proof.
1022 #[inline]
1023 pub fn trace_proof2(&mut self, path: String) -> bool {
1024 ffi::trace_proof2(&mut self.solver, path)
1025 }
1026
1027 /// Flushing the proof trace file eventually calls 'fflush' on the actual
1028 /// file or pipe and thus if this function returns all the proof steps
1029 /// should have been written (with the same guarantees as 'fflush').
1030 ///
1031 /// The additional optional argument forces to print the number of addition
1032 /// and deletion steps in the proof even if the verbosity level is zero but
1033 /// not if quiet is set as well. The default for the stand-alone solver is
1034 /// to print this information (in the 'closing proof' section) but for API
1035 /// usage of the library we want to stay silent unless explicitly requested
1036 /// or verbosity is non-zero (and as explained quiet is not set).
1037 ///
1038 /// This function can be called multiple times.
1039 ///
1040 /// require (VALID)
1041 /// ensure (VALID)
1042 ///
1043 #[inline]
1044 pub fn flush_proof_trace(&mut self, print: bool) {
1045 ffi::flush_proof_trace(&mut self.solver, print);
1046 }
1047
1048 /// Close proof trace early. Similar to 'flush' we allow the user to
1049 /// control with 'print' in a more fine-grained way whether statistics
1050 /// about the size of the written proof file and if compressed on-the-fly
1051 /// the number of actual bytes written (including deflation percentage) are
1052 /// printed. Before actually closing (or detaching in case of writing to
1053 /// '<stdout>') we check whether '`flush_proof_trace`' was called since the
1054 /// last time a proof step (addition or deletion) was traced. If this is
1055 /// not the case we would call '`flush_proof_trace`' with the same 'print'
1056 /// argument.
1057 ///
1058 /// require (VALID)
1059 /// ensure (VALID)
1060 ///
1061 #[inline]
1062 pub fn close_proof_trace(&mut self, print: bool) {
1063 ffi::close_proof_trace(&mut self.solver, print);
1064 }
1065
1066 // /// Enables clausal proof tracing with or without antecedents using
1067 // /// the Tracer interface defined in 'tracer.hpp'
1068 // ///
1069 // /// InternalTracer, StatTracer and FileTracer for internal use
1070 // ///
1071 // /// require (CONFIGURING)
1072 // /// ensure (CONFIGURING)
1073 // ///
1074 // pub fn connect_proof_tracer1(&mut self, tracer: &mut UniquePtr<Tracer>, antecedents: bool) {
1075 // todo!()
1076 // }
1077
1078 // pub fn connect_proof_tracer2(
1079 // &mut self,
1080 // tracer: &mut UniquePtr<InternalTracer>,
1081 // antecedents: bool,
1082 // ) {
1083 // todo!()
1084 // }
1085 // pub fn connect_proof_tracer3(&mut self, tracer: &mut UniquePtr<StatTracer>, antecedents: bool) {
1086 // todo!()
1087 // }
1088
1089 // pub fn connect_proof_tracer4(&mut self, tracer: &mut UniquePtr<FileTracer>, antecedents: bool) {
1090 // todo!()
1091 // }
1092
1093 /// Triggers the conclusion of incremental proofs.
1094 /// if the solver is SATISFIED it will trigger extend ()
1095 /// and give the model to the proof tracer through `conclude_sat` ()
1096 /// if the solver is UNSATISFIED it will trigger failing ()
1097 /// which will learn new clauses as explained below:
1098 /// In case of failed assumptions will provide a core negated
1099 /// as a clause through the proof tracer interface.
1100 /// With a failing contraint these can be multiple clauses.
1101 /// Then it will trigger a `conclude_unsat` event with the id(s)
1102 /// of the newly learnt clauses or the id of the global conflict.
1103 ///
1104 /// require (SATISFIED || UNSATISFIED)
1105 /// ensure (SATISFIED || UNSATISFIED)
1106 ///
1107 #[inline]
1108 pub fn conclude(&mut self) {
1109 ffi::conclude(&mut self.solver);
1110 }
1111
1112 // /// Disconnect proof tracer. If this is not done before deleting
1113 // /// the tracer will be deleted. Returns true if successful.
1114 // ///
1115 // /// require (VALID)
1116 // /// ensure (VALID)
1117 // ///
1118 // pub fn disconnect_proof_tracer1(&mut self, tracer: &mut UniquePtr<Tracer>) -> bool {
1119 // todo!()
1120 // }
1121 // pub fn disconnect_proof_tracer2(&mut self, tracer: &mut UniquePtr<StatTracer>) -> bool {
1122 // todo!()
1123 // }
1124 // pub fn disconnect_proof_tracer3(&mut self, tracer: &mut UniquePtr<FileTracer>) -> bool {
1125 // todo!()
1126 // }
1127
1128 /// print usage information for long options
1129 #[inline]
1130 pub fn usage() {
1131 ffi::usage();
1132 }
1133
1134 /// print configuration usage options
1135 #[inline]
1136 pub fn configurations() {
1137 ffi::configurations();
1138 }
1139
1140 /// require (!DELETING)
1141 /// ensure (!DELETING)
1142 ///
1143 /// print statistics
1144 #[inline]
1145 pub fn statistics(&mut self) {
1146 ffi::statistics(&mut self.solver);
1147 }
1148
1149 /// print resource usage (time and memory)
1150 #[inline]
1151 pub fn resources(&mut self) {
1152 ffi::resources(&mut self.solver);
1153 }
1154
1155 /// require (VALID)
1156 /// ensure (VALID)
1157 ///
1158 /// print current option and value list
1159 #[inline]
1160 pub fn options(&mut self) {
1161 ffi::options(&mut self.solver);
1162 }
1163
1164 //------------------------------------------------------------------------
1165 /// Traverse irredundant clauses or the extension stack in reverse order.
1166 ///
1167 /// The return value is false if traversal is aborted early due to one of
1168 /// the visitor functions returning false. See description of the
1169 /// iterators below for more details on how to use these functions.
1170 ///
1171 /// require (VALID)
1172 /// ensure (VALID)
1173 ///
1174 #[inline]
1175 pub fn traverse_clauses<I: ClauseIterator>(&self, i: &mut I) -> bool {
1176 fn f<I: ClauseIterator>(state: *mut u8, clause: &[i32]) -> bool {
1177 let ptr: *mut I = state.cast::<I>();
1178 let i = unsafe { &mut *ptr };
1179 i.clause(clause)
1180 }
1181 let mut iter =
1182 unsafe { ffi::new_clause_iterator(std::ptr::from_mut(i).cast::<u8>(), f::<I>) };
1183 ffi::traverse_clauses(&self.solver, &mut iter)
1184 }
1185
1186 #[inline]
1187 pub fn traverse_witnesses_backward<I: WitnessIterator>(&self, i: &mut I) -> bool {
1188 fn f<I: WitnessIterator>(state: *mut u8, clause: &[i32], witness: &[i32], id: u64) -> bool {
1189 let ptr: *mut I = state.cast::<I>();
1190 let i = unsafe { &mut *ptr };
1191 i.witness(clause, witness, id)
1192 }
1193 let mut iter =
1194 unsafe { ffi::new_witness_iterator(std::ptr::from_mut(i).cast::<u8>(), f::<I>) };
1195 ffi::traverse_witnesses_backward(&self.solver, &mut iter)
1196 }
1197
1198 #[inline]
1199 pub fn traverse_witnesses_forward<I: WitnessIterator>(&self, i: &mut I) -> bool {
1200 fn f<I: WitnessIterator>(state: *mut u8, clause: &[i32], witness: &[i32], id: u64) -> bool {
1201 let ptr: *mut I = state.cast::<I>();
1202 let i = unsafe { &mut *ptr };
1203 i.witness(clause, witness, id)
1204 }
1205 let mut iter =
1206 unsafe { ffi::new_witness_iterator(std::ptr::from_mut(i).cast::<u8>(), f::<I>) };
1207 ffi::traverse_witnesses_forward(&self.solver, &mut iter)
1208 }
1209
1210 //------------------------------------------------------------------------
1211 /// Files with explicit path argument support compressed input and output
1212 /// if appropriate helper functions 'gzip' etc. are available. They are
1213 /// called through opening a pipe to an external command.
1214 ///
1215 /// If the 'strict' argument is zero then the number of variables and
1216 /// clauses specified in the DIMACS headers are ignored, i.e., the header
1217 /// 'p cnf 0 0' is always legal. If the 'strict' argument is larger '1'
1218 /// strict formatting of the header is required, i.e., single spaces
1219 /// everywhere and no trailing white space.
1220 ///
1221 /// Returns zero if successful and otherwise an error message.
1222 ///
1223 /// require (VALID)
1224 /// ensure (VALID)
1225 ///
1226 #[inline]
1227 pub fn read_dimacs1(
1228 &mut self,
1229 file: String,
1230 name: String,
1231 vars: &mut i32,
1232 strict: i32,
1233 ) -> String {
1234 ffi::read_dimacs1(&mut self.solver, file, name, vars, strict)
1235 }
1236
1237 #[inline]
1238 pub fn read_dimacs2(&mut self, path: String, vars: &mut i32, strict: i32) -> String {
1239 ffi::read_dimacs2(&mut self.solver, path, vars, strict)
1240 }
1241
1242 /// The following routines work the same way but parse both DIMACS and
1243 /// INCCNF files (with 'p inccnf' header and 'a <cube>' lines). If the
1244 /// parser finds and 'p inccnf' header or cubes then '*incremental' is set
1245 /// to true and the cubes are stored in the given vector (each cube
1246 /// terminated by a zero).
1247 #[inline]
1248 pub fn read_dimacs3(
1249 &mut self,
1250 file: String,
1251 name: String,
1252 vars: &mut i32,
1253 strict: i32,
1254 incremental: &mut bool,
1255 cubes: &mut Vec<i32>,
1256 ) -> String {
1257 ffi::read_dimacs3(
1258 &mut self.solver,
1259 file,
1260 name,
1261 vars,
1262 strict,
1263 incremental,
1264 cubes,
1265 )
1266 }
1267
1268 #[inline]
1269 pub fn read_dimacs4(
1270 &mut self,
1271 path: String,
1272 vars: &mut i32,
1273 strict: i32,
1274 incremental: &mut bool,
1275 cubes: &mut Vec<i32>,
1276 ) -> String {
1277 ffi::read_dimacs4(&mut self.solver, path, vars, strict, incremental, cubes)
1278 }
1279
1280 //------------------------------------------------------------------------
1281 /// Write current irredundant clauses and all derived unit clauses
1282 /// to a file in DIMACS format. Clauses on the extension stack are
1283 /// not included, nor any redundant clauses.
1284 ///
1285 /// The '`min_max_var`' parameter gives a lower bound on the number '<vars>'
1286 /// of variables used in the DIMACS 'p cnf <vars> ...' header.
1287 ///
1288 /// Returns zero if successful and otherwise an error message.
1289 ///
1290 /// require (VALID)
1291 /// ensure (VALID)
1292 ///
1293 #[inline]
1294 pub fn write_dimacs(&mut self, path: String, min_max_var: i32) -> String {
1295 ffi::write_dimacs(&mut self.solver, path, min_max_var)
1296 }
1297
1298 /// The extension stack for reconstruction a solution can be written too.
1299 ///
1300 #[inline]
1301 pub fn write_extension(&mut self, path: String) -> String {
1302 ffi::write_extension(&mut self.solver, path)
1303 }
1304
1305 /// Print build configuration to a file with prefix 'c '. If the file
1306 /// is '<stdout>' or '<stderr>' then terminal color codes might be used.
1307 ///
1308 #[inline]
1309 pub fn build(file: String, prefix: String) {
1310 ffi::build(file, prefix);
1311 }
1312}
1313
1314/// Connected terminators are checked for termination regularly. If the
1315/// 'terminate' function of the terminator returns true the solver is
1316/// terminated synchronously as soon it calls this function.
1317pub trait Terminator {
1318 fn terminated(&mut self) -> bool;
1319}
1320
1321/// Connected learners which can be used to export learned clauses.
1322/// The 'learning' can check the size of the learn clause and only if it
1323/// returns true then the individual literals of the learned clause are given
1324/// to the learn through 'learn' one by one terminated by a zero literal.
1325pub trait Learner {
1326 fn learning(&mut self, size: i32) -> bool;
1327 fn learn(&mut self, lit: i32);
1328}
1329
1330/// Connected listener gets notified whenever the truth value of a variable is
1331/// fixed (for example during inprocessing or due to some derived unit clauses).
1332pub trait FixedAssignmentListener {
1333 fn notify_fixed_assignment(&mut self, lit: i32);
1334}
1335
1336use std::vec::Vec;
1337
1338/// Allows to connect an external propagator to propagate values to variables
1339/// with an external clause as a reason or to learn new clauses during the
1340/// CDCL loop (without restart).
1341pub trait ExternalPropagator {
1342 /// lazy propagator only checks complete assignments
1343 fn is_lazy(&self) -> bool {
1344 false
1345 }
1346
1347 /// Reason external clauses can be deleted
1348 fn are_reasons_forgettable(&self) -> bool {
1349 false
1350 }
1351
1352 /// Notify the propagator about assignments to observed variables.
1353 /// The notification is not necessarily eager. It usually happens before
1354 /// the call of propagator callbacks and when a driving clause is leading
1355 /// to an assignment.
1356 fn notify_assignment(&mut self, lits: &[i32]);
1357
1358 fn notify_new_decision_level(&mut self);
1359
1360 fn notify_backtrack(&mut self, new_level: usize);
1361
1362 /// Check by the external propagator the found complete solution (after
1363 /// solution reconstruction). If it returns false, the propagator must
1364 /// provide an external clause during the next callback.
1365 fn cb_check_found_model(&self, model: &[i32]) -> bool;
1366
1367 /// Ask the external propagator for the next decision literal. If it
1368 /// returns 0, the solver makes its own choice.
1369 fn cb_decide(&self) -> i32 {
1370 0
1371 }
1372
1373 /// Ask the external propagator if there is an external propagation to make
1374 /// under the current assignment. It returns either a literal to be
1375 /// propagated or 0, indicating that there is no external propagation under
1376 /// the current assignment.
1377 fn cb_propagate(&self) -> i32 {
1378 0
1379 }
1380
1381 /// Ask the external propagator for the reason clause of a previous
1382 /// external propagation step (done by `cb_propagate`). The clause must be
1383 /// added literal-by-literal closed with a 0. Further, the clause must
1384 /// contain the propagated literal.
1385 ///
1386 /// The clause will be learned as an Irredundant Non-Forgettable Clause (see
1387 /// below at '`cb_has_external_clause`' more details about it).
1388 fn cb_add_reason_clause_lit(&self, _propagated_lit: i32) -> i32 {
1389 0
1390 }
1391
1392 /// The following two functions are used to add external clauses to the
1393 /// solver during the CDCL loop. The external clause is added
1394 /// literal-by-literal and learned by the solver as an irredundant
1395 /// (original) input clause. The clause can be arbitrary, but if it is
1396 /// root-satisfied or tautology, the solver will ignore it without learning
1397 /// it. Root-falsified literals are eagerly removed from the clause.
1398 /// Falsified clauses trigger conflict analysis, propagating clauses
1399 /// trigger propagation. In case chrono is 0, the solver backtracks to
1400 /// propagate the new literal on the right decision level, otherwise it
1401 /// potentially will be an out-of-order assignment on the current level.
1402 /// Unit clauses always (unless root-satisfied, see above) trigger
1403 /// backtracking (independently from the value of the chrono option and
1404 /// independently from being falsified or satisfied or unassigned) to level
1405 /// 0. Empty clause (or root falsified clause, see above) makes the problem
1406 /// unsat and stops the search immediately. A literal 0 must close the
1407 /// clause.
1408 ///
1409 /// The external propagator indicates that there is a clause to add.
1410 /// The parameter of the function allows the user to indicate that how
1411 /// 'forgettable' is the external clause. Forgettable clauses are allowed
1412 /// to be removed by the SAT solver during clause database reduction.
1413 /// However, it is up to the solver to decide when actually the clause is
1414 /// deleted. For example, unit clauses, even forgettable ones, will not be
1415 /// deleted. In case the clause is not 'forgettable' (the parameter is false),
1416 /// the solver considers the clause to be irredundant.
1417 ///
1418 /// In case the solver produces incremental proofs, these external clauses
1419 /// are added to the proof during solving at real-time, i.e., the proof
1420 /// checker can ignore them until that point (so added as input clause, but
1421 /// input after the query line).
1422 ///
1423 /// Reason clauses of external propagation steps are assumed to be
1424 /// forgettable, parameter '`reason_forgettable`' can be used to change it.
1425 ///
1426 /// Currently, every external clause is expected to be over observed
1427 /// (therefore frozen) variables, hence no tainting or restore steps
1428 /// are performed upon their addition. This will be changed in later
1429 /// versions probably.
1430 fn cb_has_external_clause(&self, is_forgettable: &mut bool) -> bool;
1431
1432 /// The actual function called to add the external clause.
1433 fn cb_add_external_clause_lit(&self) -> i32;
1434}
1435
1436/// Allows to traverse all remaining irredundant clauses. Satisfied and
1437/// eliminated clauses are not included, nor any derived units unless such
1438/// a unit literal is frozen. Falsified literals are skipped. If the solver
1439/// is inconsistent only the empty clause is traversed.
1440///
1441/// If 'clause' returns false traversal aborts early.
1442pub trait ClauseIterator {
1443 fn clause(&mut self, clause: &[i32]) -> bool;
1444}
1445
1446/// Allows to traverse all clauses on the extension stack together with their
1447/// witness cubes. If the solver is inconsistent, i.e., an empty clause is
1448/// found and the formula is unsatisfiable, then nothing is traversed.
1449///
1450/// The clauses traversed in '`traverse_clauses`' together with the clauses on
1451/// the extension stack are logically equivalent to the original clauses.
1452/// See our SAT'19 paper for more details.
1453///
1454/// The witness literals can be used to extend and fix an assignment on the
1455/// remaining clauses to satisfy the clauses on the extension stack too.
1456///
1457/// All derived units of non-frozen variables are included too.
1458///
1459/// If 'witness' returns false traversal aborts early.
1460pub trait WitnessIterator {
1461 fn witness(&mut self, clause: &[i32], witness: &[i32], id: u64) -> bool;
1462}