This repository has been archived by the owner on Dec 18, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
/
solver_init.go
119 lines (98 loc) · 2.8 KB
/
solver_init.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package sat
import (
"sort"
"github.com/mitchellh/go-sat/cnf"
)
// AddFormula adds the given formula to the solver.
//
// This can only be called before Solve() is called.
func (s *Solver) AddFormula(f cnf.Formula) {
for _, c := range f {
s.AddClause(c)
}
}
// AddClause adds a Clause to solve to the solver.
//
// This can only be called before Solve() is called.
func (s *Solver) AddClause(c cnf.Clause) {
// Get the actual slice since we'll be modifying this directly.
// The API docs say not to but its part of our package and we know
// what we're doing. :)
lits := c
// Sort
sort.Slice(lits, func(i, j int) bool {
return lits[i] < lits[j]
})
// Keep track of an index since we'll be slicing as we go. We also
// keep track of the last value so that we can find tautologies (X | !X)
idx := 0
last := cnf.LitUndef
for _, current := range lits {
// Due to the sorting X and !X will always be next to each other.
// A cheap way to check for tautologies is to just check the last
// value.
if current == last.Neg() {
if s.Trace {
s.Tracer.Printf(
"[TRACE] sat: addClause: not adding clause; tautology with var %s",
current)
}
return
}
// Check if there is currently an assigned value of the literal.
// If it is false then we already can skip this literal. If it is
// true we can avoid adding the entire clause.
switch s.valueLit(current) {
case triFalse:
if s.Trace {
s.Tracer.Printf(
"[TRACE] sat: addClause: not adding literal; literal %s false: %s",
current, c)
}
continue
case triTrue:
if s.Trace {
s.Tracer.Printf(
"[TRACE] sat: addClause: not adding clause; literal %s already true: %s",
current, c)
}
return
}
// Due to sorting, we can quickly eliminate duplicates by only copying
// down when the values aren't the same.
if current != last {
lits[idx] = current
last = current
idx++
}
}
// Reset the size of literals to account for removed duplicates
lits = lits[:idx]
// If the clause is empty, then this formula can already not be satisfied
if len(lits) == 0 {
if s.Trace {
s.Tracer.Printf("[TRACE] sat: addClause: empty clause, forcing unsat")
}
s.result = satResultUnsat
return
}
// Track the available decision variables
for _, l := range lits {
s.vars[l.Var()] = struct{}{}
}
// If this is a single literal clause then we assert it cause it must be
if len(lits) == 1 {
if s.Trace {
s.Tracer.Printf("[TRACE] sat: addClause: single literal clause, asserting %s", lits[0])
}
s.assertLiteral(lits[0], nil)
// Do unit propagation since this may solve already clauses
s.propagate()
// We also don't add this clause since we just asserted the value
return
}
// Add it to our formula
c = cnf.Clause(lits)
s.clauses = append(s.clauses, c)
s.watchClause(c)
}