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}