-
-
Notifications
You must be signed in to change notification settings - Fork 16
/
gini.go
279 lines (250 loc) · 8.03 KB
/
gini.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
// Copyright 2016 The Gini Authors. All rights reserved. Use of this source
// code is governed by a license that can be found in the License file.
package gini
import (
"io"
"time"
"github.com/go-air/gini/dimacs"
"github.com/go-air/gini/inter"
"github.com/go-air/gini/internal/xo"
"github.com/go-air/gini/z"
)
// Gini is a concrete implementation of solver
type Gini struct {
xo *xo.S
}
// internal use
func newGiniXo(x *xo.S) *Gini {
g := &Gini{
xo: x}
return g
}
// New creates a new gini solver.
func New() *Gini {
g := &Gini{
xo: xo.NewS()}
return g
}
// NewDimacs create a new gini solver from
// dimacs formatted input.
func NewDimacs(r io.Reader) (*Gini, error) {
vis := &xo.DimacsVis{}
if e := dimacs.ReadCnf(r, vis); e != nil {
return nil, e
}
g := &Gini{
xo: vis.S()}
return g, nil
}
// NewV creates a new Gini solver with
// hint for capacity of variables set to capHint.
func NewV(capHint int) *Gini {
g := &Gini{
xo: xo.NewSV(capHint)}
return g
}
// NewVc creates a new Gini solver with
// hint for capacity of variables set to vCapHint,
// and likewise capacity of clauses set cCapHint
func NewVc(vCapHint, cCapHint int) *Gini {
g := &Gini{
xo: xo.NewSVc(vCapHint, cCapHint)}
return g
}
// Copy makes a copy of the Gini g.
//
// every bit of g is copied except
//
// 1. Statistics for reporting, which are set to 0 instead of copied
// 2. Control mechanisms for Solve's resulting from GoSolve() so the
// copied gini can make its own calls to GoSolve() (or Solve()) without
// affecting the original.
func (g *Gini) Copy() *Gini {
other := &Gini{
xo: g.xo.Copy()}
return other
}
// SCopy implements inter.S
func (g *Gini) SCopy() inter.S {
return g.Copy()
}
// MaxVar returns the variable whose id is max.
func (g *Gini) MaxVar() z.Var {
return g.xo.Vars.Max
}
// Lit produces a fresh variable and returns its positive literal, conforming
// to inter.Liter.
func (g *Gini) Lit() z.Lit {
return g.xo.Lit()
}
// Add implements inter.S. To add a clause (x + y + z),
// one calls
//
// g.Add(x)
// g.Add(y)
// g.Add(z)
// g.Add(0)
//
// If Add is called under a test scope, then Add will panic
// if `m` is 0/LitNull.
//
func (g *Gini) Add(m z.Lit) {
g.xo.Add(m)
}
// Assume causes the solver to make the assumption
// that m is true in the next call to Solve() or the
// next call to Test().
//
// Solve() always consumes and forgets untested assumptions.
// tested assumptions are never forgotten, and may be popped
// with Untest().
func (g *Gini) Assume(ms ...z.Lit) {
g.xo.Assume(ms...)
}
// Solve solves the constraints. It returns 1 if
// sat, -1 if unsat, and 0 if canceled.
func (g *Gini) Solve() int {
res := g.xo.Solve()
return res
}
// Try solves with a timeout. Try returns
// 1 if sat
// -1 if unsat
// 0 if timeout
func (g *Gini) Try(dur time.Duration) int {
return g.xo.Try(dur)
}
// GoSolve provides a connection to a single background
// solving goroutine, a goroutine which calls Solve()
func (g *Gini) GoSolve() inter.Solve {
return g.xo.GoSolve()
}
// Value returns the truth value of the literal m.
// The meaning of the returned value is only defined
// if the previous call to sat was satisfiable. In
// this case, the returned value is the value of m
// in a model of of the underlying problem, where that
// model is determined by the previous call to Solve().
func (g *Gini) Value(m z.Lit) bool {
return g.xo.Vars.Vals[m] == 1
}
// Why returns the slice of failed assumptions, a minimized
// set of assumptions which are sufficient for the last
// UNSAT result (from a call to Test() or Solve()).
//
// Why tries to store the failed assumptions in ms, if
// there is sufficient space.
func (g *Gini) Why(ms []z.Lit) []z.Lit {
return g.xo.Why(ms)
}
// Test tests whether the current assumptions are consistent under BCP
// and opens a scope for future assumptions.
//
// Test returns the result of BCP res
// (1: SAT, -1: UNSAT: 0, UNKNOWN)
// And any associated data in out. The data tries to use dst
// for storage if there is space.
//
// The associated data is
//
// - All assigned literals since last test if SAT or UNKNOWN
// - Either the literals of a clause which is unsat under BCP or an assumption
// which is false under BCP, whichever is found first.
//
// When g is under a test scope, many operations are not
// possible, in particular: {Add,Activate,ActivateWith,Deactivate}
// are unsupported operations under a test scope.
func (g *Gini) Test(dst []z.Lit) (res int, out []z.Lit) {
return g.xo.Test(dst)
}
// Untest removes a scope opened and sealed by Test, backtracking
// and removing assumptions.
//
// Untest returns whether the problem is consistent under BCP after
// removing assumptions from the last Test. It can happen that
// a given set of assumptions becomes inconsistent under BCP
// as the underlying solver learns clauses.
func (g *Gini) Untest() int {
return g.xo.Untest()
}
// Reasons give a set of literals which imply m by virtue of
// a single clause.
//
// Reasons only works if m was returned by some call to Test resulting in
// SAT or UNKNOWN. Otherwise, Reasons is undefined and may panic.
//
// Additionally, Reasons returns a piece of an acyclic implication graph.
// The entire graph may be reconstructed by calling Reasons for every propagated
// literal returned by Test. The underlying graph changes on calls to Test
// and Solve. If the underlying graph does not change, then Reasons guarantees
// that it is acyclic.
func (g *Gini) Reasons(dst []z.Lit, m z.Lit) []z.Lit {
return g.xo.Reasons(dst, m)
}
// Create a clause from the last (non 0-terminated, non-empty) sequence of Adds and
// `m.Not()`. Activate panics if the last sequence of Adds since Add(0) is empty,
// in other words, don't try to use an activation literal for the empty clause.
//
// Additionally, in this case subsequent behavior of `g` is undefined. The caller
// should verify a clause is not empty using `g.Value(m)` for all literals in in
// the clause to activate.
//
// To active the clause, assume `m`.
//
// Example:
//
// if g.Value(a) != false || g.Value(b) != false {
// g.Add(a)
// g.Add(b)
// m := g.Activate() // don't call g.Add(0).
// g.Assume(m) // now the clause (a + b) is active
// if g.Solve() == 1 {
// // do something
// }
// // now the clause (a+b) is not active.
// g.Deactivate(m)
// // now `m` can be re-used and the solver can ignore
// // clauses with `m`.
// }
//
// Activation of all clauses can be used in conjunction with cardinality constraints
// to easily create a MAXSAT solver.
//
// Activate is an unsupported operation under a test scope
// and will panic if called under a test scope.
func (g *Gini) Activate() (m z.Lit) {
return g.xo.Activate()
}
// ActivateWith allows the caller to specify the activation literal. It is
// useful when the caller needs to activate many clauses with one literal.
// However, please note that activation literals are volatile and will be
// recycled on Deactivate. As with Activate, ActivateWith should not
// be used to activate the empty clause. In this case, ActivateWith
// panics and subsequent behavior of g is undefined.
//
// ActivateWith is an unsupported operation under a test scope
// and will panic if called under a test scope.
func (g *Gini) ActivateWith(act z.Lit) {
g.xo.ActivateWith(act)
}
// ActivationLit returns a new literal to be used with ActivateWith().
//
// ActivationLit is an unsupported operation under a test scope and will
// panic if called under a test scope.
func (g *Gini) ActivationLit() z.Lit {
return g.xo.ActivationLit()
}
// Deactivate deactivates a literal as returned by Activate. Deactivation
// frees the literal for future Activations and removes all clauses, including
// learned clauses, which contain `m.Not()`.
//
// Deactivate is an unsupported operation under a test scope
// and will panic if called under a test scope.
func (g *Gini) Deactivate(m z.Lit) {
g.xo.Deactivate(m)
}
// Write writes the underlying CNF in dimacs format to dst,
// returning any i/o error which occured in the process.
func (g *Gini) Write(dst io.Writer) error {
return g.xo.Cdb.Write(dst)
}