Skip to main content

rustsat/
solvers.rs

1//! # Interfaces to SAT Solvers
2//!
3//! This module holds types and functions regarding SAT solvers. The main
4//! element is the [`Solve`] trait that every SAT solver in this library
5//! implements.
6//!
7//! ## Available Solvers
8//!
9//! Solvers are available through separate crates.
10//!
11//! ### CaDiCaL
12//!
13//! [CaDiCaL](https://github.com/arminbiere/cadical) is a fully incremental SAT
14//! solver by Armin Biere implemented in Cpp. It includes incremental
15//! inprocessing. It is available through the
16//! [`rustsat-cadical`](https://crates.io/crates/rustsat-cadical) crate.
17//!
18//! #### References
19//!
20//! - Armin Biere and Katalin Fazekas and Mathias Fleury and Maximillian
21//!   Heisinger: _CaDiCaL, Kissat, Paracooba, Plingeling and Treengeling
22//!   Entering the SAT Competition 2020_, SAT Competition 2020.
23//! - Original Repository:
24//!   [`https://github.com/arminbiere/cadical`](https://github.com/arminbiere/cadical)
25//! - Solver crate:
26//!   [`https://crates.io/crates/rustsat-cadical`](https://crates.io/crates/rustsat-cadical)
27//!
28//! ### Kissat
29//!
30//! [Kissat](https://github.com/arminbiere/kissat) is a non-incremental SAT
31//! solver by Armin Biere implemented in C. It is available through the
32//! [`rustsat-kissat`](https://crates.io/crates/rustsat-kissat) crate.
33//!
34//! #### References
35//!
36//! - Armin Biere and Katalin Fazekas and Mathias Fleury and Maximillian
37//!   Heisinger: _CaDiCaL, Kissat, Paracooba, Plingeling and Treengeling
38//!   Entering the SAT Competition 2020_, SAT Competition 2020.
39//! - Repository:
40//!   [`https://github.com/arminbiere/kissat`](https://github.com/arminbiere/kissat)
41//! - Solver crate:
42//!   [`https://github.com/chrjabs/rustsat-kissat`](https://github.com/chrjabs/rustsat-kissat)
43//!
44//! ### Minisat
45//!
46//! [Minisat](https://github.com/niklasso/minisat) is an incremental SAT solver
47//! by Niklas Eén and Niklas Sörensson. It is available through the
48//! [`rustsat-minisat`](https://crates.io/crates/rustsat-minisat) crate.
49//!
50//! #### References
51//!
52//! - Niklas Eén and Niklas Sörensson (2003): _An Extensible SAT-solver_, SAT
53//!   2003.
54//! - Repository:
55//!   [`https://github.com/niklasso/minisat`](https://github.com/niklasso/minisat)
56//! - Solver crate:
57//!   [`https://crates.io/crates/rustsat-minisat`](https://crates.io/crates/rustsat-minisat)
58//! - Fork used in solver crate:
59//!   [`https://github.com/chrjabs/rustsat/tree/main/minisat/cppsrc`](https://github.com/chrjabs/rustsat/tree/main/minisat/cppsrc)
60//!
61//! ### Glucose
62//!
63//! [Glucose](https://www.labri.fr/perso/lsimon/research/glucose/) is a SAT
64//! solver based on Minisat and developed by Gilles Audemard and Laurent Simon.
65//! It is available through the
66//! [`rustsat-glucose`](https://crates.io/crates/rustsat-glucose) crate.
67//!
68//! #### References
69//!
70//! - Gilles Audemard and Laurent Simon: _Predicting Learnt Clauses Quality in
71//!   Modern SAT Solvers_, IJCAI 2009.
72//! - More references at the [Glucose
73//!   web-page](https://www.labri.fr/perso/lsimon/research/glucose/)
74//! - Solver crate:
75//!   [`https://crates.io/crates/rustsat-glucose`](https://crates.io/crates/rustsat-glucose)
76//! - Fork used in solver crate:
77//!   [`https://github.com/chrjabs/rustsat/tree/main/glucose/cppsrc`](https://github.com/chrjabs/rustsat/tree/main/glucose/cppsrc)
78//!
79//! ### BatSat
80//!
81//! [BatSat](https://github.com/c-cube/batsat) is a SAT solver based on Minisat but fully
82//! implemented in Rust. Because it is fully implemented in Rust, it is a good choice for
83//! restricted compilation scenarios like WebAssembly. BatSat is available through the
84//! [`rustsat-batsat`](httpe://crates.io/crates/rustsat-batsat) crate.
85//!
86//! #### References
87//!
88//! - Solver interface crate:
89//!   [`https://crates.io/crates/rustsat-batsat`](https://crates.io/crate/rustsat-batsat)
90//! - BatSat crate:
91//!   [`https://crates.io/crates/batsat`](https://crates.io/crate/batsat)
92//! - BatSat repository:
93//!   [`https://github.com/c-cube/batsat`](https://github.com/c-cube/batsat)
94//!
95//! ### External Solvers
96//!
97//! RustSAT provides an interface for calling external solver binaries by passing them DIMACS input
98//! and parsing their output written to `<stdout>`. For more details, see the [`ExternalSolver`]
99//! type.
100//!
101//! ### IPASIR
102//!
103//! [IPASIR](https://github.com/biotomas/ipasir) is a C API for incremental SAT
104//! solvers. IPASIR bindings for RustSAT are provided in the
105//! [`rustsat-ipasir`](https://crates.io/crates/rustsat-ipasir) crate.
106
107use crate::{
108    clause,
109    encodings::CollectClauses,
110    instances::Cnf,
111    lit,
112    types::{Assignment, Cl, Clause, Lit, TernaryVal, Var},
113};
114use core::time::Duration;
115use std::fmt;
116use thiserror::Error;
117
118pub mod external;
119pub use external::Solver as ExternalSolver;
120
121pub mod simulators;
122
123/// Trait for all SAT solvers in this library.
124/// Solvers outside of this library can also implement this trait to be able to
125/// use them with this library.
126///
127/// **Note**: the [`Extend`] implementations call [`Solve::add_clause`] or
128/// [`Solve::add_clause_ref`] internally but _convert errors to panics_.
129pub trait Solve: Extend<Clause> + for<'a> Extend<&'a Clause> {
130    /// Gets a signature of the solver implementation
131    #[must_use]
132    fn signature(&self) -> &'static str;
133    /// Reserves memory in the solver until a maximum variables, if the solver
134    /// supports it
135    ///
136    /// # Errors
137    ///
138    /// A solver may return any error. One typical option might be [`crate::OutOfMemory`].
139    fn reserve(&mut self, _max_var: Var) -> anyhow::Result<()> {
140        Ok(())
141    }
142    /// Solves the internal CNF formula without any assumptions.
143    ///
144    /// # Example
145    ///
146    /// ```
147    /// # use rustsat::{lit, solvers::{SolverResult, Solve}};
148    /// // any other solver crate works the same way
149    /// let mut solver = rustsat_minisat::core::Minisat::default();
150    /// solver.add_unit(lit![0]).unwrap();
151    /// let res = solver.solve().unwrap();
152    /// debug_assert_eq!(res, SolverResult::Sat);
153    /// ```
154    ///
155    /// # Errors
156    ///
157    /// A solver may return any error. One typical option might be [`crate::OutOfMemory`].
158    fn solve(&mut self) -> anyhow::Result<SolverResult>;
159    /// Gets a solution found by the solver up to a specified highest variable.
160    ///
161    /// # Errors
162    ///
163    /// - If the solver is not in the satisfied state, returns [`StateError`]
164    /// - A specific implementation might return other errors
165    fn solution(&self, high_var: Var) -> anyhow::Result<Assignment> {
166        let mut assignment = Vec::new();
167        let len = high_var.idx32() + 1;
168        assignment.reserve(len as usize);
169        for idx in 0..len {
170            let lit = Lit::positive(idx);
171            assignment.push(self.lit_val(lit)?);
172        }
173        Ok(Assignment::from(assignment))
174    }
175    /// Gets a solution found by the solver up to the highest variable known
176    /// to the solver.
177    ///
178    /// # Errors
179    ///
180    /// - If the solver is not in the satisfied state, returns [`StateError`]
181    /// - A specific implementation might return other errors
182    fn full_solution(&self) -> anyhow::Result<Assignment>
183    where
184        Self: SolveStats,
185    {
186        if let Some(high_var) = self.max_var() {
187            self.solution(high_var)
188        } else {
189            // throw error if in incorrect state
190            self.lit_val(lit![0])?;
191            Ok(Assignment::default())
192        }
193    }
194    /// Same as [`Solve::lit_val`], but for variables.
195    ///
196    /// # Errors
197    ///
198    /// - If the solver is not in the satisfied state, returns [`StateError`]
199    /// - A specific implementation might return other errors
200    fn var_val(&self, var: Var) -> anyhow::Result<TernaryVal> {
201        self.lit_val(var.pos_lit())
202    }
203    /// Gets an assignment of a variable in the solver.
204    ///
205    /// # Example
206    ///
207    /// ```
208    /// # use rustsat::{lit, solvers::Solve, types::TernaryVal};
209    /// // any other solver crate works the same way
210    /// let mut solver = rustsat_minisat::core::Minisat::default();
211    /// solver.add_unit(lit![0]).unwrap();
212    /// let res = solver.solve().unwrap();
213    /// debug_assert_eq!(solver.lit_val(lit![0]).unwrap(), TernaryVal::True);
214    /// ```
215    ///
216    /// # Errors
217    ///
218    /// - If the solver is not in the satisfied state return [`StateError`]
219    /// - A specific implementation might return other errors
220    fn lit_val(&self, lit: Lit) -> anyhow::Result<TernaryVal>;
221    /// Adds a clause to the solver.
222    /// If the solver is in the satisfied or unsatisfied state before, it is in
223    /// the input state afterwards.
224    ///
225    /// This method can be implemented by solvers that can truly take ownership of the clause.
226    /// Otherwise, it will fall back to the mandatory [`Solve::add_clause_ref`] method.
227    ///
228    /// # Errors
229    ///
230    /// - If the solver is in an invalid state, returns [`StateError`]
231    /// - A specific implementation might return other errors
232    fn add_clause(&mut self, clause: Clause) -> anyhow::Result<()> {
233        self.add_clause_ref(&clause)
234    }
235    /// Adds a clause to the solver by reference.
236    /// If the solver is in the satisfied or unsatisfied state before, it is in
237    /// the input state afterwards.
238    ///
239    /// # Errors
240    ///
241    /// - If the solver is in an invalid state, returns [`StateError`]
242    /// - A specific implementation might return other errors
243    // TODO: Maybe rename this to `add_clause` in the future and deprecate the version taking by
244    // value
245    fn add_clause_ref<C>(&mut self, clause: &C) -> anyhow::Result<()>
246    where
247        C: AsRef<Cl> + ?Sized;
248    /// Like [`Solve::add_clause`] but for unit clauses (clauses with one literal).
249    ///
250    /// # Errors
251    ///
252    /// See [`Solve::add_clause`]
253    fn add_unit(&mut self, lit: Lit) -> anyhow::Result<()> {
254        self.add_clause(clause![lit])
255    }
256    /// Like [`Solve::add_clause`] but for clauses with two literals.
257    ///
258    /// # Errors
259    ///
260    /// See [`Solve::add_clause`]
261    fn add_binary(&mut self, lit1: Lit, lit2: Lit) -> anyhow::Result<()> {
262        self.add_clause(clause![lit1, lit2])
263    }
264    /// Like [`Solve::add_clause`] but for clauses with three literals.
265    ///
266    /// # Errors
267    ///
268    /// See [`Solve::add_clause`]
269    fn add_ternary(&mut self, lit1: Lit, lit2: Lit, lit3: Lit) -> anyhow::Result<()> {
270        self.add_clause(clause![lit1, lit2, lit3])
271    }
272    /// Adds all clauses from a [`Cnf`] instance.
273    ///
274    /// # Errors
275    ///
276    /// See [`Solve::add_clause`]
277    fn add_cnf(&mut self, cnf: Cnf) -> anyhow::Result<()> {
278        cnf.into_iter().try_for_each(|cl| self.add_clause(cl))
279    }
280    /// Adds all clauses from a [`Cnf`] instance by reference.
281    ///
282    /// # Errors
283    ///
284    /// See [`Solve::add_clause`]
285    fn add_cnf_ref(&mut self, cnf: &Cnf) -> anyhow::Result<()> {
286        cnf.iter().try_for_each(|cl| self.add_clause_ref(cl))
287    }
288}
289
290/// Trait for all SAT solvers in this library.
291/// Solvers outside of this library can also implement this trait to be able to
292/// use them with this library.
293pub trait SolveIncremental: Solve {
294    /// Solves the internal CNF formula under assumptions.
295    ///
296    /// # Errors
297    ///
298    /// A solver may return any error. One typical option might be [`crate::OutOfMemory`].
299    fn solve_assumps(&mut self, assumps: &[Lit]) -> anyhow::Result<SolverResult>;
300    /// Gets a core found by an unsatisfiable query.
301    /// A core is a clause entailed by the formula that contains only inverted
302    /// literals of the assumptions.
303    ///
304    /// # Errors
305    ///
306    /// - If the solver is not in the unsatisfied state, returns [`StateError`]
307    /// - A specific implementation might return other errors
308    fn core(&mut self) -> anyhow::Result<Vec<Lit>>;
309}
310
311/// Trait for all solvers that can be terminated by a termination callback.
312pub trait Terminate<'term> {
313    /// Attaches a termination callback to the solver. During solving this
314    /// callback is regularly called and the solver terminates if the callback
315    /// returns [`ControlSignal::Terminate`]. Only a single callback can be
316    /// attached at any time, attaching a second callback drops the first one.
317    fn attach_terminator<CB>(&mut self, cb: CB)
318    where
319        CB: FnMut() -> ControlSignal + 'term;
320    /// Detaches the terminator
321    fn detach_terminator(&mut self);
322}
323
324/// Trait for all solvers that can pass out learned clauses via a callback.
325pub trait Learn<'learn> {
326    /// Attaches a learner callback to the solver. This callback is called every
327    /// time a clause of length up to `max_len` is learned.
328    fn attach_learner<CB>(&mut self, cb: CB, max_len: usize)
329    where
330        CB: FnMut(Clause) + 'learn;
331    /// Detaches the learner
332    fn detach_learner(&mut self);
333}
334
335/// Trait for all solvers that can be asynchronously interrupt.
336pub trait Interrupt {
337    /// The interrupter of the solver
338    type Interrupter: InterruptSolver + Send + 'static;
339    /// Gets a thread safe interrupter object that can be used to terminate the solver
340    #[must_use]
341    fn interrupter(&mut self) -> Self::Interrupter;
342}
343
344/// A thread safe interrupter for a solver
345pub trait InterruptSolver: Sync {
346    /// Interrupts the solver asynchronously
347    fn interrupt(&self);
348}
349
350/// Trait for all solvers that can force a face for a literal
351pub trait PhaseLit {
352    /// Forces the default decision phase of a variable to a certain value
353    ///
354    /// # Errors
355    ///
356    /// A solver may return any error.
357    fn phase_lit(&mut self, lit: Lit) -> anyhow::Result<()>;
358    /// Undoes the effect of a call to [`PhaseLit::phase_lit`]
359    ///
360    /// # Errors
361    ///
362    /// A solver may return any error.
363    fn unphase_var(&mut self, var: Var) -> anyhow::Result<()>;
364    /// Undoes the effect of a call to [`PhaseLit::phase_lit`]
365    ///
366    /// # Errors
367    ///
368    /// A solver may return any error.
369    fn unphase_lit(&mut self, lit: Lit) -> anyhow::Result<()> {
370        self.unphase_var(lit.var())
371    }
372}
373
374/// Trait for freezing and melting variables in solvers with pre-/inprocessing.
375pub trait FreezeVar {
376    /// Freezes a variable so that it is not removed in pre-/inprocessing
377    ///
378    /// # Errors
379    ///
380    /// A solver may return any error.
381    fn freeze_var(&mut self, var: Var) -> anyhow::Result<()>;
382    /// Melts a variable after it had been frozen
383    ///
384    /// # Errors
385    ///
386    /// A solver may return any error.
387    fn melt_var(&mut self, var: Var) -> anyhow::Result<()>;
388    /// Checks if a variable is frozen
389    ///
390    /// # Errors
391    ///
392    /// A solver may return any error.
393    fn is_frozen(&mut self, var: Var) -> anyhow::Result<bool>;
394}
395
396/// Trait for all solvers that can flip a literal in the current assignment
397pub trait FlipLit {
398    /// Attempts flipping the literal in the given assignment and returns `true` if successful
399    ///
400    /// # Errors
401    ///
402    /// A solver may return any error.
403    fn flip_lit(&mut self, lit: Lit) -> anyhow::Result<bool>;
404    /// Checks if the literal can be flipped in the given assignment without flipping it
405    ///
406    /// # Errors
407    ///
408    /// A solver may return any error.
409    fn is_flippable(&mut self, lit: Lit) -> anyhow::Result<bool>;
410}
411
412/// Trait for all solvers that can limit the number of conflicts
413pub trait LimitConflicts {
414    /// Sets or removes a limit on the number of conflicts
415    ///
416    /// # Errors
417    ///
418    /// A solver may return any error.
419    fn limit_conflicts(&mut self, limit: Option<u32>) -> anyhow::Result<()>;
420}
421
422/// Trait for all solvers that can limit the number of decisions
423pub trait LimitDecisions {
424    /// Sets or removes a limit on the number of decisions
425    ///
426    /// # Errors
427    ///
428    /// A solver may return any error.
429    fn limit_decisions(&mut self, limit: Option<u32>) -> anyhow::Result<()>;
430}
431
432/// Trait for all solvers that can limit the number of propagations
433pub trait LimitPropagations {
434    /// Sets or removes a limit on the number of propagations
435    ///
436    /// # Errors
437    ///
438    /// A solver may return any error.
439    fn limit_propagations(&mut self, limit: Option<u32>) -> anyhow::Result<()>;
440}
441
442/// Trait for all solvers allowing access to internal search statistics
443pub trait GetInternalStats {
444    /// Gets the number of propagations
445    #[must_use]
446    fn propagations(&self) -> usize;
447    /// Gets the number of decisions
448    #[must_use]
449    fn decisions(&self) -> usize;
450    /// Gets the number of conflicts
451    #[must_use]
452    fn conflicts(&self) -> usize;
453}
454
455/// Trait for propagating a set of assumptions and getting all propagated literals
456pub trait Propagate {
457    /// Propagates the given assumptions and returns all propagated literals, as well as whether a
458    /// conflict was encountered
459    ///
460    /// # Errors
461    ///
462    /// A solver may return any error.
463    fn propagate(&mut self, assumps: &[Lit], phase_saving: bool)
464        -> anyhow::Result<PropagateResult>;
465}
466
467/// A result returned from the [`Propagate`] trait
468#[derive(Debug)]
469#[must_use]
470pub struct PropagateResult {
471    /// The list of propagated literals
472    pub propagated: Vec<Lit>,
473    /// Whether a conflict was encountered
474    pub conflict: bool,
475}
476
477#[allow(dead_code)]
478type TermCallbackPtr<'a> = Box<dyn FnMut() -> ControlSignal + 'a>;
479#[allow(dead_code)]
480type LearnCallbackPtr<'a> = Box<dyn FnMut(Clause) + 'a>;
481#[allow(dead_code)]
482/// Double boxing is necessary to get thin pointers for casting
483type OptTermCallbackStore<'a> = Option<Box<TermCallbackPtr<'a>>>;
484#[allow(dead_code)]
485/// Double boxing is necessary to get thin pointers for casting
486type OptLearnCallbackStore<'a> = Option<Box<LearnCallbackPtr<'a>>>;
487
488/// Solver statistics
489#[derive(Clone, PartialEq, Default, Debug)]
490pub struct SolverStats {
491    /// The number of satisfiable queries executed
492    pub n_sat: usize,
493    /// The number of unsatisfiable queries executed
494    pub n_unsat: usize,
495    /// The number of terminated queries executed
496    pub n_terminated: usize,
497    /// The number of clauses in the solver
498    pub n_clauses: usize,
499    /// The highest variable in the solver
500    pub max_var: Option<Var>,
501    /// The average length of the clauses added to the solver
502    pub avg_clause_len: f32,
503    /// The total CPU time spent solving
504    pub cpu_solve_time: Duration,
505}
506
507/// Trait for solvers that track certain statistics.
508pub trait SolveStats {
509    /// Gets the available statistics from the solver
510    #[must_use]
511    fn stats(&self) -> SolverStats;
512    /// Gets the number of satisfiable queries executed.
513    #[must_use]
514    fn n_sat_solves(&self) -> usize {
515        self.stats().n_sat
516    }
517    /// Gets the number of unsatisfiable queries executed.
518    #[must_use]
519    fn n_unsat_solves(&self) -> usize {
520        self.stats().n_unsat
521    }
522    /// Gets the number of queries that were prematurely terminated.
523    #[must_use]
524    fn n_terminated(&self) -> usize {
525        self.stats().n_terminated
526    }
527    /// Gets the total number of queries executed.
528    #[must_use]
529    fn n_solves(&self) -> usize {
530        self.n_sat_solves() + self.n_unsat_solves() + self.n_terminated()
531    }
532    /// Gets the number of clauses in the solver.
533    #[must_use]
534    fn n_clauses(&self) -> usize {
535        self.stats().n_clauses
536    }
537    /// Gets the variable with the highest index in the solver, if any.
538    ///
539    /// If all variables below have been used, the index of this variable plus one is the number of
540    /// variables in the solver.
541    #[must_use]
542    fn max_var(&self) -> Option<Var> {
543        self.stats().max_var
544    }
545    /// Get number of variables.
546    /// Note: this is only correct if all variables are used in order!
547    #[must_use]
548    fn n_vars(&self) -> usize {
549        match self.max_var() {
550            Some(var) => var.idx() + 1,
551            None => 0,
552        }
553    }
554    /// Gets the average length of all clauses in the solver.
555    #[must_use]
556    fn avg_clause_len(&self) -> f32 {
557        self.stats().avg_clause_len
558    }
559    /// Gets the total CPU time spent solving.
560    #[must_use]
561    fn cpu_solve_time(&self) -> Duration {
562        self.stats().cpu_solve_time
563    }
564}
565
566/// States that the solver can be in.
567#[derive(Debug, Clone, Copy, PartialEq, Eq)]
568pub enum SolverState {
569    /// Configuration of the solver must be done in this state, before any clauses are added
570    Configuring,
571    /// Input state, while adding clauses.
572    Input,
573    /// The query was found satisfiable.
574    Sat,
575    /// The query was found unsatisfiable.
576    Unsat,
577    /// Solving was terminated before a conclusion was reached
578    Unknown,
579}
580
581impl fmt::Display for SolverState {
582    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
583        match self {
584            SolverState::Configuring => write!(f, "CONFIGURING"),
585            SolverState::Input => write!(f, "INPUT"),
586            SolverState::Sat => write!(f, "SAT"),
587            SolverState::Unsat => write!(f, "UNSAT"),
588            SolverState::Unknown => write!(f, "UNKNOWN"),
589        }
590    }
591}
592
593/// Return value for solving queries.
594#[derive(Clone, Copy, Debug, PartialEq, Eq)]
595pub enum SolverResult {
596    /// The query was found satisfiable.
597    Sat,
598    /// The query was found unsatisfiable.
599    Unsat,
600    /// The query was prematurely interrupted.
601    Interrupted,
602}
603
604impl fmt::Display for SolverResult {
605    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
606        match self {
607            SolverResult::Sat => write!(f, "SAT"),
608            SolverResult::Unsat => write!(f, "UNSAT"),
609            SolverResult::Interrupted => write!(f, "Interrupted"),
610        }
611    }
612}
613
614/// Return type for solver terminator callbacks
615#[derive(Debug, PartialEq, Eq)]
616pub enum ControlSignal {
617    /// Variant for the solver to continue
618    Continue,
619    /// Variant for the solver to terminate
620    Terminate,
621}
622
623/// A solver state error
624#[derive(Error, Debug, Clone, PartialEq, Eq)]
625pub struct StateError {
626    /// The state required for the operation
627    pub required_state: SolverState,
628    /// The state that the solver is actually in
629    pub actual_state: SolverState,
630}
631
632impl fmt::Display for StateError {
633    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
634        write!(
635            f,
636            "action requires {} state, but solver is in state {}",
637            self.required_state, self.actual_state
638        )
639    }
640}
641
642macro_rules! pass_oom_or_panic {
643    ($result:expr) => {{
644        match $result {
645            Ok(res) => res,
646            Err(err) => match err.downcast::<crate::OutOfMemory>() {
647                Ok(oom) => return Err(oom),
648                Err(err) => panic!("unexpected error in clause collector: {err}"),
649            },
650        }
651    }};
652}
653
654impl<S: Solve + SolveStats> CollectClauses for S {
655    fn n_clauses(&self) -> usize {
656        self.n_clauses()
657    }
658
659    fn extend_clauses<T>(&mut self, cl_iter: T) -> Result<(), crate::OutOfMemory>
660    where
661        T: IntoIterator<Item = Clause>,
662    {
663        for cl in cl_iter {
664            pass_oom_or_panic!(self.add_clause(cl));
665        }
666        Ok(())
667    }
668
669    fn add_clause(&mut self, cl: Clause) -> Result<(), crate::OutOfMemory> {
670        pass_oom_or_panic!(self.add_clause(cl));
671        Ok(())
672    }
673}
674
675/// Trait for types that allow for initializing a solver or other types
676///
677/// This is very similar to the [`Default`] trait, but allows for implementing multiple
678/// initializers for the same solver. Having this as a trait rather than simply a function allows
679/// for more flexibility with generics.
680pub trait Initialize<T> {
681    /// Generates a new instance
682    fn init() -> T;
683}
684
685/// An initializer that simply calls the [`Default`] method of another type
686#[derive(Debug)]
687pub struct DefaultInitializer;
688
689impl<T: Default> Initialize<T> for DefaultInitializer {
690    #[inline]
691    fn init() -> T {
692        T::default()
693    }
694}