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}