Git Product home page Git Product logo

splr's Introduction

A modern SAT Solver for Propositional Logic in Rust

Splr is a modern SAT solver in Rust, based on Glucose 4.1. It adopts, or adopted, various research results on modern SAT solvers:

  • CDCL, watch literals, LBD and so on from Glucose, Minisat and the ancestors
  • Luby series based restart control
  • Glucose-like dynamic blocking/forcing restarts
  • pre/in-processor to simplify the given CNF
  • branching variable selection based on Learning Rate Based Branching with Reason Side Rewarding or EVSIDS
  • CaDiCaL-like extended phase saving
  • restart stabilization inspired by CadiCaL
  • clause vivification
  • trail saving

Many thanks to SAT researchers.

Please check ChangeLog about recent updates.

Correctness

Though Splr comes with ABSOLUTELY NO WARRANTY, I'd like to show some results.

Version 0.17.0

Install

Just run cargo install splr after installing the latest cargo. Two executables will be installed:

  • splr -- the solver
  • dmcr -- a very simple model checker to verify a satisfiable assignment set generated by splr.

Alternatively, Nix users can use nix build.

About no_std environment and feature no_IO

If you want to build a library for no_std environment, or if you want to compile with feature no_IO, you have to run cargo build --lib --features no_IO. They are incompatible with cargo install.

  • [2024-02-03] Feature platform_wasm was added.

Usage

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.

$ splr cnfs/unif-k3-r4.25-v360-c1530-S1293537826-039.cnf
unif-k3-r4.25-v360-c1530-S1293537826-039.cnf       360,1530 |time:   732.01
 #conflict:    9663289, #decision:     23326959, #propagate:      546184944
  Assignment|#rem:      351, #fix:        0, #elm:        9, prg%:   2.5000
      Clause|Remv:    69224, LBD2:     2857, BinC:        1, Perm:     1522
    Conflict|entg:   7.0499, cLvl:  12.2451, bLvl:  11.1030, /cpr:    30.74
    Learning|avrg:  10.4375, trnd:   1.0069, #RST:   566140, /dpc:     1.18
        misc|vivC:     7370, subC:        0, core:      122, /ppc:    61.53
      Result|file: ./ans_unif-k3-r4.25-v360-c1530-S1293537826-039.cnf
s SATISFIABLE: cnfs/unif-k3-r4.25-v360-c1530-S1293537826-039.cnf
$ cat ans_unif-k3-r4.25-v360-c1530-S1293537826-039.cnf
c This file was generated by splr-0.15.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:    9663289, #decision:     23326959, #propagate:      546184944,
c   Assignment|#rem:      351, #fix:        0, #elm:        9, prg%:   2.5000,
c       Clause|Remv:    69224, LBD2:     2857, BinC:        1, Perm:     1522,
c     Conflict|entg:   7.0499, cLvl:  12.2451, bLvl:  11.1030, /cpr:    30.74,
c      Learing|avrg:  10.4375, trnd:   1.0069, #RST:   566140, /dpc:     1.18,
c         misc|vivC:     7370, subC:        0, core:      122, /ppc:    61.53,
c     Strategy|mode:  generic, time:   732.03,
c
c   config::VarRewardDecayRate                       0.960
c   assign::NumConflict                        9663289
c   assign::NumDecision                       23326959
c   assign::NumPropagation                   546184944
c   assign::NumRephase                             734
c   assign::NumRestart                          566141
c   assign::NumVar                                 360
c   assign::NumAssertedVar                           0
c   assign::NumEliminatedVar                         9
c   assign::NumReconflict                          653
c   assign::NumRepropagation                  12460396
c   assign::NumUnassertedVar                       351
c   assign::NumUnassignedVar                       351
c   assign::NumUnreachableVar                        0
c   assign::RootLevel                                0
c   assign::AssignRate                               0.000
c   assign::DecisionPerConflict                      1.179
c   assign::PropagationPerConflict                  61.527
c   assign::ConflictPerRestart                     122.388
c   assign::ConflictPerBaseRestart                 122.388
c   assign::BestPhaseDivergenceRate                  0.000
c   clause::NumBiClause                              1
c   clause::NumBiClauseCompletion                    0
c   clause::NumBiLearnt                              1
c   clause::NumClause                            70746
c   clause::NumLBD2                               2857
c   clause::NumLearnt                            69224
c   clause::NumReduction                          1461
c   clause::NumReRegistration                        0
c   clause::Timestamp                                0
c   clause::LiteralBlockDistance                    10.438
c   clause::LiteralBlockEntanglement                 7.050
c   state::Vivification                            735
c   state::VivifiedClause                         7370
c   state::VivifiedVar                               0
c   state::NumCycle                                734
c   state::NumStage                               1461
c   state::IntervalScale                             1
c   state::IntervalScaleMax                       1024
c   state::BackjumpLevel                            11.103
c   state::ConflictLevel                            12.245
c
s SATISFIABLE
v 1 -2 3 4 5 6 -7 -8 9 -10 -11 -12 13 -14 ...  -360 0
$ 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.

Firstly run splr with the certificate option -c.

$ splr -c cnfs/unif-k3-r4.25-v360-c1530-S1028159446-096.cnf
unif-k3-r4.25-v360-c1530-S1028159446-096.cnf       360,1530 |time:   204.09
 #conflict:    4018458, #decision:      9511129, #propagate:      221662222
  Assignment|#rem:      345, #fix:        7, #elm:        8, prg%:   4.1667
      Clause|Remv:    11290, LBD2:     2018, BinC:      137, Perm:     1517
    Conflict|entg:   4.5352, cLvl:   8.0716, bLvl:   6.9145, /cpr:   112.08
    Learning|avrg:   1.5625, trnd:   0.2219, #RST:   237295, /dpc:     1.07
        misc|vivC:     4085, subC:        0, core:      345, /ppc:    52.55
      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

A: Verify with drat-trim

$ drat-trim cnfs/unif-k3-r4.25-v360-c1530-S1028159446-096.cnf proof.drat
c parsing input formula with 360 variables and 1530 clauses
c finished parsing
c detected empty clause; start verification via backward checking
c 1530 of 1530 clauses in core
c 2036187 of 4029964 lemmas in core using 68451907 resolution steps
c 0 RAT lemmas in core; 908116 redundant literals in core lemmas
s VERIFIED
c verification time: 105.841 seconds

B: Verify with gratchk

Firstly you have to convert the generated DRAT file to a GRAT file.

$ gratgen cnfs/unif-k3-r4.25-v360-c1530-S1028159446-096.cnf proof.drat -o proof.grat
c sizeof(cdb_t) = 4
c sizeof(cdb_t*) = 8
c Using RAT run heuristics
c Parsing formula ... 1ms
c Parsing proof (ASCII format) ... 32251ms
c Forward pass ... 2073ms
c Starting Backward pass
c Single threaded mode

0%   10   20   30   40   50   60   70   80   90   100%
|----|----|----|----|----|----|----|----|----|----|
***************************************************
c Waiting for aux-threads ...done
c Lemmas processed by threads: 2032698 mdev: 0
c Finished Backward pass: 65356ms
c Writing combined proof ... 19088ms
s VERIFIED
c Timing statistics (ms)
c Parsing:  32253
c Checking: 67465
c   * bwd:  65356
c Writing:  19088
c Overall:  118808
c   * vrf:  99720

c Lemma statistics
c RUP lemmas:  2032698
c RAT lemmas:  0
c   RAT run heuristics:   0
c Total lemmas:  2032698

c Size statistics (bytes)
c Number of clauses: 4031493
c Clause DB size:  309680252
c Item list:       128778112
c Pivots store:    16777216

Then verify it with gratchk.

$ gratchk unsat cnfs/unif-k3-r4.25-v360-c1530-S1028159446-096.cnf proof.grat
c Reading cnf
c Reading proof
c Done
c Verifying unsat
s VERIFIED UNSAT

Calling Splr from Rust programs

Since 0.4.0, you can use Splr in your programs. (Here I suppose that you uses Rust 2021.)

use splr::*;

fn main() {
    let v: Vec<Vec<i32>> = vec![vec![1, 2], vec![-1, 3], vec![1, -3], vec![-1, 2]];
    match Certificate::try_from(v) {
        Ok(Certificate::SAT(ans)) => println!("s SATISFIABLE: {:?}", ans),
        Ok(Certificate::UNSAT) => println!("s UNSATISFIABLE"),
        Err(e) => panic!("s UNKNOWN; {}", e),
    }
}

All solutions SAT solver as an application of 'incremental_solver' feature

The following example requires 'incremental_solver' feature. You need the following dependeny:

splr = { version = "^0.17", features = ["incremental_solver"] }

Under this configuration, module splr provides some more functions:

  • splr::Solver::reset(&mut self)
  • splr::Solver::add_var(&mut self) // increments the last variable number
  • splr::Solver::add_clause(&mut self, vec: AsRef<[i32]>) -> Result<&mut Solver, SolverError>

You have to call reset before calling add_var, add_clause, and solve again. By this, splr forgets everything about the previous formula, especially non-equivalent transformations by pre/inter-processors like clause subsumbtion. So technically splr is not an incremental solver.

'add_clause' will emit an error if vec is invalid.

use splr::*;
use std::env::args;

fn main() {
    let cnf = args().nth(1).expect("takes an arg");
    let assigns: Vec<i32> = Vec::new();
    println!("#solutions: {}", run(&cnf, &assigns));
}

#[cfg(feature = "incremental_solver")]
fn run(cnf: &str, assigns: &[i32]) -> usize {
    let mut solver = Solver::try_from(cnf).expect("panic at loading a CNF");
    for n in assigns.iter() {
        solver.add_assignment(*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::<Vec<i32>>();
                match solver.add_clause(ans) {
                    Err(SolverError::Inconsistent) => {
                        println!("c no answer due to level zero conflict");
                        break;
                    }
                    Err(e) => {
                        println!("s UNKNOWN; {:?}", e);
                        break;
                    }
                    Ok(_) => solver.reset(),
                }
            }
            Ok(Certificate::UNSAT) => {
                println!("s UNSATISFIABLE");
                break;
            }
            Err(e) => {
                println!("s UNKNOWN; {}", e);
                break;
            }
        }
    }
    count
}

Since 0.4.1, Solver has iter(). So you can iterate on satisfiable 'solution: Vec<i32>'s as:

#[cfg(feature = "incremental_solver")]
for (i, v) in Solver::try_from(cnf).expect("panic").iter().enumerate() {
    println!("{}-th answer: {:?}", i, v);
}

sample code from my sudoku solver

https://github.com/shnarazk/sudoku_sat/blob/4490b4358e5f3b72803a566323a6c8c196627f92/src/bin/sudoku400.rs#L36-L60

    let mut solver = Solver::try_from((config, rules.as_ref())).expect("panic");
    for a in setting.iter() {
        solver.add_assignment(*a).expect("panic");
    }
    for ans in solver.iter().take(1) {
        let mut picked = ans.iter().filter(|l| 0 < **l).collect::<Vec<&i32>>();
        for _i in 1..=range {
            for _j in 1..=range {
                let (_i, _j, d, _b) = Cell::decode(*picked.remove(0));
                print!("{:>2} ", d);
            }
            println!();
        }
        println!();
    }
}

Mnemonics used in the progress message

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
entg the current average of 'Literal Block entanglement'
cLvl the EMA of decision levels at which conflicts occur
bLvl the EMA of decision levels to which backjumps go
/cpr the EMA of conflicts per restart
avrg the EMA, Exponential Moving Average, of LBD of learnt clauses
trnd the current trend of the LBD's EMA
#RST the number of restarts
/dpc the EMA of decisions 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
/ppc the EMA of propagations per conflict
time the elapsed CPU time in seconds

Command line options

A modern CDCL SAT solver in Rust
Activated features: best phase tracking, stage-based clause elimination, stage-based clause vivification, stage-based dynamic restart threshold, Learning-Rate Based rewarding, reason-side rewarding, stage-based re-phasing, two-mode reduction, trail saving, unsafe access

USAGE:
  splr [FLAGS] [OPTIONS] <cnf-file>
FLAGS:
  -h, --help                Prints help information
  -C, --no-color            Disable coloring
  -q, --quiet               Disable any progress message
  -c, --certify             Writes a DRAT UNSAT certification file
  -j, --journal             Shows log about restart stages
  -l, --log                 Uses Glucose-like progress report
  -V, --version             Prints version information
OPTIONS:
      --cl <c-cls-lim>      Soft limit of #clauses (6MC/GB)         0
      --crl <cls-rdc-lbd>   Clause reduction LBD threshold          5
      --cr1 <cls-rdc-rm1>   Clause reduction ratio for mode1        0.20
      --cr2 <cls-rdc-rm2>   Clause reduction ratio for mode2        0.05
      --ecl <elm-cls-lim>   Max #lit for clause subsume            64
      --evl <elm-grw-lim>   Grow limit of #cls in var elim.         0
      --evo <elm-var-occ>   Max #cls for var elimination        20000
  -o, --dir <io-outdir>     Output directory                         .
  -p, --proof <io-pfile>    DRAT Cert. filename                 proof.drat
  -r, --result <io-rfile>   Result filename/stdout
  -t, --timeout <timeout>   CPU time limit in sec.               5000
      --vdr <vrw-dcy-rat>   Var reward decay rate                   0.96
ARGS:
  <cnf-file>    DIMACS CNF file

Solver description

Splr-0.17.0 adopts the following features by default:

  • Learning-rate based (LRB) var rewarding and clause rewarding[4]
  • Reason-side var rewarding[4]
  • chronological backtrack[5] disabled since 0.12 due to incorrect UNSAT certificates.
  • clause vivification[6]
  • Luby series based on the number of conflicts defines 'stages/cycles/segments', which are used as trigger of
    • restart
    • clause reduction
    • in-processor (clause elimination, subsumption and vivification)
    • re-configuration of var phases and var activities
    • re-configuration of trail saving extended with reason refinement based on clause quality[3].

(Splr-0.15.0 and upper try to discard various dynamic and heuristic-based control schemes used in the previous versions.)

The following figure explains the flow used in the latest Splr.

search algorithm in Splr 0.17

I use the following terms here:

  • a stage -- a span in which solver uses the same restart parameters
  • a cycle -- a group of continuos spans of which the corresponding Luby values make a non-decreasing sequence
  • a segment -- a group of continuos cycles which are separated by new maximum Luby values' occurrences

Bibliography

  • [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 LNCS, vol.7513, pp.118–126, 2012.

  • [3] R. Hickey and F. Bacchus, "Trail Saving on Backtrack", SAT 2020, LNCS, vol. 12178, pp.46-61, 2020.

  • [4] J. H. Liang, V. Ganesh, P. Poupart, and K. Czarnecki, "Learning Rate Based Branching Heuristic for SAT Solvers," in LNCS, vol.9710, pp.123–140, 2016.

  • [5] A. Nadel and V. Ryvchin, "Chronological Backtracking," in Theory and Applications of Satisfiability Testing - SAT 2018, June 2018, pp.111–121, 2018.

  • [6] C. Piette, Y. Hamadi, and L. Saïs, "Vivifying propositional clausal formulae," Front. Artif. Intell. Appl., vol.178, pp.525–529, 2008.

License

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-2024, Narazaki Shuji

splr's People

Contributors

ongardie avatar shnarazk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

splr's Issues

non-deterministic behavior in Rust program

Why the execution process without parallelism, timer, hash, and so no, isn't deterministic?

  • cand1: unsafe accesses exceed boundary.

HashMap::iter() the source.

  • best_phase.iter()
  • bi_clause_map.iter()

Make Var's footprint smaller!

Objectivte

From experiments, acb7930 and 8036598, I found that the size of 'struct' is crucial! So do
For better modularity,

  • disconnect eliminator's data, namely Var::{pos_neg}_occurs from Var.
  • move Var::phase into Var::flags

Too big restart threshold stops updating stabilization modes

Reproduce

  • SC21/mp1-klieber2017s-0300-034-t12.cnf

How to fix

  • If the average real interval at baseline stabilization mode is too long, it's the trigger to reduce Config::rst_lbd_thr.
  • no restart in a stabilization mode. 👎
  • no restart in a stabilization phase. 👎
  • refactor codes on stabilization in search

Replace list append operation with in-place update operation under the hood

List append takes O(n).

  • separate the container into pure iterator and the referred container itself.

Let's define an extended iterator on usize range.

  1. iterator is (0..watch_cache.len())
  2. push_back is iterator::push_back(), which decrement the internal counter.
  3. For checking termination, define iterator::shorten(), which decrement the internal loop-limit.
  4. This is called WatchListInplaceUpdateIF.

Adaptive var rewarding

Should run some trials:

  • time-based increase/decrease
  • decision level based increase/decrease
  • a criteron about stagntation

Correctness of the model extender

The glucose version (much readable!)

evoid SimpSolver::extendModel()
{
    int i, j;
    Lit x;

    if(model.size()==0) model.growTo(nVars());

    for (i = elimclauses.size()-1; i > 0; i -= j){
        for (j = elimclauses[i--]; j > 1; j--, i--)
            if (modelValue(toLit(elimclauses[i])) != l_False)
                goto next;

        x = toLit(elimclauses[i]);
        model[var(x)] = lbool(!sign(x));
    next:;
    }
}

splr's version

    fn extend_model<C>(&mut self, cdb: &mut C, lits: &[Lit]) -> Vec<Option<bool>>
    where
        C: ClauseDBIF,
    {
        let mut extended_model: Vec<Option<bool>> = self.assign.clone();
        if lits.is_empty() {
            return extended_model;
        }
        let mut i = lits.len() - 1;
        let mut width;
        'next: loop {
            width = usize::from(lits[i]);
            if width == 0 && i == 0 {
                break;
            }
            i -= 1;
            loop {
                if width <= 1 {
                    break;
                }
                let l = lits[i];
                if extended_model[l.vi()] != Some(!bool::from(l)) {
                    if i < width {
                        break 'next;
                    }
                    i -= width;
                    continue 'next;
                }
                width -= 1;
                i -= 1;
            }
            let l = lits[i];
            extended_model[l.vi()] = Some(bool::from(l));
            if i < width {
                break;
            }
            i -= width;
        }
        extended_model
    }

No restart for LR and Stabilization

  • LR doesn't need to restart in order to get more conflicts.
  • Stabilization doesn't (or seldom) need to restart for solve SAT problems.

So?

So far

  • There's an exploit and/or explorer problem.

Literal Container

To simulate arena in CaDiCal, how about:

type LitContainer = Vec<Vec<Lit>>;

struct Clause {
    mainLiteral: (Lit, usize),
   ...
}

impl Clause {
   fn lits(&mut self, lc: &mut LitContainer) -> &mut [Lit] {
       let (primaryLit, index) = self.mainLiteal;
       &mut LitContainer[primaryLit][index, index + self.len]
}

struct WatchList {
    watch: Vec<Watch>,
    clause: Vec<ClauseId>,
}

By collecting literals of which clauses have the same literal, which should be a (negated) watching literal for those clauses, propagate can scan consecutive memory. It's an arena.

Access to a clause from the other watching literal has the same cost as the present implementation. But we can halve the number of random access.

trail may contain a non-assigned var

aes.cnf                                      501284,2928183 |time:   208.37
 #conflict:     385764, #decision:      1347502, #propagate:       77619923
  Assignment|#rem:    16082, #ass:   237004, #elm:   248198, prg%:  96.7918
      Clause|Remv:   113716, LBD2:     5233, Binc:    11134, Perm:   759855
     Restart|#BLK:      603, #RST:      633, trgr:       32, peak:       16
         LBD|avrg:  20.3615, trnd:   1.7357, depG:   3.4696, /dpc:     1.42
    Conflict|tASG:   1.4218, cLvl:   362.30, bLvl:   360.21, /ppc:   142.90
        misc|elim:       11, #sub:   100407, core:        4, /cpr:  1764.98
thread 'main' panicked at 'elimitator350: 
Clause {
  lits: [
    Lit { ordinal: 33640 },
    Lit { ordinal: 132781 },
    Lit { ordinal: 132780 },
    Lit { ordinal: 130929 },
    Lit { ordinal: 126008 }
  ],
  rank: 2, search_from: 2, reward: 0.050000000000000044, timestamp: 396734, 
  flags: LEARNT | VIVIFIED }', src/processor/eliminator.rs:349:13

A bug about ChroneBT

Story

I misimplemented backjump when there is one literal at the highest level when a conflict occurs.
Before I found the bug, the implementation tried to backtrack to the 2nd level - 1 and assigned the conflicting literal as a decision variable. This might cause an infinite assign-backtrack loop.
Actually, it should backtrack to the 2nd level and assign that by implication.
And this requires updating watches correctly. That was the missing part.

Some transition fails to update watch literal pairs rigidly

aes.cnf                                      501284,2928183 |time:    23.05
 #conflict:       1632, #decision:        23381, #propagate:        2161454
  Assignment|#rem:   109460, #ass:   221238, #elm:   170586, prg%:  78.1641
      Clause|Remv:      910, LBD2:      199, Binc:   570062, Perm:  1137043
     Restart|#BLK:        0, #RST:       58, trgr:        8, peak:        4
         LBD|avrg:   5.4365, trnd:   8.0095, depG:   0.3028, /dpc:    10.20
    Conflict|tASG:   5.0980, cLvl:    21.97, bLvl:    19.96, /ppc:   864.35
        misc|proc:        2, #sub:    80682, core:    87799, /cpr:     8.33
thread 'main' panicked at 'assertion failed: 
cached == cdb[cid].lit0() || cached == cdb[cid].lit1()', 
src/assign/propagate.rs:359:17

It's by elimination.

UNSAT certificate still broken

$ drat-trim ../SC/HCP-470-60.cnf HCP-470-60.drat
c parsing input formula with 28840 variables and 234244 clauses
c finished parsing
c detected empty clause; start verification via backward checking
c WARNING: RAT check on proof pivot failed : [2189605] -5760 0
c RAT check failed on all possible pivots
c failed at proof line 1424930 (modulo deletion errors)

s NOT VERIFIED
c verification time: 3.462 seconds
$ ucpc ../SC/rphp4_065_shuffled.cnf 5000
rphp4_065_shuffled.cnf                             520,6959 |time:   423.51
 #conflict:    2183629, #decision:     33782050, #propagate:      141957763
  Assignment|#rem:      469, #fix:        0, #elm:       51, prg%:   9.8077
      Clause|Remv:  1462086, LBD2:       36, BinC:      673, Perm:     6957
     Restart|#BLK:     1876, #RST:   224852, *scl:        2, sclM:       16
         LBD|trnd:   0.2425, avrg:   5.8213, depG:   9.1974, /dpc:    14.42
    Conflict|tASG:   1.0542, cLvl:    58.58, bLvl:    44.60, /ppc:    48.81
        misc|vivC:     1402, subC:       23, core:        5, /cpr:    19.28
thread 'main' panicked at 'assertion failed: 0 < second_level', src/solver/conflict.rs:58:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

trail may contain a literal doublly

89cf2ea1@20210417-revert-vivification*$ splr -t 50000 aes.cnf                                                                    
aes.cnf                                      501284,2928183 |time:   539.50
 #conflict:    1097515, #decision:      3370284, #propagate:      209606850
  Assignment|#rem:    13314, #ass:   239360, #elm:   248610, prg%:  97.3440
      Clause|Remv:   153494, LBD2:     8297, Binc:    15084, Perm:   743864
     Restart|#BLK:     1138, #RST:     1113, trgr:        1, peak:       32
         LBD|avrg:  25.0436, trnd:   1.5164, depG:   3.1491, /dpc:     2.48
    Conflict|tASG:   0.9368, cLvl:   357.19, bLvl:   355.09, /ppc:   580.76
        misc|elim:       21, #sub:   102798, core:        4, /cpr:  2007.61
clause vivifying(assert:0, purge:0 shorten:43, check:8000/29049)...thread 'main' panicked a
t 'called `Option::unwrap()` on a `None` value', src/assign/propagate.rs:212:54
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
zsh: abort      splr -t 50000 aes.cnf

Clause with positive and negative literals

$ splr -t 10000 aes.cnf                      
aes.cnf                                      501284,2928183 |time:   329.19
 #conflict:     564576, #decision:      1872059, #propagate:      114753356
  Assignment|#rem:    13410, #ass:   239528, #elm:   248346, prg%:  97.3249
      Clause|Remv:   127032, LBD2:     6550, Binc:     7881, Perm:   739395
     Restart|#BLK:      616, #RST:      871, trgr:        1, peak:       32
         LBD|avrg:  15.4201, trnd:   1.1346, depG:   3.7786, /dpc:     1.51
    Conflict|tASG:   0.7515, cLvl:   454.38, bLvl:   452.98, /ppc:   107.88
        misc|elim:       15, #sub:   101300, core:        4, /cpr:  2236.73
thread 'main' panicked at 'assertion failed: pos.iter().all(|x| *x != *cid)', src/process
or/eliminate.rs:138:17 

RAT-check failed

The resolution goal

  • 1st pass T56
  • 2nd pass T56
  • 3rd pass T56
  • 1st pass unif-k3-r4.25-v360-c1530-S1028159446-096.cnf
  • 2nd pass unif-k3-r4.25-v360-c1530-S1028159446-096.cnf
T56.2.0.cnf                                3145220,10854665 |time:   447.85
 #conflict:     233481, #decision:      2234694, #propagate:      861887802
  Assignment|#rem:   541433, #ass:    15502, #elm:  2588285, prg%:  82.7855
      Clause|Remv:    74792, LBD2:     8800, Binc:   563808, Perm:  3351710
     Restart|#BLK:       71, #RST:     2179, trgr:        1, peak:       32
         LBD|avrg:   2.7393, trnd:   0.3095, depG:   2.4767, /dpc:     1.54
    Conflict|tASG:   1.0955, cLvl:    44.72, bLvl:    41.27, /ppc:  6004.12
        misc|proc:       11, #sub:   951539, core:   541433, /cpr:   118.02
      Result|file: ./ans_T56.2.0.cnf
 Certificate|file: T56.2.0.drat
s UNSATISFIABLE: ../SC/T56.2.0.cnf
c sizeof(cdb_t) = 4
c sizeof(cdb_t*) = 8
c Using RAT run heuristics
c Parsing formula ... 15455ms
c Parsing proof (ASCII format) ... 71882ms
c Forward pass ... 5943ms
c Starting Backward pass
c Single threaded mode
c FAILED: RAT-check failed
s ERROR

Recurring Conflict Complexity

Objective

Restart if the present 'path' is a part of a too complex network. It's a derivation of #7.

Branches

I've learned so far

  • It's not an alternative to the LBD threshold.
  • Rather a kind of var reward.

Tried

  • adaptive threshold on the frequency of being conflict
    • reset by a new level 0 assignment
  • Ema based threshold on the recent average of the frequency of recurring conflict
  • used as a restart condition on conflict paths.
  • used as a coefficient for LBD threshold in order to be tolerant of 'bad' learnt on a 'hard' path.
    Since the development of path expansion isn't a Markov process, we can't estimate ... well, what?
  • used as a reward for variables; reward should be given to variables that emit or have emitted conflicts. So RCC should be such a weighted criterion.

splr as a library

I would like to use SPLR as a library to solve SAT problems created dynamically without writing it to a file. I particular, this would allow me to embed a SAT solver in a WASM application where there is no file system at all. Is this possible? I do not see any interface to create a SAT instance (add variables and clauses).

Revert to the original CHB or LRB

Objective

Splr-0.2.1's main ordering heuristics wasn't CHB! Bogus! I need to investigate CHB again with more clever eyes.

Reference

  • Liang, J. H., Ganesh, V., Poupart, P., & Czarnecki, K.: Exponential Recency Weighted Average Branching Heuristic for SAT Solvers, 2016.

VSIDS decays the activities of all variables whereas CHB again only decays the Q scores of branched, propagated, and asserted variables.

  • Liang, J. H., Ganesh, V., Poupart, P. & Czarnecki, K.: Learning Rate Based Branching Heuristic for SAT Solvers, 2016.

branches

So far

  • Even after checking and modifying most part of the program, it still gets bad performance on UNSAT problems, compared with EVISDS. How about extending restart steps by multiplying with FOC, because UNSAT problems have (small) UNSAT cores that we should focus on? This also might be evidence that deep search works well.
  • We can't change misc settings on adaptive_restart and deep_search. The present is ever the best.
  • Reason-Side Rewarding can improve performance.
  • Tiny change rates of var activity are very good for 3SAT problems since they tend to fix the order of var selections. This means the effects of restart is reduced and so it's likely to execute exhaustive search instead of random jumping.

Comparison target

dev-0.2.2

# ~/.cargo/bin/splr (splr 0.2.2-dev.0) @ 2020-01-05T10:37:14
solver,       num,                 target,    time
"splr",         1,           "UF250(100)", 144.184
"splr",         2,          "UUF250(100)", 361.036
"splr",         3, "3/SAT/v360-c1530/002", 195.049
"splr",         4, "3/SAT/v360-c1530/030", 243.745
"splr",         5, "3/SAT/v360-c1530/033",   4.581
"splr",         6, "3/SAT/v360-c1530/035",  17.230
"splr",         7, "3/SAT/v360-c1530/039",   ABORT
"splr",         8, "3/SAT/v360-c1530/051",   ABORT
"splr",         9, "3/SAT/v360-c1530/060",  20.544
"splr",        10, "3/SAT/v360-c1530/073", 228.022
"splr",        11, "3/SAT/v360-c1530/087",   0.811
"splr",        12, "3/SAT/v360-c1530/093",  29.456
"splr",        13, "3/UNS/v360-c1530/001", 474.862
"splr",        14, "3/UNS/v360-c1530/015", 257.642
"splr",        15, "3/UNS/v360-c1530/028", 433.232
"splr",        16, "3/UNS/v360-c1530/029",   ABORT
"splr",        17, "3/UNS/v360-c1530/031",   ABORT
"splr",        18, "3/UNS/v360-c1530/053", 449.915
"splr",        19, "3/UNS/v360-c1530/061",   ABORT
"splr",        20, "3/UNS/v360-c1530/086", 218.609
"splr",        21, "3/UNS/v360-c1530/089", 336.133
"splr",        22, "3/UNS/v360-c1530/096", 225.897
"splr",        23,          "SR2015/itox",   2.545
"splr",        24,          "SR2015/m283",  72.317
"splr",        25,           "SR2015/38b",   6.358
"splr",        26,           "SR2015/44b", 422.609
# ~/.cargo/bin/splr (splr 0.2.2-dev.0) @ 2019-12-29T09:21:39
solver,       num,                 target,    time
"splr",         1,           "UF250(100)", 120.159
"splr",         2,          "UUF250(100)", 367.286
"splr",         3, "3/SAT/v360-c1530/002",  91.467
"splr",         4, "3/SAT/v360-c1530/030", 278.417
"splr",         5, "3/SAT/v360-c1530/033",  11.541
"splr",         6, "3/SAT/v360-c1530/035",  14.478
"splr",         7, "3/SAT/v360-c1530/039",   ABORT
"splr",         8, "3/SAT/v360-c1530/051",   ABORT
"splr",         9, "3/SAT/v360-c1530/060",   ABORT
"splr",        10, "3/SAT/v360-c1530/073", 107.075
"splr",        11, "3/SAT/v360-c1530/087",  99.664
"splr",        12, "3/SAT/v360-c1530/093", 138.323
"splr",        13, "3/UNS/v360-c1530/001",   ABORT
"splr",        14, "3/UNS/v360-c1530/015", 327.836
"splr",        15, "3/UNS/v360-c1530/028", 486.770
"splr",        16, "3/UNS/v360-c1530/029",   ABORT
"splr",        17, "3/UNS/v360-c1530/031",   ABORT
"splr",        18, "3/UNS/v360-c1530/053", 377.727
"splr",        19, "3/UNS/v360-c1530/061",   ABORT
"splr",        20, "3/UNS/v360-c1530/086", 295.135
"splr",        21, "3/UNS/v360-c1530/089", 368.148
"splr",        22, "3/UNS/v360-c1530/096", 202.818
"splr",        23,          "SR2015/itox",   1.637
"splr",        24,          "SR2015/m283",  59.509
"splr",        25,           "SR2015/38b",  34.444
"splr",        26,           "SR2015/44b", 118.803

Lift ClauseId to a struct

Purpose

another refactoring on ClauseId which is an alias of usize

Todo

  • no performance regression

  • make fields private

  • refactor exporting/importing symbols Changing relations affects performance somehow.

  • before

solver,       num,                 target,    time
"splr",         1,           "UF250(100)", 103.478
"splr",         3,          "UUF250(100)", 356.468 
  • after inlining
"splr",         1,           "UF250(100)", 103.600
"splr",         2,          "UUF250(100)", 356.598

Revising Watch

splr/src/clause.rs

Lines 144 to 151 in 49d700a

/// 'watch literal' structure
#[derive(Clone, Debug)]
pub struct Watch {
/// a cache of a literal in the clause
pub blocker: Lit,
/// ClauseId
pub c: ClauseId,
}

// This version of 'propagate' uses lazy watches and keeps two watched
// literals at the beginning of the clause.  We also use 'blocking literals'
// to reduce the number of times clauses have to be visited (2008 JSAT paper
// by Chu, Harwood and Stuckey).  The watches know if a watched clause is
// binary, in which case it never has to be visited.  If a binary clause is
// falsified we continue propagating.

1: need to revise

splr/src/clause.rs

Lines 105 to 106 in 491537a

/// make a new 'watch', and add it to this watcher list.
fn register(&mut self, blocker: Lit, c: ClauseId);

2: register a binary clause twice to keep the literals order 👎

Since binary clause is permanent, we won’t have any problem.

if false_lit < the_pair {
  return b.c;
} else {
  return b.c + 1. // actually ClauseId doesn’t have Add trail.

3: Var::reason extends with enum AssignReason 👍

We don’t need the clause id if it’s a binary clause during conflict analysis.

Fail to propagate by (bi)clauses

case 1

$ splr aes.cnf
aes.cnf                                      501284,2928183 |time:    37.88
 #conflict:          0, #decision:        45110, #propagate:         219056
  Assignment|#rem:   330576, #ass:        0, #elm:   170708, prg%:  34.0541
      Clause|Remv:        0, LBD2:        0, Binc:  1071881, Perm:  1743759
     Restart|#BLK:        0, #RST:        0, trgr:        1, peak:        1
         LBD|avrg:   0.0000, trnd:      NaN, depG:   0.0000, /dpc:     0.00
    Conflict|tASG:      NaN, cLvl:     0.00, bLvl:     0.00, /ppc:     0.00
        misc|proc:        1, #sub:    79540, core:   501284, /cpr:     0.00
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `0`,
 right: `1`: found a strange biclause 66C
 -    -8L: Some(false) at level   0 by    Asserted at 0,  false
 -  1261L:        None at level   1 by     Not assigned,  false
', src/cdb/db.rs:1235:17

case 2

$ splr aes.cnf
aes.cnf                                      501284,2928183 |time:    36.09
 #conflict:          0, #decision:        45115, #propagate:         219056
  Assignment|#rem:   330744, #ass:        0, #elm:   170540, prg%:  34.0206
      Clause|Remv:        0, LBD2:        0, Binc:  1072019, Perm:  1744273
     Restart|#BLK:        0, #RST:        0, trgr:        1, peak:        1
         LBD|avrg:   0.0000, trnd:      NaN, depG:   0.0000, /dpc:     0.00
    Conflict|tASG:      NaN, cLvl:     0.00, bLvl:     0.00, /ppc:     0.00
        misc|proc:        1, #sub:    79557, core:   501284, /cpr:     0.00
thread 'main' panicked at 'found a strange biclause 586961C
 -   64814L: Some(false) at level   1 by Implied by B3683537C, false
 -   62087L:        None at level   2 by         Not assigned, false
', src/cdb/db.rs:1235:17

Reasons

  1. cdb.bi_clause used wrong keys to store bi-clauses.
  2. try to assert without backtack
  3. TBU

complete_bi_clauses

Fill the missing direct linkages between 2 literals automatically after generating a new bi-clause.

Eliminator found a strange clause

[89cf2ea1@20210417-revert-vivification*]$ splr -t 50000 aes.cnf
aes.cnf                                      501284,2928183 |time:   706.77
 #conflict:     918856, #decision:      3033039, #propagate:      189369619
  Assignment|#rem:    13215, #ass:   239513, #elm:   248556, prg%:  97.3638
      Clause|Remv:   115060, LBD2:     7466, Binc:     8187, Perm:   737970
     Restart|#BLK:      988, #RST:     1074, trgr:        1, peak:       32
         LBD|avrg:  47.2536, trnd:   1.1079, depG:   4.1347, /dpc:     1.32
    Conflict|tASG:   0.7825, cLvl:   316.51, bLvl:   314.63, /ppc:   340.24
        misc|elim:       18, #sub:   102947, core:        4, /cpr:  2140.75
thread 'main' panicked at 'elim.add_cid_occur found a strange negative clause5584330C{[-320719, -320719]}', src/processor/eliminator.rs:304:21
aes.cnf                                      501284,2928183 |time:   374.89
 #conflict:     568872, #decision:      2034285, #propagate:      101626873
  Assignment|#rem:    12609, #ass:   240200, #elm:   248475, prg%:  97.4847
      Clause|Remv:   141063, LBD2:     5839, Binc:    12302, Perm:   740034
     Restart|#BLK:      699, #RST:      789, trgr:        1, peak:       32
         LBD|avrg:  45.4205, trnd:   1.6897, depG:   3.0670, /dpc:     2.14
    Conflict|tASG:   1.4259, cLvl:   388.00, bLvl:   385.81, /ppc:   670.97
        misc|elim:       14, #sub:   101060, core:       19, /cpr:  1859.26
thread 'main' panicked at 
'elim.add_cid_occur for Var { index: 159986, participated: 0, reward: 0.23099639969570587, timestamp: 614387, flags: ENQUEUED }
 found a strange negative clause 4987252C{[-159986, -159986]}, 
[ClauseId { ordinal: 3464781 }, ClauseId { ordinal: 3464782 }, ClauseId { ordinal: 3468192 }, 
 ClauseId { ordinal: 3475306 }, ClauseId { ordinal: 3475307 }, ClauseId { ordinal: 3848623 },
 ClauseId { ordinal: 3848624 }, ClauseId { ordinal: 3848646 }, ClauseId { ordinal: 3848648 },
 ClauseId { ordinal: 3853097 }, ClauseId { ordinal: 3853101 }, ClauseId { ordinal: 4004809 },
 ClauseId { ordinal: 4004811 }, ClauseId { ordinal: 4004812 }, ClauseId { ordinal: 4004813 }, ClauseId { ordinal: 4005937 }, ClauseId { ordinal: 4005939 }, ClauseId { ordinal: 4006104 }, ClauseId { ordinal: 4006105 }, ClauseId { ordinal: 4007466 }, ClauseId { ordinal: 4007467 }, ClauseId { ordinal: 4016782 }, ClauseId { ordinal: 4016789 }, ClauseId { ordinal: 4072206 }, ClauseId { ordinal: 4072212 }, ClauseId { ordinal: 4083231 }, ClauseId { ordinal: 4083233 }, ClauseId { ordinal: 4083236 }, ClauseId { ordinal: 4083237 }, ClauseId { ordinal: 4178868 }, ClauseId { ordinal: 4178870 }, ClauseId { ordinal: 4278038 }, ClauseId { ordinal: 4280405 }, ClauseId { ordinal: 4280409 }, ClauseId { ordinal: 4304687 }, ClauseId { ordinal: 4304689 }, ClauseId { ordinal: 4304690 }, ClauseId { ordinal: 4335228 }, ClauseId { ordinal: 4421702 }, ClauseId { ordinal: 4421705 }, ClauseId { ordinal: 4421706 }, ClauseId { ordinal: 4563469 }, ClauseId { ordinal: 4574110 }, ClauseId { ordinal: 4660830 }, ClauseId { ordinal: 4672375 }, ClauseId { ordinal: 4672377 }, ClauseId { ordinal: 4672667 }, ClauseId { ordinal: 4672669 }, ClauseId { ordinal: 4672670 }, ClauseId { ordinal: 4672673 }, ClauseId { ordinal: 4687724 }, ClauseId { ordinal: 4712796 }, ClauseId { ordinal: 4826156 }, ClauseId { ordinal: 4831542 }, ClauseId { ordinal: 4956277 }, ClauseId { ordinal: 4956281 }]', src/processor/eliminator.rs:306:21

Differentiate FirstUIP-decomposable problems and VoP-decomposable problems

Objective

FirstUIP-based var ordering heuristics like VSIDS and CHB work well definitely. But VoP one works well too exactly. So how can I combine or select from them? It's a sort of problem that needs a balance of deliberation and reactivity.

Changes on the codebase

  • [to be into MASTER] introduce ProgressLVL implementing ProgressEvaluator trait

So far

  • A better one reduces decision level quickly. Probably. LBD is used for the criteria of restart trigger. Can it also be used for strategy changer? Meta-level restart?
  • No! Not LBD but conflict level. Exceeding an average conflict level is a key to switch the heuristics.

A cache of a literal watch can hold a literal which is satisfied at a higher level

$ splr aes.cnf
aes.cnf                                      501284,2928183 |time:    35.05
 #conflict:          0, #decision:            0, #propagate:         219056
  Assignment|#rem:   330722, #ass:        0, #elm:   170562, prg%:  34.0250
      Clause|Remv:        0, LBD2:        0, Binc:  1071976, Perm:  1744097
     Restart|#BLK:        0, #RST:        0, trgr:        1, peak:        1
         LBD|avrg:   0.0000, trnd:      NaN, depG:   0.0000, /dpc:     0.00
    Conflict|tASG:      NaN, cLvl:     0.00, bLvl:     0.00, /ppc:     0.00
        misc|proc:        1, #sub:    79566, core:   501284, /cpr:     0.00
unreachable core: 330722thread 'main' panicked at 
'assertion failed: self.level[new_watch.vi()] <= self.level[propagating.vi()]', 
src/assign/propagate.rs:405:29

In this path, a clause continues to use a falsified literal (the negation of a propagating literal) as a watch literal!
Between the level of this propagation and lower than the level of the cached literal, this clause should be treated as an unsatisfied clause. But Splr can't. We need another flesh watch-literal and update the cache using transform_by_updating_cache.

side effect: chrono-BT requires checking literals' level.

Variance of polarity

Objective

Import and try the idea prioritizing decision vars based on their variance of polarity EMA in the context of CDCL SAT solvers;

  • Prioritized Unit Propagation with Periodic Resetting is (Almost) All You Need for Random SAT Solving, avXiv

  • PR: #8

So far

  • The EMA length should be short.
  • Shouldn't substitute 'phase' with 'polarity'.
  • It's another deep swamp eating time endlessly. Managing and reflecting the best assignment set needs some idea.
  • Should reconsider Luby restart again in the context of my deep search usability.
  • Combining heuristics is another way to enable multi-dimension investigation like restarts. So it should be good.
  • There is a very similar idea: confliction heat map, or frequency of conflicts, requires update operations only on conflicting vars. ➡️ #11
  • Suspended.
  • Another idea: frequency of conflict and its EMA.

tried

  • mixed and conditional combination of activity and VoP.
  • use VoP as the increment of CHB. Fixing an important or difficult conflict eagerly seems rational.
  • 20191231-vop-restart: Instead of var ordering, how about as a restart trigger? Escaping from "a too difficult conflicting situation" might be good.
  • New series from 2020-01-22: update only when getting the most assigns ever.

UNSAT certificates are invalid.

Description

  • version: Splr-0.6.3 to 0.7.0
gratgen aes.cnf proof.drat -o proof.grat 
c sizeof(cdb_t) = 4
c sizeof(cdb_t*) = 8
c Using RAT run heuristics
c Parsing formula ... 4127ms
c Parsing proof (ASCII format) ... 42353ms
c Forward pass ... 1971ms
c Starting Backward pass
c Single threaded mode
c FAILED: RAT-check failed
s ERROR

Solution

  • resolved at Splr-0.7.1 RC

Reason

  • the order of clause generation and deletion operations was shuffled by garbage_collect! But still invalid.

0.6.0 urgent fixes within 2 days

  • fix compilation errors on configurations without feature 'staging'
  • use the term 'deterministic' as 'monotonous'
  • feature comparison
  • try to scalable gradual stabilization deepening
  • replace Lcyc with heat xpnd in progress message
  • benchmark if possible
  • tiny optimization about literal traversing in progress
  • rename assign_at_rootlevel with assign_at_root_level
    スクリーンショット 2021-01-16 18 45 58

ChronoBT

Objective

Implement one of the most important ideas in 2018, Chronological BackTrack.
I'm going to modify its implementation slightly. But before it, I need to scrutinize the paper.

  • A. Nadel and V. Ryvchin, “Chronological Backtracking,” in Theory and Applications of Satisfiability Testing - SAT 2018, pp.111–121, 2018.

branches

So far

  • Fixed all bugs at 2020-02-18T16:00:00 probably. Ditch results before it.
  • I can't still understand the need for the one-literal-in-conflict-level path.
  • There're unpropagated literals behind q_head

    splr/src/propagator.rs

    Lines 297 to 302 in 7e649a3

    self.trail.truncate(lim);
    for l in &q {
    self.trail.push(*l);
    }
    self.trail_lim.truncate(lv);
    self.q_head = self.trail.len();
  • How does redundant_lit recognize and handle the 1st literal, which is the 1st UIP?
  • conflict_analyze must handle disordered trail. The termination condition should be modified to skip seen literals with lower levels.
    • special case 1: a conflicting clause consists of only level 0 literals
    • special case 2: path_cnt should be decreased if the level of a new literal is the conflicting level.
  • note: then my 1st patch can be rejected, it handles the same problem in another way.
  • BUG HUNT2: see below. It's too complicated to fix all the bugs. So I ditched the idea, say, postponed level zero assignment and had to switch to sliding insertion of level zero assignment. That's not choroBT.
  • BUG HUNT: By postponing level 0 propagation as a consequence of my implementation, some vars that should be implicated at level 0 are found as first UIPs at a further level. Since rudandant_lit, however, declares them as redundant, they are disappeared from learnt clauses. We must handle this case by returning unit clauses from simplify_learnt, then by invoking AssignStack::uncheck_flip. This is not the reason for crashes.

Reverse propagation by biclause in conflict analysis

sympton

$ splr ../SC/T56.2.0.cnf
T56.2.0.cnf                                3145220,10854665 |time:    39.72
 #conflict:       1488, #decision:        17024, #propagate:        6541243
  Assignment|#rem:   587418, #ass:        0, #elm:  2557802, prg%:  81.3235
      Clause|Remv:      876, LBD2:       68, Binc:   583874, Perm:  3665666
     Restart|#BLK:        0, #RST:       52, trgr:        2, peak:        4
         LBD|avrg:   6.1434, trnd:   5.3063, depG:   0.6789, /dpc:    14.70
    Conflict|tASG:   6.0404, cLvl:    23.27, bLvl:    21.29, /ppc:  3931.49
        misc|proc:        2, #sub:   938076, core:   473559, /cpr:    11.55
unreachable core: 457974conflict_analysis broke the bottom at lit -37723L, path_cnt 1 scanned len 28611, lv 139
building learnt
VarReport { lit: 0, val: None, pos: None, lvl: 0, reason: None, at: -123456 }
VarReport { lit: -38003, val: Some(false), pos: Some(4516), lvl: 35, reason: Implication(4024680C, -1394273L), at: 1693 }
VarReport { lit: -38023, val: Some(false), pos: Some(4512), lvl: 35, reason: Implication(4024679C, -1394273L), at: 1693 }
VarReport { lit: -38043, val: Some(false), pos: Some(4514), lvl: 35, reason: Implication(4024678C, -1394273L), at: 1693 }
VarReport { lit: -38063, val: Some(false), pos: Some(1949), lvl: 14, reason: Implication(20134006C, 0L), at: 1680 }
VarReport { lit: -38083, val: Some(false), pos: Some(1943), lvl: 14, reason: Implication(20134005C, 0L), at: 1680 }
VarReport { lit: -38103, val: Some(false), pos: Some(1942), lvl: 14, reason: Implication(20134004C, 0L), at: 1680 }
VarReport { lit: -38123, val: Some(false), pos: Some(1941), lvl: 14, reason: Implication(20134003C, 0L), at: 1680 }
VarReport { lit: -37983, val: Some(false), pos: Some(4513), lvl: 35, reason: Implication(4024681C, -1394273L), at: 1693 }
VarReport { lit: -37703, val: Some(false), pos: Some(3304), lvl: 17, reason: Decision(17), at: 1683 }
VarReport { lit: -37663, val: Some(false), pos: Some(3316), lvl: 18, reason: Decision(18), at: 1683 }
VarReport { lit: -37683, val: Some(false), pos: Some(3348), lvl: 21, reason: Decision(21), at: 1683 }
VarReport { lit: 1394274, val: Some(false), pos: Some(1839), lvl: 14, reason: Implication(12393551C, 0L), at: 1680 }
VarReport { lit: -37783, val: Some(false), pos: Some(4684), lvl: 35, reason: Implication(20134013C, 0L), at: 1693 }
VarReport { lit: -37743, val: Some(false), pos: Some(4601), lvl: 35, reason: Implication(20134015C, 0L), at: 1693 }
VarReport { lit: -37763, val: Some(false), pos: Some(3921), lvl: 35, reason: Implication(4019032C, 41569L), at: 1693 }
VarReport { lit: -37803, val: Some(false), pos: Some(4685), lvl: 35, reason: Implication(20134012C, 0L), at: 1693 }
conflicting clause
VarReport { lit: 37723, val: Some(false), pos: Some(28556), lvl: 139, reason: Implication(21209189C, 0L), at: 1763 }
VarReport { lit: -1329727, val: Some(false), pos: Some(28558), lvl: 139, reason: Implication(4018718C, -37523L), at: 1764 }
cid? 4018718
 SVarReport { lit: 37523, val: Some(false), pos: Some(28561), lvl: 139, reason: Implication(92886C, 0L), at: 1764 }
  VarReport { lit: 1329727, val: Some(true), pos: Some(28558), lvl: 139, reason: Implication(4018718C, -37523L), at: 1764 }
cid? 92886
 SVarReport { lit: -37523, val: Some(true), pos: Some(28561), lvl: 139, reason: Implication(92886C, 0L), at: 1764 }
  VarReport { lit: -37504, val: Some(false), pos: Some(28571), lvl: 139, reason: Implication(92834C, 0L), at: 1764 }
  VarReport { lit: 37524, val: Some(false), pos: Some(28396), lvl: 134, reason: Decision(134), at: 1750 }
cid? 92834
  VarReport { lit: 37504, val: Some(true), pos: Some(28571), lvl: 139, reason: Implication(92834C, 0L), at: 1764 }
  VarReport { lit: -37503, val: Some(false), pos: Some(28586), lvl: 35, reason: Implication(22418781C, 0L), at: 1764 }
  VarReport { lit: -37484, val: Some(false), pos: Some(28594), lvl: 139, reason: Implication(92782C, 0L), at: 1763 }
cid? 

In this trace, the binary clause 4018718, which is the reason of the 28558th assignment has:

  • VarReport { lit: 37523, val: Some(false), pos: Some(28561), lvl: 139, reason: Implication(92886C, 0L), at: 1764 }
  • VarReport { lit: 1329727, val: Some(true), pos: Some(28558), lvl: 139, reason: Implication(4018718C, -37523L), at: 1764 }

How Is this possible?!

reason

 if chronobt && assign_level + state.config.c_cbt_thr <= conflicting_level {
        asg.cancel_until(conflicting_level - 1);
    } else {
        asg.cancel_until(assign_level);
    }

`-q` can't kill all output.

I need to delete them:

      Result|file: ./.ans_uf250-096.cnf
s SATISFIABLE: ../SAT-bench/3-SAT/UF250/uf250-096.cnf

Assigned but not propagated!

$ splr aes.cnf
aes.cnf                                      501284,2928183 |time:   756.14
 #conflict:      77952, #decision:       510809, #propagate:       42482730
  Assignment|#rem:    52355, #ass:   249433, #elm:   199496, prg%:  89.5558
      Clause|Remv:    39112, LBD2:     2210, Binc:   483528, Perm:   953565
     Restart|#BLK:      131, #RST:      456, trgr:        1, peak:       16
         LBD|avrg:   8.8189, trnd:   1.0471, depG:   3.2885, /dpc:     2.20
    Conflict|tASG:   0.0348, cLvl:   350.17, bLvl:   343.52, /ppc:   235.85
        misc|proc:        5, #sub:    82046, core:        0, /cpr:   335.57
Before extending the model
falsifies by 3851765C at level 406, NumConf 77952
 which was born at 0, and used in conflict analysis at 0
 which was moved among watch caches at FindNewWatch(77944, 487421L, 487051L)
Its literals: {[-487051, -488491, 497405, 486367, -487421, -486765, -489896, -490520, 490606]b0}
 |   pos |   time | level |   literal  |  assignment |               reason |
 | 51739 |  77951 |   374 |   -486765  | Some(false) | Implied by 2661684C  | Propagated(77951)
 | 51740 |  77951 |   373 |   -490520  | Some(false) | Implied by 2652673C  | Propagated(77951)
 | 51741 |  77951 |   377 |   -487421  | Some(false) | Implied by 2675707C  | Propagated(77951)
 | 51742 |  77951 |   380 |    486367  | Some(false) | Implied by 2671052C  | Propagated(77951)
 | 51743 |  77951 |   380 |   -489896  | Some(false) | Implied by 2664069C  | Assigned(77951)
 | 51744 |  77951 |   379 |   -487051* | Some(false) | Implied by 2664802C  | Assigned(77951)
 | 51745 |  77951 |   375 |   -488491* | Some(false) | Implied by 2662492C  | Assigned(77951)
 | 51746 |  77951 |   373 |    490606  | Some(false) | Implied by 2660795C  | Assigned(77951)
 | 51784 |  77952 |   390 |    497405  | Some(false) | Decided at level 390 | Propagated(77952)
 - L0 -487051L has complements [-488491L] in its cache
 - L1 -488491L has complements [-487051L] in its cache
The last assigned literal in stack:
 | 52354 |  77952 |   406 |   -237190  | Some(true)  | Decided at level 406 |
thread 'main' panicked at 'explicit panic', src/solver/search.rs:440:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
zsh: abort      splr aes.cnf
@@ -229,8 +231,9 @@ impl PropagateIF for AssignStack {
         }
         self.trail.truncate(lim);
         // moved below -- self.q_head = self.trail.len();
+        // see https://github.com/shnarazk/splr/issues/117
+        self.q_head = self.trail.len().min(self.q_head);
         self.trail.append(&mut unpropagated);
-        self.q_head = self.trail.len();
         debug_assert!(self
             .trail
             .iter()                                             

Revise Clause -- cyclic search for non-falsified literal

// Finally, for long clauses we save the position of the last watch
// replacement in 'pos', which in turn reduces certain quadratic accumulated
// propagation costs (2013 JAIR article by Ian Gent) at the expense of four
// more bytes for each clause.
// This follows Ian Gent's (JAIR'13) idea of saving the position
// of the last watch replacement.  In essence it needs two copies
// of the default search for a watch replacement (in essence the
// code in the 'if (v < 0) { ... }' block below), one starting at
// the saved position until the end of the clause and then if that
// one failed to find a replacement another one starting at the
// first non-watched literal until the saved position.

It's a cyclic search. 😃

// a sketch
'search: loop {
  for i in c.start_from..c.len() { .. }
  for i in 2..c.start_form { .. }
  break 'search;
}
// therefore
for (b, e) in &[(c.start, c.len()), (2, c.start)] {
    for i in b..e {
       if found {
         c.start = i;
         break 'outer_loop;
       }
    }
}

bumpreason -- bump reason literals too

DONE: it's just reason side rewarding.

It's important for UNSAT problems.

inline bool Internal::bump_also_reason_literal (int lit) {
  assert (lit);
  assert (val (lit) < 0);
  Flags & f = flags (lit);
  if (f.seen) return false;
  const Var & v = var (lit);
  if (!v.level) return false;
  f.seen = true;
  analyzed.push_back (lit);
  LOG ("bumping also reason literal %d assigned at level %d", lit, v.level);
  return true;
}

inline void Internal::bump_also_reason_literals (int lit, int limit) {
  assert (lit);
  assert (limit > 0);
  const Var & v = var (lit);
  assert (val (lit));
  if (!v.level) return;
  Clause * reason = v.reason;
  if (!reason) return;
  for (const auto & other : *reason) {
    if (other == lit)  continue;
    if (!bump_also_reason_literal (other)) continue;
    if (limit < 2) continue;
    bump_also_reason_literals (-other, limit-1);
  }
}

inline void Internal::bump_also_all_reason_literals () {
  assert (opts.bumpreason);
  assert (opts.bumpreasondepth > 0);
  for (const auto & lit : clause)
    bump_also_reason_literals (-lit, opts.bumpreasondepth);
}
  --bumpreasondepth=1..3     bump reason depth [1]

How is blocking restart similar to stabilizing restart

The opposite search mode of exploration mode could be divided into several (sub) ones:

  • accepting 'bad' learnts
  • postponing the next restart
  • restricting the target search space guided by mutual correlation of literals

So?

stabilzephase -- use target variable phase

  • 'stabilize' is to stop restarts.
  • 'stabilizephase' is to store the best assign in the present or target cycle into phase slots.

So far

adopt simplified version: store best assign instead of target assign.

Assignment traversing needs a special handling for ChronoBT

$ splr -t 9000 aes.cnf
aes.cnf                                      501284,2928183 |time:  1040.09
 #conflict:    1232434, #decision:      3245711, #propagate:      886879916
  Assignment|#rem:    41050, #ass:   260696, #elm:   199538, prg%:  91.8110
      Clause|Remv:   182443, LBD2:     7638, Binc:   496190, Perm:   904711
     Restart|#BLK:     1385, #RST:     1249, trgr:        1, peak:       32
         LBD|avrg:  34.9654, trnd:   2.2807, depG:   2.9327, /dpc:     2.04
    Conflict|tASG:   1.0624, cLvl:   353.70, bLvl:   351.83, /ppc:  2035.31
        misc|proc:       19, #sub:    83161, core:        4, /cpr:  2901.83
thread 'main' panicked at 'assertion failed: 0 < path_cnt', src/solver/conflict.rs:393:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
zsh: abort      splr -t 9000 aes.cnf

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.