mirror of
https://github.com/mudler/luet.git
synced 2025-07-17 08:52:14 +00:00
127 lines
3.7 KiB
Go
127 lines
3.7 KiB
Go
package solver
|
|
|
|
// computeLbd computes and sets c's LBD (Literal Block Distance).
|
|
func (c *Clause) computeLbd(model Model) {
|
|
c.setLbd(1)
|
|
curLvl := abs(model[c.Get(0).Var()])
|
|
for i := 0; i < c.Len(); i++ {
|
|
lit := c.Get(i)
|
|
if lvl := abs(model[lit.Var()]); lvl != curLvl {
|
|
curLvl = lvl
|
|
c.incLbd()
|
|
}
|
|
}
|
|
}
|
|
|
|
// addClauseLits is a helper function for learnClause.
|
|
// It deals with lits from the conflict clause.
|
|
func (s *Solver) addClauseLits(confl *Clause, lvl decLevel, met, metLvl []bool, lits *[]Lit) int {
|
|
nbLvl := 0
|
|
for i := 0; i < confl.Len(); i++ {
|
|
l := confl.Get(i)
|
|
v := l.Var()
|
|
if s.litStatus(l) != Unsat {
|
|
// In clauses where cardinality > 1, some lits might be true in the conflict clause: ignore them
|
|
continue
|
|
}
|
|
met[v] = true
|
|
s.varBumpActivity(v)
|
|
if abs(s.model[v]) == lvl {
|
|
metLvl[v] = true
|
|
nbLvl++
|
|
} else {
|
|
*lits = append(*lits, l)
|
|
}
|
|
}
|
|
return nbLvl
|
|
}
|
|
|
|
var bufLits = make([]Lit, 10000) // Buffer for lits in learnClause. Used to reduce allocations.
|
|
|
|
// learnClause creates a conflict clause and returns either:
|
|
// - the clause itself, if its len is at least 2,
|
|
// - a nil clause and a unit literal, if its len is exactly 1,
|
|
// - a nil clause and -1, if the empty clause was learned.
|
|
func (s *Solver) learnClause(confl *Clause, lvl decLevel) (learned *Clause, unit Lit) {
|
|
s.clauseBumpActivity(confl)
|
|
lits := bufLits[:1] // Not 0: make room for asserting literal
|
|
buf := make([]bool, s.nbVars*2) // Buffer for met and metLvl; reduces allocs/deallocs
|
|
met := buf[:s.nbVars] // List of all vars already met
|
|
metLvl := buf[s.nbVars:] // List of all vars from current level to deal with
|
|
// nbLvl is the nb of vars in lvl currently used
|
|
nbLvl := s.addClauseLits(confl, lvl, met, metLvl, &lits)
|
|
ptr := len(s.trail) - 1 // Pointer in propagation trail
|
|
for nbLvl > 1 { // We will stop once we only have one lit from current level.
|
|
for !metLvl[s.trail[ptr].Var()] {
|
|
if abs(s.model[s.trail[ptr].Var()]) == lvl { // This var was deduced afterwards and was not a reason for the conflict
|
|
met[s.trail[ptr].Var()] = true
|
|
}
|
|
ptr--
|
|
}
|
|
v := s.trail[ptr].Var()
|
|
if s.assumptions[v] {
|
|
// Now we only have assumed lits: this is a top-level conflict
|
|
return nil, -1
|
|
}
|
|
ptr--
|
|
nbLvl--
|
|
if reason := s.reason[v]; reason != nil {
|
|
s.clauseBumpActivity(reason)
|
|
for i := 0; i < reason.Len(); i++ {
|
|
lit := reason.Get(i)
|
|
if v2 := lit.Var(); !met[v2] {
|
|
if s.litStatus(lit) != Unsat { // In clauses where cardinality > 1, some lits might be true in the conflict clause: ignore them
|
|
continue
|
|
}
|
|
met[v2] = true
|
|
s.varBumpActivity(v2)
|
|
if abs(s.model[v2]) == lvl {
|
|
metLvl[v2] = true
|
|
nbLvl++
|
|
} else {
|
|
lits = append(lits, lit)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for _, l := range s.trail { // Look for last lit from lvl and use it as asserting lit
|
|
if metLvl[l.Var()] {
|
|
lits[0] = l.Negation()
|
|
break
|
|
}
|
|
}
|
|
s.varDecayActivity()
|
|
s.clauseDecayActivity()
|
|
sortLiterals(lits, s.model)
|
|
sz := s.minimizeLearned(met, lits)
|
|
if sz == 1 {
|
|
return nil, lits[0]
|
|
}
|
|
learned = NewLearnedClause(alloc.newLits(lits[0:sz]...))
|
|
learned.computeLbd(s.model)
|
|
return learned, -1
|
|
}
|
|
|
|
// minimizeLearned reduces (if possible) the length of the learned clause and returns the size
|
|
// of the new list of lits.
|
|
func (s *Solver) minimizeLearned(met []bool, learned []Lit) int {
|
|
sz := 1
|
|
for i := 1; i < len(learned); i++ {
|
|
if reason := s.reason[learned[i].Var()]; reason == nil {
|
|
learned[sz] = learned[i]
|
|
sz++
|
|
} else {
|
|
for k := 0; k < reason.Len(); k++ {
|
|
lit := reason.Get(k)
|
|
if !met[lit.Var()] /*&& abs(s.model[lit.Var()]) > 1*/ {
|
|
learned[sz] = learned[i]
|
|
sz++
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return sz
|
|
}
|