PB conflict analysis
RoundingSat 2 - May 2020
Caveats
- Current implementation is
- educated guess
- plenty to research
- plenty to improve
- There is no silver bullet?
- probably no single best approach
- current heuristic: avoid clauses
division, weakening, resolving "clausify" a constraint
- Goal: give broad overview, few details
- starting point of more thorough conflict analysis research
Conflict analysis
- In: constraint C falsified by assignment ρ at decision level d
- Out: constraint L asserting under ρ at decision level < d
- potentially: falsified by ρ at decision level < d
while(size(ρ)>0){ if(stopcondition) break l ← back(ρ) if(coef(C,l)≥0) continue R ← reason(l) preprocess(R) reduce(R) C ← resolve(R,C) postprocess(C) unassign(l) } L ← C
backjump to L non-conflicting postprocess(L)
Conflict analysis
Terminology:
- l = asserting literal
- a = coef of l in reason
- b = coef of ~l in conflict
- c = some coefficient
- div = divisor
- d = current decision level
- ρ = current assignment
- R = "reason side"
- C = "conflict side"
- L = constraint to learn
- n = number of variables
- RS1 = RoundingSat master
- RS2 = RoundingSat 2
Stop condition
Candidate stop conditions
- until all-decisions - O(1)
- until decision at current level - O(1)
- until unique literal at current level - O(|C|)
-
until some current level literal is asserting - O(|C|)
- until some literal is asserting - O(|C| lg(|C|))
More resolving steps
RS1
RS2
Preprocess reason
Goal: strengthen & simplify
removeUnits(R) saturate(R) weakenNonImplying(R) saturate(R)
Currently:
weaken down smallest falsified coefficients for total of at most
a - slack(ρ,R) - 1
if l ≥ 1 or 0 ≥ l,
eliminate l
O(|R| lg(|R|)) naively
but O(|R|) if R is sorted
Potentially:
weakenNonImplied(R) divideByGCD(R) reduceToEquivalentCardinality(R)
RS2
RS1
Reduce reason
Goal: ensure resolvent is conflicting
- roundToOne:
- div = a
- weaken non-divisible non-falsifieds
- roundToZeroSlack:
- div = slack(ρ,R)+1
- partially weaken down non-falsifieds
- mixedIntegerRounding:
- apply MIR inequality with some div > slack(ρ,R)
- partially weaken down non-falsifieds
- at least as strong as roundToZeroSlack
- weakenAndSaturate - Sat4J style
- combinedReduce:
- alternate division and weakening of non-falsifieds
slack(ρ,R)=0
slack(ρ,resolvent(R,C))<0
RS1
RS2
Reduce reason
Goal: ensure resolvent is conflicting
Here be dragons, many parameters to play with
- which divisor(s)?
- should it be a divisor of a? Of b?
- how to weaken non-falsified?
- partial vs. complete
- weaken up l when C cancels l?
- weaken down falsifieds?
- saturate at the end of reduce(R)? (yes in RS2)
- ... ?
Note: in RS2, it is possible that the slack of R is negative
Resolve
Goal: add up reason and conflict to cancel l
- divide R and C to a = b = 1
- pick div s.t. floor(a,div) divides b
- afterwards, simple & efficient multiplication of R
- div can be large, e.g., if b = 1, then div = a
- multiply R and C to cancel out l
- O(|C|), C can become large
- leads to larger coefficients
- no constraints on picking div
-
sufficient goal: resolvent is conflicting after unassign(l)
-
no need to fully cancel l?
-
some falsified literals can even be ignored?
-
RS2
RS1
Postprocess conflict
Goal: strengthen C and fix potential overflow
saturate(C) addressOverflow(C)
Currently:
Potentially:
divideByGCD(C) reduceToEquivalentCardinality(C) ?
if largest coef c > 1e9, divide by smallest div s.t. ceil(c/div) ≤ 1e9, weaken non-falsifieds partially
O(|C|)
but may often be trivial
RS1: no saturate(C); addressOverflow(C) divides to cardinality
Resolve loop complexity
while(size(ρ)>0){ if(stopcondition) break l ← back(ρ) if(coef(C,l)≥0) continue R ← reason(l) preprocess(R) reduce(R) C ← resolve(R,C) postprocess(C) unassign(l) } L ← C
backjump to L non-conflicting postprocess(L)
- linear number of iterations
- linear amount of work in one iteration
- R can be linear
- C can grow to linear size
- stopcondition check is O(|C|)
- resolve(R,C) is O(|C|) when multiplying C
- postprocess(C) is O(|C|)
- Can complexity be lowered without sacrificing resolvent quality?
O(n²)
Backjump
Goal: L is not conflicting
- simple: backjump to root
- hard (?): non-chronological backjump
- backjump to latest asserting level
- might lead to missed propagations, e.g.,
learn x+y+z≥2 with trail [z=0 (dec), x=1 (dec), y=0 (dec)]
backjump to [z=0 (dec), x=1 (dec)]
propagate to [z=0 (dec), x=1 (dec), y=1 (prop)]
...
after backjump to [z=0 (dec)],
no propagation watches trigger for x+y+z≥2
- might lead to missed propagations, e.g.,
- backjump to earliest asserting level
- compute slack from level 0 to d
- keep track of largest unassigned coef on each level
- return lowest level such that unassigned coef > slack
- O(|L| lg(|L|))
RS2
RS1
Postprocess learned
Goal: simplify & strengthen L
weakenNonImplied(L) weakenNonImplying(L) saturate(L) divideByGCD(L) reduceToEquivalentCardinality(L)
Currently:
Potentially:
eliminateRedundantLits(L) generalizedSaturation(L) generalizedSelfSubsumption(L,.) ?
weaken non-falsified literals with coefficient ≤ slack(ρ,L)
O(|L| lg(|L|))
check whether smallest and largest set of coefficients summing op to
> degree are equal in size
RS1
Simple experiment
- Run RS1 and RS2 for 5000s with 16GiB RAM
- opt-mode=linear
- lp=0
- RS2 has faster propagation than RS1
Simple experiment
Simple experiment
Simple experiment
Thanks for your attention
More questions?
PB conflict analysis: May 2020
By Jo Devriendt
PB conflict analysis: May 2020
- 419