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