Splr is a modern SAT solver in Rust, based on Glucose 4.1. It adopts various research results on modern SAT solvers:
Many thanks to SAT researchers.
Please check ChangeLog about recent updates.
Though Splr comes with ABSOLUTELY NO WARRANTY, I'd like to show some results.
Just run cargo install splr
after installing the latest cargo.
Two executables will be installed:
splr
-- the solverdmcr
-- a very simple model checker to verify a satisfiable assignment set generated by splr
.Alternatively, Nix users can use nix build
.
Splr is a standalone program, taking a CNF file. The result will be saved to a file, which format is defined by SAT competition 2011 rules.
plain
unif-k3-r4.25-v360-c1530-S1293537826-039.cnf 360,1530 |time: 251.06
#conflict: 2402204, #decision: 4410993, #propagate: 129058093
Assignment|#rem: 351, #fix: 0, #elm: 9, prg%: 2.5000
Clause|Remv: 70187, LBD2: 613, BinC: 2, Perm: 1523
Restart|#BLK: 0, #RST: 3655, *scl: 1, sclM: 32
LBD|avrg: 9.9065, trnd: 0.7834, depG: 3.0248, /dpc: 1.17
Conflict|tASG: 0.9294, cLvl: 16.08, bLvl: 14.93, /ppc: 56.35
misc|vivC: 861, subC: 0, core: 125, /cpr: 2900.25
Result|file: ./ans_unif-k3-r4.25-v360-c1530-S1293537826-039.cnf
s SATISFIABLE: cnfs/unif-k3-r4.25-v360-c1530-S1293537826-039.cnf
plain
$ cat ans_unif-k3-r4.25-v360-c1530-S1293537826-039.cnf
c This file was generated by splr-0.11.0 for cnfs/unif-k3-r4.25-v360-c1530-S1293537826-039.cnf
c
c unif-k3-r4.25-v360-c1530-S1293537826-039.cnf, #var: 360, #cls: 1530
c #conflict: 2402204, #decision: 4410993, #propagate: 129058093,
c Assignment|#rem: 351, #fix: 0, #elm: 9, prg%: 2.5000,
c Clause|Remv: 70187, LBD2: 613, BinC: 2, Perm: 1523,
c Restart|#BLK: 0, #RST: 3655, *scl: 1, sclM: 32,
c LBD|avrg: 9.9065, trnd: 0.7834, depG: 3.0248, /dpc: 1.17,
c Conflict|tASG: 0.9294, cLvl: 16.08, bLvl: 14.93, /ppc: 56.35,
c misc|vivC: 90, subC: 0, core: 125, /cpr: 2900.25,
c Strategy|mode: generic, time: 251.07,
c
c config::ChronoBtThreshold 100
c config::ClauseRewardDecayRate 0.95
c config::InprocessorInterval 10000
c config::RestartAsgThreshold 0.6
c config::RestartLbdThreshold 1.6
c config::VarRewardDecayRate 0.94
c assign::NumConflict 2402204
c assign::NumDecision 4410993
c assign::NumPropagation 129058093
c assign::NumRephase 56
c assign::NumRestart 3656
c assign::NumVar 360
c assign::NumAssertedVar 0
c assign::NumEliminatedVar 9
c assign::NumUnassertedVar 351
c assign::NumUnassignedVar 351
c assign::NumUnreachableVar 0
c assign::RootLevel 0
c assign::DecisionPerConflict 1.168
c assign::PropagationPerConflict 56.349
c assign::ConflictPerRestart 2944.588
c assign::ConflictPerBaseRestart 2944.588
c assign::BestPhaseDivergenceRate 0.187
c clause::NumBiClause 2
c clause::NumBiClauseCompletion 0
c clause::NumBiLearnt 2
c clause::NumClause 71710
c clause::NumLBD2 613
c clause::NumLearnt 70187
c clause::NumReduction 88
c clause::NumReRegistration 0
c clause::Timestamp 2402204
c clause::DpAverageLBD 3.025
c processor::NumFullElimination 90
c processor::NumSubsumedClause 0
c restart::NumBlock 0
c restart::NumCycle 5
c restart::NumRestart 3656
c restart::NumStage 88
c restart::IntervalScale 1
c restart::IntervalScaleMax 32
c state::NumDecisionConflict 1209918
c state::NumProcessor 89
c state::Vivification 89
c state::VivifiedClause 861
c state::VivifiedVar 0
c state::BackjumpLevel 14.934
c state::ConflictLevel 16.077
c
s SATISFIABLE
v 1 -2 3 4 5 6 -7 -8 9 -10 -11 -12 13 -14 ... -360 0
plain
$ dmcr cnfs/unif-k3-r4.25-v360-c1530-S1293537826-039.cnf
A valid assignment set for cnfs/unif-k3-r4.25-v360-c1530-S1293537826-039.cnf is found in ans_unif-k3-r4.25-v360-c1530-S1293537826-039.cnf
If you want to certificate unsatisfiability, use --certify
or -c
and use proof checker like Grid.
plain
$ splr -c cnfs/unif-k3-r4.25-v360-c1530-S1028159446-096.cnf
unif-k3-r4.25-v360-c1530-S1028159446-096.cnf 360,1530 |time: 129.90
#conflict: 1752264, #decision: 2887321, #propagate: 90608546
Assignment|#rem: 350, #fix: 2, #elm: 8, prg%: 2.7778
Clause|Remv: 214899, LBD2: 652, BinC: 491, Perm: 1974
Restart|#BLK: 0, #RST: 4467, *scl: 1, sclM: 32
LBD|avrg: 2.0147, trnd: 0.2924, depG: 2.2306, /dpc: 1.05
Conflict|tASG: 0.9935, cLvl: 7.65, bLvl: 6.52, /ppc: 49.02
misc|vivC: 690, subC: 0, core: 350, /cpr: 882.87
Result|file: ./ans_unif-k3-r4.25-v360-c1530-S1028159446-096.cnf
Certificate|file: proof.drat
s UNSATISFIABLE: cnfs/unif-k3-r4.25-v360-c1530-S1028159446-096.cnf
```plain $ gratgen cnfs/unif-k3-r4.25-v360-c1530-S1028159446-096.cnf proof.drat -o proof.grat roof.gratgratgen cnfs/unif-k3-r4.25-v360-c1530-S1028159446-096.cnf proof.drat c sizeof(cdbt) = 4 c sizeof(cdbt*) = 8 c Using RAT run heuristics c Parsing formula ... 1ms c Parsing proof (ASCII format) ... 13977ms c Forward pass ... 1671ms c Starting Backward pass c Single threaded mode c Waiting for aux-threads ...done c Lemmas processed by threads: 1560280 mdev: 0 c Finished Backward pass: 56677ms c Writing combined proof ... 15791ms s VERIFIED c Timing statistics (ms) c Parsing: 13979 c Checking: 58371 c * bwd: 56677 c Writing: 15791 c Overall: 88168 c * vrf: 72377
c Lemma statistics c RUP lemmas: 1560280 c RAT lemmas: 0 c RAT run heuristics: 0 c Total lemmas: 1560280
c Size statistics (bytes) c Number of clauses: 1762685 c Clause DB size: 128927268 c Item list: 52911152 c Pivots store: 8388608 ```
gratchk
.plain
$ gratchk unsat cnfs/unif-k3-r4.25-v360-c1530-S1028159446-096.cnf proof.grat
Since 0.4.0, you can use Splr in your programs.
```rust use splr::*; use std::convert::TryFrom;
fn main() {
let v: Vec
```rust use splr::*; use std::{convert::TryFrom, env::args};
fn main() {
let cnf = args().nth(1).expect("takes an arg");
let assigns: Vec
fn run(cnf: &str, assigns: &[i32]) -> usize {
let mut solver = Solver::tryfrom(cnf).expect("panic at loading a CNF");
for n in assigns.iter() {
solver.addassignment(*n).expect("panic at assertion");
}
let mut count = 0;
loop {
match solver.solve() {
Ok(Certificate::SAT(ans)) => {
count += 1;
println!("s SATISFIABLE({}): {:?}", count, ans);
let ans = ans.iter().map(|i| -i).collect::
Since 0.4.1, Solver
has iter()
. So you can iterate on satisfiable 'solution: Vec<i32>
's as:
```rust
for (i, v) in Solver::try_from(cnf).expect("panic").iter().enumerate() { println!("{}-th answer: {:?}", i, v); } ```
| mnemonic | meaning |
| ------------ | ----------------------------------------------------------------------------------------- |
| #var
| the number of variables used in the given CNF file |
| #cls
| the number of clauses used in the given CNF file |
| time
| elapsed CPU time in seconds (or wall-clock time if CPU time is not available) |
| #conflict
| the number of conflicts |
| #decision
| the number of decisions |
| #propagate
| the number of propagates (its unit is literal) |
| #rem
| the number of remaining variables |
| #fix
| the number of asserted variables (which has been assigned a value at decision level zero) |
| #elm
| the number of eliminated variables |
| prg%
| the percentage of remaining variables / total variables
|
| Remv
| the current number of learnt clauses that are not bi-clauses |
| LBD2
| the accumulated number of learnt clauses which LBDs are 2 |
| BinC
| the current number of binary learnt clauses |
| Perm
| the current number of given clauses and binary learnt clauses |
| #BLK
| the number of blocking restarts |
| #RST
| the number of restarts |
| *scl
| the scaling factor for restart interval used in Luby stabilization |
| sclM
| the largest scaling factor so far |
| avrg
| the EMA, Exponential Moving Average, of LBD of learnt clauses |
| trnd
| the current trend of the LBD's EMA |
| depG
| the EMA of LBD of the clauses used in conflict analysis |
| /dpc
| the EMA of decisions per conflict |
| tASG
| the current trend of the number of assigned vars after restart |
| cLvl
| the EMA of decision levels at which conflicts occur |
| bLvl
| the EMA of decision levels to which backjumps go |
| /ppc
| the EMA of propagations per conflict |
| vivC
| the number of the vivified clauses |
| subC
| the number of the clauses subsumed by clause elimination processor |
| core
| the number of unreachable vars |
| /cpr
| the EMA of conflicts per restart |
| mode
| Selected strategy's id |
| time
| the elapsed CPU time in seconds |
```plain $ splr --help A modern CDCL SAT solver in Rust Activated features: best phase tracking, binary clause completion, clause elimination, clause vivification, Learning-Rate based rewarding, Luby stabilization, reason side rewarding, stage-based rephase
USAGE:
splr [FLAGS] [OPTIONS]
--ral
Splr-0.11.0 adopts the following features by default:
As shown in the blow, Splr calls in-processor very frequently.
Luby stabilization is an original mechanism to make long periods without restarts, which are called stabilized modes. This method updates the restart interval, which usually has a constant value, as follows:
restart_interval = luby(n) * base_interval;
where n
represents the number of updates, and luby(n)
is a function returning n-th number of Luby series.
The longer the solver searches, the larger the average value is. So we can periodically explore the search space more deeply.
Here is an example.
Note: the mechanism explained here is different from that used in Splr-0.10.0.
[1] G. Audemard and L. Simon, "Predicting learnt clauses quality in modern SAT solvers," in International Joint Conference on Artificial Intelligence 2009, pp. 399–404, 2009.
[2] G. Audemard and L. Simon, "Refining restarts strategies for SAT and UNSAT," in Lecture Notes in Computer Science, vol.7513, pp.118–126, 2012.
[3] J. H. Liang, V. Ganesh, P. Poupart, and K. Czarnecki, "Learning Rate Based Branching Heuristic for SAT Solvers," in Lecture Notes in Computer Science, vol.9710, pp.123–140, 2016.
[4] A. Nadel and V. Ryvchin, "Chronological Backtracking," in Theory and Applications of Satisfiability Testing - SAT 2018, June 2018, pp.111–121, 2018.
[5] C. Piette, Y. Hamadi, and L. Saïs, "Vivifying propositional clausal formulae," Front. Artif. Intell. Appl., vol.178, pp.525–529, 2008.
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
2020-2021, Narazaki Shuji