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    last_external_propagator: Option<UniquePtr<ffi::ExternalPropagator>>,
264    last_fixed_listener: Option<UniquePtr<ffi::FixedAssignmentListener>>,
265    last_tracer: Option<UniquePtr<ffi::Tracer>>,
266}
267
268impl Clone for CaDiCal {
269    fn clone(&self) -> Self {
270        let mut r = Self::new();
271        Self::copy(self, &mut r);
272        r
273    }
274}
275
276impl Default for CaDiCal {
277    fn default() -> Self {
278        Self::new()
279    }
280}
281
282impl CaDiCal {
283    #[must_use]
284    #[inline]
285    pub fn new() -> Self {
286        Self {
287            solver: ffi::constructor(),
288            last_terminator: None,
289            last_learner: None,
290            last_external_propagator: None,
291            last_fixed_listener: None,
292            last_tracer: None,
293        }
294    }
295
296    /// Core functionality as in the IPASIR incremental SAT solver interface.
297    /// (recall 'READY = CONFIGURING | STEADY  | SATISFIED | UNSATISFIED').
298    /// Further note that 'lit' is required to be different from '`INT_MIN`' and
299    /// different from '0' except for 'add'.
300    ///
301    /// Add valid literal to clause or zero to terminate clause.
302    ///
303    ///   require (VALID)                   recall 'VALID = READY | ADDING'
304    ///
305    ///   if (lit) ensure (ADDING)          and thus VALID but not READY
306    ///
307    ///   if (!lit) ensure (STEADY )        and thus READY
308    ///
309    #[inline]
310    pub fn add(&mut self, lit: i32) {
311        ffi::add(&mut self.solver, lit);
312    }
313
314    /// Here are functions simplifying clause addition. The given literals
315    /// should all be valid (different from '`INT_MIN`' and different from '0').
316    ///
317    ///   require (VALID)
318    ///   ensure (STEADY )
319    ///
320    #[inline]
321    pub fn clause1(&mut self, l1: i32) {
322        ffi::clause1(&mut self.solver, l1);
323    }
324
325    #[inline]
326    pub fn clause2(&mut self, l1: i32, l2: i32) {
327        ffi::clause2(&mut self.solver, l1, l2);
328    }
329
330    #[inline]
331    pub fn clause3(&mut self, l1: i32, l2: i32, l3: i32) {
332        ffi::clause3(&mut self.solver, l1, l2, l3);
333    }
334
335    #[inline]
336    pub fn clause4(&mut self, l1: i32, l2: i32, l3: i32, l4: i32) {
337        ffi::clause4(&mut self.solver, l1, l2, l3, l4);
338    }
339
340    #[inline]
341    pub fn clause5(&mut self, l1: i32, l2: i32, l3: i32, l4: i32, l5: i32) {
342        ffi::clause5(&mut self.solver, l1, l2, l3, l4, l5);
343    }
344
345    #[inline]
346    pub fn clause6(&mut self, v: &[i32]) {
347        ffi::clause6(&mut self.solver, v);
348    }
349
350    /// This function can be used to check if the formula is already
351    /// inconsistent (contains the empty clause or was proven to be
352    /// root-level unsatisfiable).
353    #[inline]
354    pub fn inconsistent(&mut self) -> bool {
355        ffi::inconsistent(&mut self.solver)
356    }
357
358    /// Assume valid non zero literal for next call to 'solve'.  These
359    /// assumptions are reset after the call to 'solve' as well as after
360    /// returning from 'simplify' and 'lookahead.
361    ///
362    ///   require (READY)
363    ///   ensure (STEADY )
364    ///
365    #[inline]
366    pub fn assume(&mut self, lit: i32) {
367        ffi::assume(&mut self.solver, lit);
368    }
369
370    /// Try to solve the current formula.  Returns
371    ///
372    ///    0 = UNKNOWN      (limit reached or interrupted through 'terminate')
373    ///   10 = SATISFIABLE
374    ///   20 = UNSATISFIABLE
375    ///
376    ///   require (READY)
377    ///   ensure (STEADY  | SATISFIED | UNSATISFIED)
378    ///
379    /// Note, that while in this call the solver actually transitions to state
380    /// 'SOLVING', which however is only visible from a different context,
381    /// i.e., from a different thread or from a signal handler.  Only right
382    /// before returning from this call it goes into a 'READY' state.
383    ///
384    #[inline]
385    pub fn solve(&mut self) -> Status {
386        ffi::solve(&mut self.solver).into()
387    }
388
389    /// Get value (-lit=false, lit=true) of valid non-zero literal.
390    ///
391    ///   require (SATISFIED)
392    ///   ensure (SATISFIED)
393    ///
394    #[inline]
395    pub fn val(&mut self, lit: i32) -> i32 {
396        ffi::val(&mut self.solver, lit)
397    }
398
399    /// Try to flip the value of the given literal without falsifying the
400    /// formula.  Returns 'true' if this was successful. Otherwise the model is
401    /// not changed and 'false' is returned.  If a literal was eliminated or
402    /// substituted flipping will fail on that literal and in particular the
403    /// solver will not taint it nor restore any clauses.
404    ///
405    /// The 'flip' function can only flip the value of a variables not acting
406    /// as witness on the reconstruction stack.
407    ///
408    /// As a side effect of calling this function first all assigned variables
409    /// are propagated again without using blocking literal.  Thus the first
410    /// call to this function after obtaining a model adds a substantial
411    /// overhead.  Subsequent calls will not need to properly propagate again.
412    ///
413    /// Furthermore if the reconstruction stack is non-empty and has been
414    /// traversed to reconstruct a full extended model for eliminated
415    /// variables (and to satisfy removed blocked clauses), the values of these
416    /// witness variables obtained via 'val' before become invalid. The user
417    /// thus will need to call 'val' again after calling 'flip' which will
418    /// trigger then a traversal of the reconstruction stack.
419    ///
420    /// So try to avoid mixing 'flip' and 'val' (for efficiency only).
421    /// Further, this functionality is currently not supported in the presence
422    /// of an external propagator.
423    ///
424    ///   require (SATISFIED)
425    ///   ensure (SATISFIED)
426    ///
427    #[inline]
428    pub fn flip(&mut self, lit: i32) -> bool {
429        ffi::flip(&mut self.solver, lit)
430    }
431
432    /// Same as 'flip' without actually flipping it. This functionality is
433    /// currently not supported in the presence of an external propagator.
434    ///
435    ///   require (SATISFIED)
436    ///   ensure (SATISFIED)
437    ///
438    #[inline]
439    pub fn flippable(&mut self, lit: i32) -> bool {
440        ffi::flippable(&mut self.solver, lit)
441    }
442
443    /// Determine whether the valid non-zero literal is in the core.
444    /// Returns 'true' if the literal is in the core and 'false' otherwise.
445    /// Note that the core does not have to be minimal.
446    ///
447    ///   require (UNSATISFIED)
448    ///   ensure (UNSATISFIED)
449    ///
450    #[inline]
451    pub fn failed(&mut self, lit: i32) -> bool {
452        ffi::failed(&mut self.solver, lit)
453    }
454
455    /// Add call-back which is checked regularly for termination.  There can
456    /// only be one terminator connected.  If a second (non-zero) one is added
457    /// the first one is implicitly disconnected.
458    ///
459    ///   require (VALID)
460    ///   ensure (VALID)
461    ///
462    #[inline]
463    #[allow(clippy::missing_panics_doc)]
464    pub fn connect_terminator<'a, 'b: 'a, T: Terminator>(&'a mut self, terminator: &'b mut T) {
465        fn f<T: Terminator>(state: *mut u8) -> bool {
466            let ptr: *mut T = state.cast::<T>();
467            let i = unsafe { &mut *ptr };
468            i.terminated()
469        }
470        let terminator =
471            unsafe { ffi::new_terminator(std::ptr::from_mut(terminator).cast::<u8>(), f::<T>) };
472        self.last_terminator = Some(terminator);
473        ffi::connect_terminator(&mut self.solver, self.last_terminator.as_mut().unwrap());
474    }
475
476    #[inline]
477    pub fn disconnect_terminator(&mut self) {
478        ffi::disconnect_terminator(&mut self.solver);
479        self.last_terminator = None;
480    }
481
482    /// Add call-back which allows to export learned clauses.
483    ///
484    ///   require (VALID)
485    ///   ensure (VALID)
486    ///
487    #[inline]
488    #[allow(clippy::missing_panics_doc)]
489    pub fn connect_learner<'a, 'b: 'a, T: Learner>(&'a mut self, learner: &'b mut T) {
490        fn learning<T: Learner>(state: *mut u8, size: i32) -> bool {
491            let ptr: *mut T = state.cast::<T>();
492            let i = unsafe { &mut *ptr };
493            i.learning(size)
494        }
495
496        fn learn<T: Learner>(state: *mut u8, lit: i32) {
497            let ptr: *mut T = state.cast::<T>();
498            let i = unsafe { &mut *ptr };
499            i.learn(lit);
500        }
501
502        let learner = unsafe {
503            ffi::new_learner(
504                std::ptr::from_mut(learner).cast::<u8>(),
505                learning::<T>,
506                learn::<T>,
507            )
508        };
509        self.last_learner = Some(learner);
510        ffi::connect_learner(&mut self.solver, self.last_learner.as_mut().unwrap());
511    }
512
513    #[inline]
514    pub fn disconnect_learner(&mut self) {
515        ffi::disconnect_learner(&mut self.solver);
516        self.last_learner = None;
517    }
518
519    /// Add call-back which allows to observe when a variable is fixed.
520    ///
521    ///   require (VALID)
522    ///   ensure (VALID)
523    ///
524    #[allow(clippy::missing_panics_doc)]
525    pub fn connect_fixed_listener<'a, 'b: 'a, F: FixedAssignmentListener>(
526        &'a mut self,
527        fixed_listener: &'b mut F,
528    ) {
529        fn notify_fixed_assignment<F: FixedAssignmentListener>(state: *mut u8, lit: i32) {
530            let ptr: *mut F = state.cast::<F>();
531            let i = unsafe { &mut *ptr };
532            i.notify_fixed_assignment(lit);
533        }
534
535        let s = std::ptr::from_mut(fixed_listener).cast::<u8>();
536
537        let listener =
538            unsafe { ffi::new_fixed_assignment_listener(s, notify_fixed_assignment::<F>) };
539
540        // Store the listener in self to prevent it from being dropped
541        self.last_fixed_listener = Some(listener);
542
543        // Use the stored listener
544        ffi::connect_fixed_listener(&mut self.solver, self.last_fixed_listener.as_mut().unwrap());
545    }
546
547    #[inline]
548    pub fn disconnect_fixed_listener(&mut self) {
549        ffi::disconnect_fixed_listener(&mut self.solver);
550        self.last_fixed_listener = None;
551    }
552
553    /// Add call-back which allows to learn, propagate and backtrack based on
554    /// external constraints. Only one external propagator can be connected
555    /// and after connection every related variables must be 'observed' (use
556    /// '`add_observed_var`' function).
557    /// Disconnection of the external propagator resets all the observed
558    /// variables.
559    ///
560    ///   require (VALID)
561    ///   ensure (VALID)
562    ///
563    #[allow(clippy::missing_panics_doc)]
564    pub fn connect_external_propagator<'a, 'b: 'a, T: ExternalPropagator>(
565        &'a mut self,
566        propagator: &'b mut T,
567    ) {
568        fn notify_assignment<T: ExternalPropagator>(state: *mut u8, x: &[i32]) {
569            let ptr: *mut T = state.cast::<T>();
570            let i = unsafe { &mut *ptr };
571            i.notify_assignment(x);
572        }
573        fn notify_new_decision_level<T: ExternalPropagator>(state: *mut u8) {
574            let ptr: *mut T = state.cast::<T>();
575            let i = unsafe { &mut *ptr };
576            i.notify_new_decision_level();
577        }
578        fn notify_backtrack<T: ExternalPropagator>(state: *mut u8, x: usize) {
579            let ptr: *mut T = state.cast::<T>();
580            let i = unsafe { &mut *ptr };
581            i.notify_backtrack(x);
582        }
583        fn cb_check_found_model<T: ExternalPropagator>(state: *mut u8, x: &[i32]) -> bool {
584            let ptr: *mut T = state.cast::<T>();
585            let i = unsafe { &mut *ptr };
586            i.cb_check_found_model(x)
587        }
588        fn cb_decide<T: ExternalPropagator>(state: *mut u8) -> i32 {
589            let ptr: *mut T = state.cast::<T>();
590            let i = unsafe { &mut *ptr };
591            i.cb_decide()
592        }
593        fn cb_propagate<T: ExternalPropagator>(state: *mut u8) -> i32 {
594            let ptr: *mut T = state.cast::<T>();
595            let i = unsafe { &mut *ptr };
596            i.cb_propagate()
597        }
598        fn cb_add_reason_clause_lit<T: ExternalPropagator>(state: *mut u8, x: i32) -> i32 {
599            let ptr: *mut T = state.cast::<T>();
600            let i = unsafe { &mut *ptr };
601            i.cb_add_reason_clause_lit(x)
602        }
603        fn cb_has_external_clause<T: ExternalPropagator>(state: *mut u8, x: *mut bool) -> bool {
604            let ptr: *mut T = state.cast::<T>();
605            let i = unsafe { &mut *ptr };
606            i.cb_has_external_clause(unsafe { &mut *x })
607        }
608        fn cb_add_external_clause_lit<T: ExternalPropagator>(state: *mut u8) -> i32 {
609            let ptr: *mut T = state.cast::<T>();
610            let i = unsafe { &mut *ptr };
611            i.cb_add_external_clause_lit()
612        }
613        let is_lazy = propagator.is_lazy();
614        let are_reasons_forgettable = propagator.are_reasons_forgettable();
615
616        let external_propagator = unsafe {
617            ffi::new_external_propagator(
618                std::ptr::from_mut(propagator).cast::<u8>(),
619                is_lazy,
620                are_reasons_forgettable,
621                notify_assignment::<T>,
622                notify_new_decision_level::<T>,
623                notify_backtrack::<T>,
624                cb_check_found_model::<T>,
625                cb_decide::<T>,
626                cb_propagate::<T>,
627                cb_add_reason_clause_lit::<T>,
628                cb_has_external_clause::<T>,
629                cb_add_external_clause_lit::<T>,
630            )
631        };
632
633        self.last_external_propagator = Some(external_propagator);
634        ffi::connect_external_propagator(
635            &mut self.solver,
636            self.last_external_propagator.as_mut().unwrap(),
637        );
638    }
639    pub fn disconnect_external_propagator(&mut self) {
640        ffi::disconnect_external_propagator(&mut self.solver);
641        self.last_external_propagator = None;
642    }
643
644    /// Mark as 'observed' those variables that are relevant to the external
645    /// propagator. External propagation, clause addition during search and
646    /// notifications are all over these observed variabes.
647    /// A variable can not be observed witouth having an external propagator
648    /// connected. Observed variables are "frozen" internally, and so
649    /// inprocessing will not consider them as candidates for elimination.
650    /// An observed variable is allowed to be a fresh variable and it can be
651    /// added also during solving.
652    ///
653    ///   require (`VALID_OR_SOLVING`)
654    ///   ensure (`VALID_OR_SOLVING`)
655    ///
656    #[inline]
657    pub fn add_observed_var(&mut self, var: i32) {
658        ffi::add_observed_var(&mut self.solver, var);
659    }
660
661    /// Removes the 'observed' flag from the given variable. A variable can be
662    /// set unobserved only between solve calls, not during it (to guarantee
663    /// that no yet unexplained external propagation involves it).
664    ///
665    ///   require (VALID)
666    ///   ensure (VALID)
667    ///
668    #[inline]
669    pub fn remove_observed_var(&mut self, var: i32) {
670        ffi::remove_observed_var(&mut self.solver, var);
671    }
672
673    /// Removes all the 'observed' flags from the variables. Disconnecting the
674    /// propagator invokes this step as well.
675    ///
676    ///   require (VALID)
677    ///   ensure (VALID)
678    ///
679    #[inline]
680    pub fn reset_observed_vars(&mut self) {
681        ffi::reset_observed_vars(&mut self.solver);
682    }
683
684    /// Get reason of valid observed literal (true = it is an observed variable
685    /// and it got assigned by a decision during the CDCL loop. Otherwise:
686    /// false.
687    ///
688    ///   require (`VALID_OR_SOLVING`)
689    ///   ensure (`VALID_OR_SOLVING`)
690    ///
691    #[inline]
692    pub fn is_decision(&mut self, lit: i32) -> bool {
693        ffi::is_decision(&mut self.solver, lit)
694    }
695
696    /// Force solve to backtrack to certain decision level. Can be called only
697    /// during '`cb_decide`' of a connected External Propagator.
698    /// Invoking in any other time will not have an effect.
699    /// If the call had an effect, the External Propagator will be notified about
700    /// the backtrack via '`notify_backtrack`'.
701    ///
702    ///   require (SOLVING)
703    ///   ensure (SOLVING)
704    ///
705    #[inline]
706    pub fn force_backtrack(&mut self, new_level: usize) {
707        ffi::force_backtrack(&mut self.solver, new_level);
708    }
709
710    //------------------------------------------------------------------------
711    /// Adds a literal to the constraint clause. Same functionality as 'add'
712    /// but the clause only exists for the next call to solve (same lifetime as
713    /// assumptions). Only one constraint may exists at a time. A new
714    /// constraint replaces the old. The main application of this functonality
715    /// is the model checking algorithm IC3. See our FMCAD'21 paper
716    /// [FroleyksBiere-FMCAD'19] for more details.
717    ///
718    /// Add valid literal to the constraint clause or zero to terminate it.
719    ///
720    ///   require (VALID)                     /// recall 'VALID = READY |
721    ///   ADDING' if (lit) ensure (ADDING)            /// and thus VALID but not
722    ///   READY if (!lit) && !`adding_clause` ensure (STEADY ) // and thus READY
723    ///
724    #[inline]
725    pub fn constrain(&mut self, lit: i32) {
726        ffi::constrain(&mut self.solver, lit);
727    }
728
729    /// Determine whether the constraint was used to proof the
730    /// unsatisfiability. Note that the formula might still be unsatisfiable
731    /// without the constraint.
732    ///
733    ///   require (UNSATISFIED)
734    ///   ensure (UNSATISFIED)
735    ///
736    #[inline]
737    pub fn constraint_failed(&mut self) -> bool {
738        ffi::constraint_failed(&mut self.solver)
739    }
740
741    //------------------------------------------------------------------------
742    /// This function determines a good splitting literal.  The result can be
743    /// zero if the formula is proven to be satisfiable or unsatisfiable.  This
744    /// can then be checked by 'state ()'.  If the formula is empty and
745    /// the function is not able to determine satisfiability also zero is
746    /// returned but the state remains steady.
747    ///
748    ///   require (READY)
749    ///   ensure (STEADY |SATISFIED|UNSATISFIED)
750    ///
751    #[inline]
752    pub fn lookahead(&mut self) -> i32 {
753        ffi::lookahead(&mut self.solver)
754    }
755
756    #[inline]
757    pub fn generate_cubes(&mut self, x: i32, min_depth: i32, result_cubes: &mut Vec<i32>) -> i32 {
758        ffi::generate_cubes(&mut self.solver, x, min_depth, result_cubes)
759    }
760
761    #[inline]
762    pub fn reset_assumptions(&mut self) {
763        ffi::reset_assumptions(&mut self.solver);
764    }
765
766    #[inline]
767    pub fn reset_constraint(&mut self) {
768        ffi::reset_constraint(&mut self.solver);
769    }
770
771    /// Return the current state of the solver as defined above.
772    ///
773    #[must_use]
774    #[inline]
775    pub fn state(&self) -> State {
776        ffi::state(&self.solver).into()
777    }
778
779    /// Similar to 'state ()' but using the staddard competition exit codes of
780    /// '10' for 'SATISFIABLE', '20' for 'UNSATISFIABLE' and '0' otherwise.
781    ///
782    #[must_use]
783    #[inline]
784    pub fn status(&self) -> Status {
785        ffi::status(&self.solver).into()
786    }
787
788    /// return version string
789    #[must_use]
790    #[inline]
791    pub fn version() -> String {
792        ffi::version()
793    }
794
795    /*----------------------------------------------------------------------*/
796    /// Copy 'this' into a fresh 'other'.  The copy procedure is not a deep
797    /// clone, but only copies irredundant clauses and units.  It also makes
798    /// sure that witness reconstruction works with the copy as with the
799    /// original formula such that both solvers have the same models.
800    /// Assumptions are not copied.  Options however are copied as well as
801    /// flags which remember the current state of variables in preprocessing.
802    ///
803    ///   require (READY)          /// for 'this'
804    ///   ensure (READY)           /// for 'this'
805    ///
806    ///   other.require (CONFIGURING)
807    ///   other.ensure (CONFIGURING | STEADY )
808    ///
809    #[inline]
810    pub fn copy(source: &CaDiCal, destination: &mut CaDiCal) {
811        ffi::copy(&source.solver, &mut destination.solver);
812    }
813
814    /*----------------------------------------------------------------------*/
815    /// Variables are usually added and initialized implicitly whenever a
816    /// literal is used as an argument except for the functions 'val', 'fixed',
817    /// 'failed' and 'frozen'.  However, the library internally keeps a maximum
818    /// variable index, which can be queried.
819    ///
820    ///   require (VALID | SOLVING)
821    ///   ensure (VALID | SOLVING)
822    ///
823    #[inline]
824    pub fn vars(&mut self) -> i32 {
825        ffi::vars(&mut self.solver)
826    }
827
828    /// Increase the maximum variable index explicitly.  This function makes
829    /// sure that at least '`min_max_var`' variables are initialized.  Since it
830    /// might need to reallocate tables, it destroys a satisfying assignment
831    /// and has the same state transition and conditions as 'assume' etc.
832    ///
833    ///   require (READY)
834    ///   ensure (STEADY )
835    ///
836    #[inline]
837    pub fn reserve(&mut self, min_max_var: i32) {
838        ffi::reserve(&mut self.solver, min_max_var);
839    }
840
841    // pub fn `trace_api_calls(&mut` self, file: String);
842
843    //------------------------------------------------------------------------
844    /// Option handling.
845    /// Determine whether 'name' is a valid option name.
846    ///
847    #[must_use]
848    #[inline]
849    pub fn is_valid_option(name: String) -> bool {
850        ffi::is_valid_option(name)
851    }
852
853    /// Determine whether 'name' enables a specific preprocessing technique.
854    ///
855    #[must_use]
856    #[inline]
857    pub fn is_preprocessing_option(name: String) -> bool {
858        ffi::is_preprocessing_option(name)
859    }
860
861    /// Determine whether 'arg' is a valid long option of the form '--<name>',
862    /// '--<name>=<val>' or '--no-<name>' similar to '`set_long_option`' below.
863    /// Legal values are 'true', 'false', or '[-]<mantissa>[e<exponent>]'.
864    #[must_use]
865    #[inline]
866    pub fn is_valid_long_option(arg: String) -> bool {
867        ffi::is_valid_long_option(arg)
868    }
869
870    /// Get the current value of the option 'name'.  If 'name' is invalid then
871    /// zero is returned.  Here '--...' arguments as invalid options.
872    ///
873    #[inline]
874    pub fn get(&mut self, name: String) -> i32 {
875        ffi::get(&mut self.solver, name)
876    }
877
878    /// Set the default verbose message prefix (default "c ").
879    ///
880    #[inline]
881    pub fn prefix(&mut self, verbose_message_prefix: String) {
882        ffi::prefix(&mut self.solver, verbose_message_prefix);
883    }
884
885    /// Explicit version of setting an option.  If the option '<name>' exists
886    /// and '<val>' can be parsed then 'true' is returned.  If the option value
887    /// is out of range the actual value is computed as the closest (minimum or
888    /// maximum) value possible, but still 'true' is returned.
889    ///
890    ///   require (CONFIGURING)
891    ///   ensure (CONFIGURING)
892    ///
893    /// Thus options can only bet set right after initialization.
894    ///
895    #[inline]
896    pub fn set(&mut self, name: String, val: i32) -> bool {
897        ffi::set(&mut self.solver, name, val)
898    }
899
900    /// This function accepts options in command line syntax:
901    ///
902    ///   '--<name>=<val>', '--<name>', or '--no-<name>'
903    ///
904    /// It actually calls the previous 'set' function after parsing 'arg'.  The
905    /// same values are expected as for '`is_valid_long_option`' above and as
906    /// with 'set' any value outside of the range of legal values for a
907    /// particular option are set to either the minimum or maximum depending on
908    /// which side of the valid interval they lie.
909    ///
910    ///   require (CONFIGURING)
911    ///   ensure (CONFIGURING)
912    ///
913    #[inline]
914    pub fn set_long_option(&mut self, arg: String) -> bool {
915        ffi::set_long_option(&mut self.solver, arg)
916    }
917
918    /// Determine whether 'name' is a valid configuration.
919    ///
920    #[must_use]
921    #[inline]
922    pub fn is_valid_configuration(name: String) -> bool {
923        ffi::is_valid_configuration(name)
924    }
925
926    /// Overwrite (some) options with the forced values of the configuration.
927    /// The result is 'true' iff the 'name' is a valid configuration.
928    ///
929    ///   require (CONFIGURING)
930    ///   ensure (CONFIGURING)
931    ///
932    #[inline]
933    pub fn configure(&mut self, name: String) -> bool {
934        ffi::configure(&mut self.solver, name)
935    }
936
937    /// Increase preprocessing and inprocessing limits by '10^<val>'.  Values
938    /// below '0' are ignored and values above '9' are reduced to '9'.
939    ///
940    ///   require (READY)
941    ///   ensure (READY)
942    ///
943    #[inline]
944    pub fn optimize(&mut self, val: i32) {
945        ffi::optimize(&mut self.solver, val);
946    }
947
948    /// Specify search limits, where currently 'name' can be "conflicts",
949    /// "decisions", "preprocessing", or "localsearch".  The first two limits
950    /// are unbounded by default.  Thus using a negative limit for conflicts or
951    /// decisions switches back to the default of unlimited search (for that
952    /// particular limit).  The preprocessing limit determines the number of
953    /// preprocessing rounds, which is zero by default.  Similarly, the local
954    /// search limit determines the number of local search rounds (also zero by
955    /// default).  As with 'set', the return value denotes whether the limit
956    /// 'name' is valid.  These limits are only valid for the next 'solve' or
957    /// 'simplify' call and reset to their default after 'solve' returns (as
958    /// well as overwritten and reset during calls to 'simplify' and
959    /// 'lookahead').  We actually also have an internal "terminate" limit
960    /// which however should only be used for testing and debugging.
961    ///
962    ///   require (READY)
963    ///   ensure (READY)
964    ///
965    #[inline]
966    pub fn limit(&mut self, arg: String, val: i32) -> bool {
967        ffi::limit(&mut self.solver, arg, val)
968    }
969    #[inline]
970    pub fn is_valid_limit(&mut self, arg: String) -> bool {
971        ffi::is_valid_limit(&mut self.solver, arg)
972    }
973
974    /// The number of currently active variables and clauses can be queried by
975    /// these functions.  Variables become active if a clause is added with it.
976    /// They become inactive if they are eliminated or fixed at the root level
977    /// Clauses become inactive if they are satisfied, subsumed, eliminated.
978    /// Redundant clauses are reduced regularly and thus the 'redundant'
979    /// function is less useful.
980    ///
981    ///   require (VALID)
982    ///   ensure (VALID)
983    ///
984    /// Number of active variables.
985    #[must_use]
986    #[inline]
987    pub fn active(&self) -> i32 {
988        ffi::active(&self.solver)
989    }
990
991    /// Number of active redundant clauses.
992    #[must_use]
993    #[inline]
994    pub fn redundant(&self) -> i64 {
995        ffi::redundant(&self.solver)
996    }
997
998    /// Number of active irredundant clauses.
999    #[must_use]
1000    #[inline]
1001    pub fn irredundant(&self) -> i64 {
1002        ffi::irredundant(&self.solver)
1003    }
1004
1005    //------------------------------------------------------------------------
1006    /// This function executes the given number of preprocessing rounds. It is
1007    /// similar to 'solve' with 'limits ("preprocessing", rounds)' except that
1008    /// no CDCL nor local search, nor lucky phases are executed.  The result
1009    /// values are also the same: 0=UNKNOWN, 10=SATISFIABLE, 20=UNSATISFIABLE.
1010    /// As 'solve' it resets current assumptions and limits before returning.
1011    /// The numbers of rounds should not be negative.  If the number of rounds
1012    /// is zero only clauses are restored (if necessary) and top level unit
1013    /// propagation is performed, which both take some time.
1014    ///
1015    ///   require (READY)
1016    ///   ensure (STEADY  | SATISFIED | UNSATISFIED)
1017    ///
1018    #[inline]
1019    pub fn simplify(&mut self, rounds: i32) -> Status {
1020        ffi::simplify(&mut self.solver, rounds).into()
1021    }
1022
1023    //------------------------------------------------------------------------
1024    /// Force termination of 'solve' asynchronously.
1025    ///
1026    ///  require (SOLVING | READY)
1027    ///  ensure (STEADY )           /// actually not immediately (synchronously)
1028    ///
1029    #[inline]
1030    pub fn terminate(&mut self) {
1031        ffi::terminate(&mut self.solver);
1032    }
1033
1034    //------------------------------------------------------------------------
1035
1036    /// We have the following common reference counting functions, which avoid
1037    /// to restore clauses but require substantial user guidance.  This was the
1038    /// only way to use inprocessing in incremental SAT solving in Lingeling
1039    /// (and before in `MiniSAT`'s 'freeze' / 'thaw') and which did not use
1040    /// automatic clause restoring.  In general this is slower than
1041    /// restoring clauses and should not be used.
1042    ///
1043    /// In essence the user freezes variables which potentially are still
1044    /// needed in clauses added or assumptions used after the next 'solve'
1045    /// call.  As in Lingeling you can freeze a variable multiple times, but
1046    /// then have to melt it the same number of times again in order to enable
1047    /// variable eliminating on it etc.  The arguments can be literals
1048    /// (negative indices) but conceptually variables are frozen.
1049    ///
1050    /// In the old way of doing things without restore you should not use a
1051    /// variable incrementally (in 'add' or 'assume'), which was used before
1052    /// and potentially could have been eliminated in a previous 'solve' call.
1053    /// This can lead to spurious satisfying assignment.  In order to check
1054    /// this API contract one can use the 'checkfrozen' option.  This has the
1055    /// drawback that restoring clauses implicitly would fail with a fatal
1056    /// error message even if in principle the solver could just restore
1057    /// clauses. Thus this option is disabled by default.
1058    ///
1059    /// See our SAT'19 paper [FazekasBiereScholl-SAT'19] for more details.
1060    ///
1061    ///   require (VALID)
1062    ///   ensure (VALID)
1063    ///
1064    #[must_use]
1065    #[inline]
1066    pub fn frozen(&self, lit: i32) -> bool {
1067        ffi::frozen(&self.solver, lit)
1068    }
1069
1070    #[inline]
1071    pub fn freeze(&mut self, lit: i32) {
1072        ffi::freeze(&mut self.solver, lit);
1073    }
1074
1075    #[inline]
1076    pub fn melt(&mut self, lit: i32) {
1077        ffi::melt(&mut self.solver, lit);
1078    }
1079
1080    //------------------------------------------------------------------------
1081    /// Root level assigned variables can be queried with this function.
1082    /// It returns '1' if the literal is implied by the formula, '-1' if its
1083    /// negation is implied, or '0' if this is unclear at this point.
1084    ///
1085    ///   require (VALID)
1086    ///   ensure (VALID)
1087    ///
1088    #[must_use]
1089    #[inline]
1090    pub fn fixed(&self, lit: i32) -> i32 {
1091        ffi::fixed(&self.solver, lit)
1092    }
1093
1094    //------------------------------------------------------------------------
1095    /// Force the default decision phase of a variable to a certain value.
1096    ///
1097    #[inline]
1098    pub fn phase(&mut self, lit: i32) {
1099        ffi::phase(&mut self.solver, lit);
1100    }
1101
1102    #[inline]
1103    pub fn unphase(&mut self, lit: i32) {
1104        ffi::unphase(&mut self.solver, lit);
1105    }
1106
1107    //------------------------------------------------------------------------
1108    /// Enables clausal proof tracing in DRAT format and returns 'true' if
1109    /// successfully opened for writing.  Writing proofs has to be enabled
1110    /// before calling 'solve', 'add' and 'dimacs', that is in state
1111    /// 'CONFIGURING'.  Otherwise only partial proofs would be written.
1112    ///
1113    ///   require (CONFIGURING)
1114    ///   ensure (CONFIGURING)
1115    ///
1116    /// Write DRAT proof.
1117    #[inline]
1118    pub fn trace_proof1(&mut self, file: String, name: String) -> bool {
1119        ffi::trace_proof1(&mut self.solver, file, name)
1120    }
1121
1122    /// Open & write proof.
1123    #[inline]
1124    pub fn trace_proof2(&mut self, path: String) -> bool {
1125        ffi::trace_proof2(&mut self.solver, path)
1126    }
1127
1128    /// Flushing the proof trace file eventually calls 'fflush' on the actual
1129    /// file or pipe and thus if this function returns all the proof steps
1130    /// should have been written (with the same guarantees as 'fflush').
1131    ///
1132    /// The additional optional argument forces to print the number of addition
1133    /// and deletion steps in the proof even if the verbosity level is zero but
1134    /// not if quiet is set as well.  The default for the stand-alone solver is
1135    /// to print this information (in the 'closing proof' section) but for API
1136    /// usage of the library we want to stay silent unless explicitly requested
1137    /// or verbosity is non-zero (and as explained quiet is not set).
1138    ///
1139    /// This function can be called multiple times.
1140    ///
1141    ///   require (VALID)
1142    ///   ensure (VALID)
1143    ///
1144    #[inline]
1145    pub fn flush_proof_trace(&mut self, print: bool) {
1146        ffi::flush_proof_trace(&mut self.solver, print);
1147    }
1148
1149    /// Close proof trace early.  Similar to 'flush' we allow the user to
1150    /// control with 'print' in a more fine-grained way whether statistics
1151    /// about the size of the written proof file and if compressed on-the-fly
1152    /// the number of actual bytes written (including deflation percentage) are
1153    /// printed.  Before actually closing (or detaching in case of writing to
1154    /// '<stdout>') we check whether '`flush_proof_trace`' was called since the
1155    /// last time a proof step (addition or deletion) was traced.  If this is
1156    /// not the case we would call '`flush_proof_trace`' with the same 'print'
1157    /// argument.
1158    ///
1159    ///   require (VALID)
1160    ///   ensure (VALID)
1161    ///
1162    #[inline]
1163    pub fn close_proof_trace(&mut self, print: bool) {
1164        ffi::close_proof_trace(&mut self.solver, print);
1165    }
1166
1167    // /// Enables clausal proof tracing with or without antecedents using
1168    // /// the Tracer interface defined in 'tracer.hpp'
1169    // ///
1170    // /// InternalTracer, StatTracer and FileTracer for internal use
1171    // ///
1172    // ///   require (CONFIGURING)
1173    // ///   ensure (CONFIGURING)
1174    // ///
1175    #[allow(clippy::missing_panics_doc)]
1176    #[allow(clippy::too_many_lines)]
1177    pub fn connect_proof_tracer1<'a, 'b: 'a, T: ProofTracer>(
1178        &'a mut self,
1179        tracer: &'b mut T,
1180        antecedents: bool,
1181    ) {
1182        fn add_original_clause<T: ProofTracer>(
1183            state: *mut u8,
1184            id: u64,
1185            redundant: bool,
1186            clause: &[i32],
1187            restored: bool,
1188        ) {
1189            let ptr: *mut T = state.cast::<T>();
1190            let t = unsafe { &mut *ptr };
1191            t.add_original_clause(id, redundant, clause, restored);
1192        }
1193
1194        fn add_derived_clause<T: ProofTracer>(
1195            state: *mut u8,
1196            id: u64,
1197            redundant: bool,
1198            clause: &[i32],
1199            antecedents: &[u64],
1200        ) {
1201            let ptr: *mut T = state.cast::<T>();
1202            let t = unsafe { &mut *ptr };
1203            t.add_derived_clause(id, redundant, clause, antecedents);
1204        }
1205
1206        fn delete_clause<T: ProofTracer>(state: *mut u8, id: u64, redundant: bool, clause: &[i32]) {
1207            let ptr: *mut T = state.cast::<T>();
1208            let t = unsafe { &mut *ptr };
1209            t.delete_clause(id, redundant, clause);
1210        }
1211
1212        fn weaken_minus<T: ProofTracer>(state: *mut u8, id: u64, clause: &[i32]) {
1213            let ptr: *mut T = state.cast::<T>();
1214            let t = unsafe { &mut *ptr };
1215            t.weaken_minus(id, clause);
1216        }
1217
1218        fn strengthen<T: ProofTracer>(state: *mut u8, id: u64) {
1219            let ptr: *mut T = state.cast::<T>();
1220            let t = unsafe { &mut *ptr };
1221            t.strengthen(id);
1222        }
1223
1224        fn finalize_clause<T: ProofTracer>(state: *mut u8, id: u64, clause: &[i32]) {
1225            let ptr: *mut T = state.cast::<T>();
1226            let t = unsafe { &mut *ptr };
1227            t.finalize_clause(id, clause);
1228        }
1229
1230        fn add_assumption<T: ProofTracer>(state: *mut u8, lit: i32) {
1231            let ptr: *mut T = state.cast::<T>();
1232            let t = unsafe { &mut *ptr };
1233            t.add_assumption(lit);
1234        }
1235
1236        fn add_constraint<T: ProofTracer>(state: *mut u8, clause: &[i32]) {
1237            let ptr: *mut T = state.cast::<T>();
1238            let t = unsafe { &mut *ptr };
1239            t.add_constraint(clause);
1240        }
1241
1242        fn reset_assumptions<T: ProofTracer>(state: *mut u8) {
1243            let ptr: *mut T = state.cast::<T>();
1244            let t = unsafe { &mut *ptr };
1245            t.reset_assumptions();
1246        }
1247
1248        fn add_assumption_clause<T: ProofTracer>(
1249            state: *mut u8,
1250            id: u64,
1251            clause: &[i32],
1252            antecedents: &[u64],
1253        ) {
1254            let ptr: *mut T = state.cast::<T>();
1255            let t = unsafe { &mut *ptr };
1256            t.add_assumption_clause(id, clause, antecedents);
1257        }
1258
1259        fn conclude_sat<T: ProofTracer>(state: *mut u8, conclusion_type: i32, model: &[i32]) {
1260            let ptr: *mut T = state.cast::<T>();
1261            let t = unsafe { &mut *ptr };
1262            t.conclude_sat(conclusion_type, model);
1263        }
1264
1265        fn conclude_unsat<T: ProofTracer>(
1266            state: *mut u8,
1267            conclusion_type: i32,
1268            clause_ids: &[u64],
1269        ) {
1270            let ptr: *mut T = state.cast::<T>();
1271            let t = unsafe { &mut *ptr };
1272            t.conclude_unsat(conclusion_type, clause_ids);
1273        }
1274
1275        fn conclude_unknown<T: ProofTracer>(state: *mut u8, trail: &[i32]) {
1276            let ptr: *mut T = state.cast::<T>();
1277            let t = unsafe { &mut *ptr };
1278            t.conclude_unknown(trail);
1279        }
1280
1281        let tracer_ptr = unsafe {
1282            ffi::new_tracer(
1283                std::ptr::from_mut(tracer).cast::<u8>(),
1284                add_original_clause::<T>,
1285                add_derived_clause::<T>,
1286                delete_clause::<T>,
1287                weaken_minus::<T>,
1288                strengthen::<T>,
1289                finalize_clause::<T>,
1290                add_assumption::<T>,
1291                add_constraint::<T>,
1292                reset_assumptions::<T>,
1293                add_assumption_clause::<T>,
1294                conclude_sat::<T>,
1295                conclude_unsat::<T>,
1296                conclude_unknown::<T>,
1297            )
1298        };
1299
1300        // Store the tracer to prevent it from being dropped
1301        self.last_tracer = Some(tracer_ptr);
1302
1303        // Connect the tracer to the solver
1304        ffi::connect_proof_tracer1(
1305            &mut self.solver,
1306            self.last_tracer.as_mut().unwrap(),
1307            antecedents,
1308        );
1309    }
1310
1311    // pub fn connect_proof_tracer2(
1312    //     &mut self,
1313    //     tracer: &mut UniquePtr<InternalTracer>,
1314    //     antecedents: bool,
1315    // ) {
1316    //     todo!()
1317    // }
1318    // pub fn connect_proof_tracer3(&mut self, tracer: &mut UniquePtr<StatTracer>, antecedents: bool) {
1319    //     todo!()
1320    // }
1321
1322    // pub fn connect_proof_tracer4(&mut self, tracer: &mut UniquePtr<FileTracer>, antecedents: bool) {
1323    //     todo!()
1324    // }
1325
1326    /// Triggers the conclusion of incremental proofs.
1327    /// if the solver is SATISFIED it will trigger extend ()
1328    /// and give the model to the proof tracer through `conclude_sat` ()
1329    /// if the solver is UNSATISFIED it will trigger failing ()
1330    /// which will learn new clauses as explained below:
1331    /// In case of failed assumptions will provide a core negated
1332    /// as a clause through the proof tracer interface.
1333    /// With a failing contraint these can be multiple clauses.
1334    /// Then it will trigger a `conclude_unsat` event with the id(s)
1335    /// of the newly learnt clauses or the id of the global conflict.
1336    ///
1337    ///   require (SATISFIED || UNSATISFIED)
1338    ///   ensure (SATISFIED || UNSATISFIED)
1339    ///
1340    #[inline]
1341    pub fn conclude(&mut self) {
1342        ffi::conclude(&mut self.solver);
1343    }
1344
1345    // /// Disconnect proof tracer. If this is not done before deleting
1346    // /// the tracer will be deleted. Returns true if successful.
1347    // ///
1348    // ///   require (VALID)
1349    // ///   ensure (VALID)
1350    // ///
1351    pub fn disconnect_proof_tracer1(&mut self) {
1352        if let Some(tracer) = &mut self.last_tracer {
1353            ffi::disconnect_proof_tracer1(&mut self.solver, tracer);
1354        }
1355        self.last_tracer = None;
1356    }
1357    // pub fn disconnect_proof_tracer2(&mut self, tracer: &mut UniquePtr<StatTracer>) -> bool {
1358    //     todo!()
1359    // }
1360    // pub fn disconnect_proof_tracer3(&mut self, tracer: &mut UniquePtr<FileTracer>) -> bool {
1361    //     todo!()
1362    // }
1363
1364    /// print usage information for long options
1365    #[inline]
1366    pub fn usage() {
1367        ffi::usage();
1368    }
1369
1370    /// print configuration usage options
1371    #[inline]
1372    pub fn configurations() {
1373        ffi::configurations();
1374    }
1375
1376    ///   require (!DELETING)
1377    ///   ensure (!DELETING)
1378    ///
1379    /// print statistics
1380    #[inline]
1381    pub fn statistics(&mut self) {
1382        ffi::statistics(&mut self.solver);
1383    }
1384
1385    /// print resource usage (time and memory)
1386    #[inline]
1387    pub fn resources(&mut self) {
1388        ffi::resources(&mut self.solver);
1389    }
1390
1391    ///   require (VALID)
1392    ///   ensure (VALID)
1393    ///
1394    /// print current option and value list
1395    #[inline]
1396    pub fn options(&mut self) {
1397        ffi::options(&mut self.solver);
1398    }
1399
1400    //------------------------------------------------------------------------
1401    /// Traverse irredundant clauses or the extension stack in reverse order.
1402    ///
1403    /// The return value is false if traversal is aborted early due to one of
1404    /// the visitor functions returning false.  See description of the
1405    /// iterators below for more details on how to use these functions.
1406    ///
1407    ///   require (VALID)
1408    ///   ensure (VALID)
1409    ///
1410    #[inline]
1411    pub fn traverse_clauses<I: ClauseIterator>(&self, i: &mut I) -> bool {
1412        fn f<I: ClauseIterator>(state: *mut u8, clause: &[i32]) -> bool {
1413            let ptr: *mut I = state.cast::<I>();
1414            let i = unsafe { &mut *ptr };
1415            i.clause(clause)
1416        }
1417        let mut iter =
1418            unsafe { ffi::new_clause_iterator(std::ptr::from_mut(i).cast::<u8>(), f::<I>) };
1419        ffi::traverse_clauses(&self.solver, &mut iter)
1420    }
1421
1422    #[inline]
1423    pub fn traverse_witnesses_backward<I: WitnessIterator>(&self, i: &mut I) -> bool {
1424        fn f<I: WitnessIterator>(state: *mut u8, clause: &[i32], witness: &[i32], id: u64) -> bool {
1425            let ptr: *mut I = state.cast::<I>();
1426            let i = unsafe { &mut *ptr };
1427            i.witness(clause, witness, id)
1428        }
1429        let mut iter =
1430            unsafe { ffi::new_witness_iterator(std::ptr::from_mut(i).cast::<u8>(), f::<I>) };
1431        ffi::traverse_witnesses_backward(&self.solver, &mut iter)
1432    }
1433
1434    #[inline]
1435    pub fn traverse_witnesses_forward<I: WitnessIterator>(&self, i: &mut I) -> bool {
1436        fn f<I: WitnessIterator>(state: *mut u8, clause: &[i32], witness: &[i32], id: u64) -> bool {
1437            let ptr: *mut I = state.cast::<I>();
1438            let i = unsafe { &mut *ptr };
1439            i.witness(clause, witness, id)
1440        }
1441        let mut iter =
1442            unsafe { ffi::new_witness_iterator(std::ptr::from_mut(i).cast::<u8>(), f::<I>) };
1443        ffi::traverse_witnesses_forward(&self.solver, &mut iter)
1444    }
1445
1446    //------------------------------------------------------------------------
1447    /// Files with explicit path argument support compressed input and output
1448    /// if appropriate helper functions 'gzip' etc. are available.  They are
1449    /// called through opening a pipe to an external command.
1450    ///
1451    /// If the 'strict' argument is zero then the number of variables and
1452    /// clauses specified in the DIMACS headers are ignored, i.e., the header
1453    /// 'p cnf 0 0' is always legal.  If the 'strict' argument is larger '1'
1454    /// strict formatting of the header is required, i.e., single spaces
1455    /// everywhere and no trailing white space.
1456    ///
1457    /// Returns zero if successful and otherwise an error message.
1458    ///
1459    ///   require (VALID)
1460    ///   ensure (VALID)
1461    ///
1462    #[inline]
1463    pub fn read_dimacs1(
1464        &mut self,
1465        file: String,
1466        name: String,
1467        vars: &mut i32,
1468        strict: i32,
1469    ) -> String {
1470        ffi::read_dimacs1(&mut self.solver, file, name, vars, strict)
1471    }
1472
1473    #[inline]
1474    pub fn read_dimacs2(&mut self, path: String, vars: &mut i32, strict: i32) -> String {
1475        ffi::read_dimacs2(&mut self.solver, path, vars, strict)
1476    }
1477
1478    /// The following routines work the same way but parse both DIMACS and
1479    /// INCCNF files (with 'p inccnf' header and 'a <cube>' lines).  If the
1480    /// parser finds and 'p inccnf' header or cubes then '*incremental' is set
1481    /// to true and the cubes are stored in the given vector (each cube
1482    /// terminated by a zero).
1483    #[inline]
1484    pub fn read_dimacs3(
1485        &mut self,
1486        file: String,
1487        name: String,
1488        vars: &mut i32,
1489        strict: i32,
1490        incremental: &mut bool,
1491        cubes: &mut Vec<i32>,
1492    ) -> String {
1493        ffi::read_dimacs3(
1494            &mut self.solver,
1495            file,
1496            name,
1497            vars,
1498            strict,
1499            incremental,
1500            cubes,
1501        )
1502    }
1503
1504    #[inline]
1505    pub fn read_dimacs4(
1506        &mut self,
1507        path: String,
1508        vars: &mut i32,
1509        strict: i32,
1510        incremental: &mut bool,
1511        cubes: &mut Vec<i32>,
1512    ) -> String {
1513        ffi::read_dimacs4(&mut self.solver, path, vars, strict, incremental, cubes)
1514    }
1515
1516    //------------------------------------------------------------------------
1517    /// Write current irredundant clauses and all derived unit clauses
1518    /// to a file in DIMACS format.  Clauses on the extension stack are
1519    /// not included, nor any redundant clauses.
1520    ///
1521    /// The '`min_max_var`' parameter gives a lower bound on the number '<vars>'
1522    /// of variables used in the DIMACS 'p cnf <vars> ...' header.
1523    ///
1524    /// Returns zero if successful and otherwise an error message.
1525    ///
1526    ///   require (VALID)
1527    ///   ensure (VALID)
1528    ///
1529    #[inline]
1530    pub fn write_dimacs(&mut self, path: String, min_max_var: i32) -> String {
1531        ffi::write_dimacs(&mut self.solver, path, min_max_var)
1532    }
1533
1534    /// The extension stack for reconstruction a solution can be written too.
1535    ///
1536    #[inline]
1537    pub fn write_extension(&mut self, path: String) -> String {
1538        ffi::write_extension(&mut self.solver, path)
1539    }
1540
1541    /// Print build configuration to a file with prefix 'c '.  If the file
1542    /// is '<stdout>' or '<stderr>' then terminal color codes might be used.
1543    ///
1544    #[inline]
1545    pub fn build(file: String, prefix: String) {
1546        ffi::build(file, prefix);
1547    }
1548}
1549
1550/// Connected terminators are checked for termination regularly.  If the
1551/// 'terminate' function of the terminator returns true the solver is
1552/// terminated synchronously as soon it calls this function.
1553pub trait Terminator {
1554    fn terminated(&mut self) -> bool;
1555}
1556
1557/// Connected learners which can be used to export learned clauses.
1558/// The 'learning' can check the size of the learn clause and only if it
1559/// returns true then the individual literals of the learned clause are given
1560/// to the learn through 'learn' one by one terminated by a zero literal.
1561pub trait Learner {
1562    fn learning(&mut self, size: i32) -> bool;
1563    fn learn(&mut self, lit: i32);
1564}
1565
1566/// Connected listener gets notified whenever the truth value of a variable is
1567/// fixed (for example during inprocessing or due to some derived unit clauses).
1568pub trait FixedAssignmentListener {
1569    fn notify_fixed_assignment(&mut self, lit: i32);
1570}
1571
1572use std::vec::Vec;
1573
1574/// Allows to connect an external propagator to propagate values to variables
1575/// with an external clause as a reason or to learn new clauses during the
1576/// CDCL loop (without restart).
1577pub trait ExternalPropagator {
1578    /// lazy propagator only checks complete assignments
1579    fn is_lazy(&mut self) -> bool {
1580        false
1581    }
1582
1583    /// Reason external clauses can be deleted
1584    fn are_reasons_forgettable(&mut self) -> bool {
1585        false
1586    }
1587
1588    /// Notify the propagator about assignments to observed variables.
1589    /// The notification is not necessarily eager. It usually happens before
1590    /// the call of propagator callbacks and when a driving clause is leading
1591    /// to an assignment.
1592    fn notify_assignment(&mut self, lits: &[i32]);
1593
1594    fn notify_new_decision_level(&mut self);
1595
1596    fn notify_backtrack(&mut self, new_level: usize);
1597
1598    /// Check by the external propagator the found complete solution (after
1599    /// solution reconstruction). If it returns false, the propagator must
1600    /// provide an external clause during the next callback.
1601    fn cb_check_found_model(&mut self, model: &[i32]) -> bool;
1602
1603    /// Ask the external propagator for the next decision literal. If it
1604    /// returns 0, the solver makes its own choice.
1605    fn cb_decide(&mut self) -> i32 {
1606        0
1607    }
1608
1609    /// Ask the external propagator if there is an external propagation to make
1610    /// under the current assignment. It returns either a literal to be
1611    /// propagated or 0, indicating that there is no external propagation under
1612    /// the current assignment.
1613    fn cb_propagate(&mut self) -> i32 {
1614        0
1615    }
1616
1617    /// Ask the external propagator for the reason clause of a previous
1618    /// external propagation step (done by `cb_propagate`). The clause must be
1619    /// added literal-by-literal closed with a 0. Further, the clause must
1620    /// contain the propagated literal.
1621    ///
1622    /// The clause will be learned as an Irredundant Non-Forgettable Clause (see
1623    /// below at '`cb_has_external_clause`' more details about it).
1624    fn cb_add_reason_clause_lit(&mut self, _propagated_lit: i32) -> i32 {
1625        0
1626    }
1627
1628    /// The following two functions are used to add external clauses to the
1629    /// solver during the CDCL loop. The external clause is added
1630    /// literal-by-literal and learned by the solver as an irredundant
1631    /// (original) input clause. The clause can be arbitrary, but if it is
1632    /// root-satisfied or tautology, the solver will ignore it without learning
1633    /// it. Root-falsified literals are eagerly removed from the clause.
1634    /// Falsified clauses trigger conflict analysis, propagating clauses
1635    /// trigger propagation. In case chrono is 0, the solver backtracks to
1636    /// propagate the new literal on the right decision level, otherwise it
1637    /// potentially will be an out-of-order assignment on the current level.
1638    /// Unit clauses always (unless root-satisfied, see above) trigger
1639    /// backtracking (independently from the value of the chrono option and
1640    /// independently from being falsified or satisfied or unassigned) to level
1641    /// 0. Empty clause (or root falsified clause, see above) makes the problem
1642    /// unsat and stops the search immediately. A literal 0 must close the
1643    /// clause.
1644    ///
1645    /// The external propagator indicates that there is a clause to add.
1646    /// The parameter of the function allows the user to indicate that how
1647    /// 'forgettable' is the external clause. Forgettable clauses are allowed
1648    /// to be removed by the SAT solver during clause database reduction.
1649    /// However, it is up to the solver to decide when actually the clause is
1650    /// deleted. For example, unit clauses, even forgettable ones, will not be
1651    /// deleted. In case the clause is not 'forgettable' (the parameter is false),
1652    /// the solver considers the clause to be irredundant.
1653    ///
1654    /// In case the solver produces incremental proofs, these external clauses
1655    /// are added to the proof during solving at real-time, i.e., the proof
1656    /// checker can ignore them until that point (so added as input clause, but
1657    /// input after the query line).
1658    ///
1659    /// Reason clauses of external propagation steps are assumed to be
1660    /// forgettable, parameter '`reason_forgettable`' can be used to change it.
1661    ///
1662    /// Currently, every external clause is expected to be over observed
1663    /// (therefore frozen) variables, hence no tainting or restore steps
1664    /// are performed upon their addition. This will be changed in later
1665    /// versions probably.
1666    fn cb_has_external_clause(&mut self, is_forgettable: &mut bool) -> bool;
1667
1668    /// The actual function called to add the external clause.
1669    fn cb_add_external_clause_lit(&mut self) -> i32;
1670}
1671
1672/// Allows to traverse all remaining irredundant clauses.  Satisfied and
1673/// eliminated clauses are not included, nor any derived units unless such
1674/// a unit literal is frozen. Falsified literals are skipped.  If the solver
1675/// is inconsistent only the empty clause is traversed.
1676///
1677/// If 'clause' returns false traversal aborts early.
1678pub trait ClauseIterator {
1679    fn clause(&mut self, clause: &[i32]) -> bool;
1680}
1681
1682/// Allows to traverse all clauses on the extension stack together with their
1683/// witness cubes.  If the solver is inconsistent, i.e., an empty clause is
1684/// found and the formula is unsatisfiable, then nothing is traversed.
1685///
1686/// The clauses traversed in '`traverse_clauses`' together with the clauses on
1687/// the extension stack are logically equivalent to the original clauses.
1688/// See our SAT'19 paper for more details.
1689///
1690/// The witness literals can be used to extend and fix an assignment on the
1691/// remaining clauses to satisfy the clauses on the extension stack too.
1692///
1693/// All derived units of non-frozen variables are included too.
1694///
1695/// If 'witness' returns false traversal aborts early.
1696pub trait WitnessIterator {
1697    fn witness(&mut self, clause: &[i32], witness: &[i32], id: u64) -> bool;
1698}
1699
1700/// Trait for proof tracing that allows you to track proof events in real-time.
1701/// This is useful for SMT solvers that need to interleave SAT solver clauses
1702/// with theory clauses to generate eDRAT proofs.
1703pub trait ProofTracer {
1704    /// Called when an original clause is added to the solver
1705    fn add_original_clause(&mut self, id: u64, redundant: bool, clause: &[i32], restored: bool);
1706
1707    /// Called when a derived clause is learned by the SAT solver
1708    fn add_derived_clause(&mut self, id: u64, redundant: bool, clause: &[i32], antecedents: &[u64]);
1709
1710    /// Called when a clause is deleted
1711    fn delete_clause(&mut self, id: u64, redundant: bool, clause: &[i32]);
1712
1713    /// Called when a clause is weakened (might be restored later)
1714    fn weaken_minus(&mut self, id: u64, clause: &[i32]);
1715
1716    /// Called when a clause is strengthened
1717    fn strengthen(&mut self, id: u64);
1718
1719    /// Called when a clause is finalized
1720    fn finalize_clause(&mut self, id: u64, clause: &[i32]);
1721
1722    /// Called when an assumption is added
1723    fn add_assumption(&mut self, lit: i32);
1724
1725    /// Called when a constraint is added
1726    fn add_constraint(&mut self, clause: &[i32]);
1727
1728    /// Called when assumptions are reset
1729    fn reset_assumptions(&mut self);
1730
1731    /// Called when an assumption clause is added (negation of failing assumptions)
1732    fn add_assumption_clause(&mut self, id: u64, clause: &[i32], antecedents: &[u64]);
1733
1734    /// Called when the solver concludes SAT
1735    fn conclude_sat(&mut self, conclusion_type: i32, model: &[i32]);
1736
1737    /// Called when the solver concludes UNSAT
1738    fn conclude_unsat(&mut self, conclusion_type: i32, clause_ids: &[u64]);
1739
1740    /// Called when the solver concludes UNKNOWN
1741    fn conclude_unknown(&mut self, trail: &[i32]);
1742}