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}