python-sat 1.8.dev25__cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of python-sat might be problematic. Click here for more details.
- pycard.cpython-314-x86_64-linux-gnu.so +0 -0
- pysat/__init__.py +24 -0
- pysat/_fileio.py +209 -0
- pysat/_utils.py +58 -0
- pysat/allies/__init__.py +0 -0
- pysat/allies/approxmc.py +385 -0
- pysat/allies/unigen.py +435 -0
- pysat/card.py +802 -0
- pysat/engines.py +1302 -0
- pysat/examples/__init__.py +0 -0
- pysat/examples/bbscan.py +663 -0
- pysat/examples/bica.py +691 -0
- pysat/examples/fm.py +527 -0
- pysat/examples/genhard.py +516 -0
- pysat/examples/hitman.py +653 -0
- pysat/examples/lbx.py +638 -0
- pysat/examples/lsu.py +496 -0
- pysat/examples/mcsls.py +610 -0
- pysat/examples/models.py +189 -0
- pysat/examples/musx.py +344 -0
- pysat/examples/optux.py +710 -0
- pysat/examples/primer.py +620 -0
- pysat/examples/rc2.py +1858 -0
- pysat/examples/usage.py +63 -0
- pysat/formula.py +5619 -0
- pysat/pb.py +463 -0
- pysat/process.py +363 -0
- pysat/solvers.py +7591 -0
- pysolvers.cpython-314-x86_64-linux-gnu.so +0 -0
- python_sat-1.8.dev25.data/scripts/approxmc.py +385 -0
- python_sat-1.8.dev25.data/scripts/bbscan.py +663 -0
- python_sat-1.8.dev25.data/scripts/bica.py +691 -0
- python_sat-1.8.dev25.data/scripts/fm.py +527 -0
- python_sat-1.8.dev25.data/scripts/genhard.py +516 -0
- python_sat-1.8.dev25.data/scripts/lbx.py +638 -0
- python_sat-1.8.dev25.data/scripts/lsu.py +496 -0
- python_sat-1.8.dev25.data/scripts/mcsls.py +610 -0
- python_sat-1.8.dev25.data/scripts/models.py +189 -0
- python_sat-1.8.dev25.data/scripts/musx.py +344 -0
- python_sat-1.8.dev25.data/scripts/optux.py +710 -0
- python_sat-1.8.dev25.data/scripts/primer.py +620 -0
- python_sat-1.8.dev25.data/scripts/rc2.py +1858 -0
- python_sat-1.8.dev25.data/scripts/unigen.py +435 -0
- python_sat-1.8.dev25.dist-info/METADATA +45 -0
- python_sat-1.8.dev25.dist-info/RECORD +48 -0
- python_sat-1.8.dev25.dist-info/WHEEL +6 -0
- python_sat-1.8.dev25.dist-info/licenses/LICENSE.txt +21 -0
- python_sat-1.8.dev25.dist-info/top_level.txt +3 -0
pysat/examples/lsu.py
ADDED
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
#-*- coding:utf-8 -*-
|
|
3
|
+
##
|
|
4
|
+
## lsu.py
|
|
5
|
+
##
|
|
6
|
+
## Created on: Aug 29, 2018
|
|
7
|
+
## Author: Miguel Neves
|
|
8
|
+
## E-mail: neves@sat.inesc-id.pt
|
|
9
|
+
##
|
|
10
|
+
|
|
11
|
+
"""
|
|
12
|
+
===============
|
|
13
|
+
List of classes
|
|
14
|
+
===============
|
|
15
|
+
|
|
16
|
+
.. autosummary::
|
|
17
|
+
:nosignatures:
|
|
18
|
+
|
|
19
|
+
LSU
|
|
20
|
+
LSUPlus
|
|
21
|
+
|
|
22
|
+
==================
|
|
23
|
+
Module description
|
|
24
|
+
==================
|
|
25
|
+
|
|
26
|
+
The module implements a prototype of the known *LSU/LSUS*, e.g. *linear
|
|
27
|
+
(search) SAT-UNSAT*, algorithm for MaxSAT, e.g. see [1]_. The
|
|
28
|
+
implementation is improved by the use of the *iterative totalizer encoding*
|
|
29
|
+
[2]_. The encoding is used in an incremental fashion, i.e. it is created
|
|
30
|
+
once and reused as many times as the number of iterations the algorithm
|
|
31
|
+
makes.
|
|
32
|
+
|
|
33
|
+
.. [1] António Morgado, Federico Heras, Mark H. Liffiton, Jordi Planes,
|
|
34
|
+
Joao Marques-Silva. *Iterative and core-guided MaxSAT solving: A
|
|
35
|
+
survey and assessment*. Constraints 18(4). 2013. pp. 478-534
|
|
36
|
+
|
|
37
|
+
.. [2] Ruben Martins, Saurabh Joshi, Vasco M. Manquinho, Inês Lynce.
|
|
38
|
+
*Incremental Cardinality Constraints for MaxSAT*. CP 2014. pp. 531-548
|
|
39
|
+
|
|
40
|
+
The implementation can be used as an executable (the list of available
|
|
41
|
+
command-line options can be shown using ``lsu.py -h``) in the following
|
|
42
|
+
way:
|
|
43
|
+
|
|
44
|
+
::
|
|
45
|
+
|
|
46
|
+
$ xzcat formula.wcnf.xz
|
|
47
|
+
p wcnf 3 6 4
|
|
48
|
+
1 1 0
|
|
49
|
+
1 2 0
|
|
50
|
+
1 3 0
|
|
51
|
+
4 -1 -2 0
|
|
52
|
+
4 -1 -3 0
|
|
53
|
+
4 -2 -3 0
|
|
54
|
+
|
|
55
|
+
$ lsu.py -s glucose3 -m -v formula.wcnf.xz
|
|
56
|
+
c formula: 3 vars, 3 hard, 3 soft
|
|
57
|
+
o 2
|
|
58
|
+
s OPTIMUM FOUND
|
|
59
|
+
v -1 -2 3 0
|
|
60
|
+
c oracle time: 0.0000
|
|
61
|
+
|
|
62
|
+
Alternatively, the algorithm can be accessed and invoked through the
|
|
63
|
+
standard ``import`` interface of Python, e.g.
|
|
64
|
+
|
|
65
|
+
.. code-block:: python
|
|
66
|
+
|
|
67
|
+
>>> from pysat.examples.lsu import LSU
|
|
68
|
+
>>> from pysat.formula import WCNF
|
|
69
|
+
>>>
|
|
70
|
+
>>> wcnf = WCNF(from_file='formula.wcnf.xz')
|
|
71
|
+
>>>
|
|
72
|
+
>>> lsu = LSU(wcnf, verbose=0)
|
|
73
|
+
>>> lsu.solve() # set of hard clauses should be satisfiable
|
|
74
|
+
True
|
|
75
|
+
>>> print(lsu.cost) # cost of MaxSAT solution should be 2
|
|
76
|
+
>>> 2
|
|
77
|
+
>>> print(lsu.model)
|
|
78
|
+
[-1, -2, 3]
|
|
79
|
+
|
|
80
|
+
==============
|
|
81
|
+
Module details
|
|
82
|
+
==============
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
#
|
|
86
|
+
#==============================================================================
|
|
87
|
+
from __future__ import print_function
|
|
88
|
+
import getopt
|
|
89
|
+
from pysat.card import ITotalizer
|
|
90
|
+
from pysat.formula import CNF, WCNF, WCNFPlus
|
|
91
|
+
from pysat.solvers import Solver, SolverNames
|
|
92
|
+
from threading import Timer
|
|
93
|
+
import os
|
|
94
|
+
import sys
|
|
95
|
+
import re
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
# TODO: support weighted MaxSAT
|
|
99
|
+
#==============================================================================
|
|
100
|
+
class LSU:
|
|
101
|
+
"""
|
|
102
|
+
Linear SAT-UNSAT algorithm for MaxSAT [1]_. The algorithm can be seen
|
|
103
|
+
as a series of satisfiability oracle calls refining an upper bound on
|
|
104
|
+
the MaxSAT cost, followed by one unsatisfiability call, which stops the
|
|
105
|
+
algorithm. The implementation encodes the sum of all selector literals
|
|
106
|
+
using the *iterative totalizer encoding* [2]_. At every iteration, the
|
|
107
|
+
upper bound on the cost is reduced and enforced by adding the
|
|
108
|
+
corresponding unit size clause to the working formula. No clauses are
|
|
109
|
+
removed during the execution of the algorithm. As a result, the SAT
|
|
110
|
+
oracle is used incrementally.
|
|
111
|
+
|
|
112
|
+
.. warning:: At this point, :class:`LSU` supports only
|
|
113
|
+
**unweighted** problems.
|
|
114
|
+
|
|
115
|
+
The constructor receives an input :class:`.WCNF` formula, a name of the
|
|
116
|
+
SAT solver to use (see :class:`.SolverNames` for details), and an
|
|
117
|
+
integer verbosity level.
|
|
118
|
+
|
|
119
|
+
:param formula: input MaxSAT formula
|
|
120
|
+
:param solver: name of SAT solver
|
|
121
|
+
:param incr: enable incremental mode of Glucose
|
|
122
|
+
:param expect_interrupt: whether or not an :meth:`interrupt` call is expected
|
|
123
|
+
:param verbose: verbosity level
|
|
124
|
+
|
|
125
|
+
:type formula: :class:`.WCNF`
|
|
126
|
+
:type solver: str
|
|
127
|
+
:type incr: bool
|
|
128
|
+
:type expect_interrupt: bool
|
|
129
|
+
:type verbose: int
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
def __init__(self, formula, solver='g4', incr=False, expect_interrupt=False, verbose=0):
|
|
133
|
+
"""
|
|
134
|
+
Constructor.
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
self.verbose = verbose
|
|
138
|
+
self.solver = solver
|
|
139
|
+
self.incr = incr
|
|
140
|
+
self.expect_interrupt = expect_interrupt
|
|
141
|
+
self.formula = formula
|
|
142
|
+
self.topv = formula.nv # largest variable index
|
|
143
|
+
self.sels = [] # soft clause selector variables
|
|
144
|
+
self.tot = None # totalizer encoder for the cardinality constraint
|
|
145
|
+
self._init(formula) # initiaize SAT oracle
|
|
146
|
+
|
|
147
|
+
def _init(self, formula):
|
|
148
|
+
"""
|
|
149
|
+
SAT oracle initialization. The method creates a new SAT oracle and
|
|
150
|
+
feeds it with the formula's hard clauses. Afterwards, all soft
|
|
151
|
+
clauses of the formula are augmented with selector literals and
|
|
152
|
+
also added to the solver. The list of all introduced selectors is
|
|
153
|
+
stored in variable ``self.sels``.
|
|
154
|
+
|
|
155
|
+
:param formula: input MaxSAT formula
|
|
156
|
+
:type formula: :class:`WCNF`
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
self.oracle = Solver(name=self.solver, bootstrap_with=formula.hard,
|
|
160
|
+
incr=self.incr, use_timer=True)
|
|
161
|
+
|
|
162
|
+
for i, cl in enumerate(formula.soft):
|
|
163
|
+
# TODO: if clause is unit, use its literal as selector
|
|
164
|
+
# (ITotalizer must be extended to support PB constraints first)
|
|
165
|
+
self.topv += 1
|
|
166
|
+
selv = self.topv
|
|
167
|
+
cl.append(self.topv)
|
|
168
|
+
self.oracle.add_clause(cl)
|
|
169
|
+
self.sels.append(selv)
|
|
170
|
+
|
|
171
|
+
if self.verbose > 1:
|
|
172
|
+
print('c formula: {0} vars, {1} hard, {2} soft'.format(formula.nv, len(formula.hard), len(formula.soft)))
|
|
173
|
+
|
|
174
|
+
def __del__(self):
|
|
175
|
+
"""
|
|
176
|
+
Destructor.
|
|
177
|
+
"""
|
|
178
|
+
|
|
179
|
+
self.delete()
|
|
180
|
+
|
|
181
|
+
def __enter__(self):
|
|
182
|
+
"""
|
|
183
|
+
'with' constructor.
|
|
184
|
+
"""
|
|
185
|
+
|
|
186
|
+
return self
|
|
187
|
+
|
|
188
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
189
|
+
"""
|
|
190
|
+
'with' destructor.
|
|
191
|
+
"""
|
|
192
|
+
|
|
193
|
+
self.delete()
|
|
194
|
+
|
|
195
|
+
def delete(self):
|
|
196
|
+
"""
|
|
197
|
+
Explicit destructor of the internal SAT oracle and the
|
|
198
|
+
:class:`.ITotalizer` object.
|
|
199
|
+
"""
|
|
200
|
+
|
|
201
|
+
if self.oracle:
|
|
202
|
+
self.oracle.delete()
|
|
203
|
+
self.oracle = None
|
|
204
|
+
|
|
205
|
+
if self.tot:
|
|
206
|
+
self.tot.delete()
|
|
207
|
+
self.tot = None
|
|
208
|
+
|
|
209
|
+
def solve(self):
|
|
210
|
+
"""
|
|
211
|
+
Computes a solution to the MaxSAT problem. The method implements
|
|
212
|
+
the LSU/LSUS algorithm, i.e. it represents a loop, each iteration
|
|
213
|
+
of which calls a SAT oracle on the working MaxSAT formula and
|
|
214
|
+
refines the upper bound on the MaxSAT cost until the formula
|
|
215
|
+
becomes unsatisfiable.
|
|
216
|
+
|
|
217
|
+
Returns ``True`` if the hard part of the MaxSAT formula is
|
|
218
|
+
satisfiable, i.e. if there is a MaxSAT solution, and ``False``
|
|
219
|
+
otherwise.
|
|
220
|
+
|
|
221
|
+
:rtype: bool
|
|
222
|
+
"""
|
|
223
|
+
|
|
224
|
+
is_sat = False
|
|
225
|
+
|
|
226
|
+
while self.oracle.solve_limited(expect_interrupt=self.expect_interrupt):
|
|
227
|
+
is_sat = True
|
|
228
|
+
self.model = self.oracle.get_model()
|
|
229
|
+
self.cost = self._get_model_cost(self.formula, self.model)
|
|
230
|
+
if self.verbose:
|
|
231
|
+
print('o {0}'.format(self.cost))
|
|
232
|
+
sys.stdout.flush()
|
|
233
|
+
if self.cost == 0: # if cost is 0, then model is an optimum solution
|
|
234
|
+
break
|
|
235
|
+
self._assert_lt(self.cost)
|
|
236
|
+
|
|
237
|
+
if is_sat:
|
|
238
|
+
self.model = filter(lambda l: abs(l) <= self.formula.nv, self.model)
|
|
239
|
+
if self.verbose:
|
|
240
|
+
if self.found_optimum():
|
|
241
|
+
print('s OPTIMUM FOUND')
|
|
242
|
+
else:
|
|
243
|
+
print('s SATISFIABLE')
|
|
244
|
+
elif self.verbose:
|
|
245
|
+
print('s UNSATISFIABLE')
|
|
246
|
+
|
|
247
|
+
return is_sat
|
|
248
|
+
|
|
249
|
+
def get_model(self):
|
|
250
|
+
"""
|
|
251
|
+
This method returns a model obtained during a prior satisfiability
|
|
252
|
+
oracle call made in :func:`solve`.
|
|
253
|
+
|
|
254
|
+
:rtype: list(int)
|
|
255
|
+
"""
|
|
256
|
+
|
|
257
|
+
return self.model
|
|
258
|
+
|
|
259
|
+
def found_optimum(self):
|
|
260
|
+
"""
|
|
261
|
+
Checks if the optimum solution was found in a prior call to
|
|
262
|
+
:func:`solve`.
|
|
263
|
+
|
|
264
|
+
:rtype: bool
|
|
265
|
+
"""
|
|
266
|
+
|
|
267
|
+
return self.oracle.get_status() is not None
|
|
268
|
+
|
|
269
|
+
def _get_model_cost(self, formula, model):
|
|
270
|
+
"""
|
|
271
|
+
Given a WCNF formula and a model, the method computes the MaxSAT
|
|
272
|
+
cost of the model, i.e. the sum of weights of soft clauses that are
|
|
273
|
+
unsatisfied by the model.
|
|
274
|
+
|
|
275
|
+
:param formula: an input MaxSAT formula
|
|
276
|
+
:param model: a satisfying assignment
|
|
277
|
+
|
|
278
|
+
:type formula: :class:`.WCNF`
|
|
279
|
+
:type model: list(int)
|
|
280
|
+
|
|
281
|
+
:rtype: int
|
|
282
|
+
"""
|
|
283
|
+
|
|
284
|
+
model_set = set(model)
|
|
285
|
+
cost = 0
|
|
286
|
+
|
|
287
|
+
for i, cl in enumerate(formula.soft):
|
|
288
|
+
cost += formula.wght[i] if all(l not in model_set for l in filter(lambda l: abs(l) <= self.formula.nv, cl)) else 0
|
|
289
|
+
|
|
290
|
+
return cost
|
|
291
|
+
|
|
292
|
+
def _assert_lt(self, cost):
|
|
293
|
+
"""
|
|
294
|
+
The method enforces an upper bound on the cost of the MaxSAT
|
|
295
|
+
solution. This is done by encoding the sum of all soft clause
|
|
296
|
+
selectors with the use the iterative totalizer encoding, i.e.
|
|
297
|
+
:class:`.ITotalizer`. Note that the sum is created once, at the
|
|
298
|
+
beginning. Each of the following calls to this method only enforces
|
|
299
|
+
the upper bound on the created sum by adding the corresponding unit
|
|
300
|
+
size clause. Each such clause is added on the fly with no restart
|
|
301
|
+
of the underlying SAT oracle.
|
|
302
|
+
|
|
303
|
+
:param cost: the cost of the next MaxSAT solution is enforced to be
|
|
304
|
+
*lower* than this current cost
|
|
305
|
+
|
|
306
|
+
:type cost: int
|
|
307
|
+
"""
|
|
308
|
+
|
|
309
|
+
if self.tot == None:
|
|
310
|
+
self.tot = ITotalizer(lits=self.sels, ubound=cost-1, top_id=self.topv)
|
|
311
|
+
self.topv = self.tot.top_id
|
|
312
|
+
|
|
313
|
+
for cl in self.tot.cnf.clauses:
|
|
314
|
+
self.oracle.add_clause(cl)
|
|
315
|
+
|
|
316
|
+
self.oracle.add_clause([-self.tot.rhs[cost-1]])
|
|
317
|
+
|
|
318
|
+
def interrupt(self):
|
|
319
|
+
"""
|
|
320
|
+
Interrupt the current execution of LSU's :meth:`solve` method.
|
|
321
|
+
Can be used to enforce time limits using timer objects. The
|
|
322
|
+
interrupt must be cleared before running the LSU algorithm again
|
|
323
|
+
(see :meth:`clear_interrupt`).
|
|
324
|
+
"""
|
|
325
|
+
|
|
326
|
+
self.oracle.interrupt()
|
|
327
|
+
|
|
328
|
+
def clear_interrupt(self):
|
|
329
|
+
"""
|
|
330
|
+
Clears an interruption.
|
|
331
|
+
"""
|
|
332
|
+
|
|
333
|
+
self.oracle.clear_interrupt()
|
|
334
|
+
|
|
335
|
+
def oracle_time(self):
|
|
336
|
+
"""
|
|
337
|
+
Method for calculating and reporting the total SAT solving time.
|
|
338
|
+
"""
|
|
339
|
+
|
|
340
|
+
return self.oracle.time_accum()
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
#
|
|
344
|
+
#==============================================================================
|
|
345
|
+
class LSUPlus(LSU, object):
|
|
346
|
+
"""
|
|
347
|
+
LSU-like algorithm extended for :class:`.WCNFPlus` formulas (using
|
|
348
|
+
:class:`.Minicard`).
|
|
349
|
+
|
|
350
|
+
:param formula: input MaxSAT formula in WCNF+ format
|
|
351
|
+
:param expect_interrupt: whether or not an :meth:`interrupt` call is expected
|
|
352
|
+
:param verbose: verbosity level
|
|
353
|
+
|
|
354
|
+
:type formula: :class:`.WCNFPlus`
|
|
355
|
+
:type expect_interrupt: bool
|
|
356
|
+
:type verbose: int
|
|
357
|
+
"""
|
|
358
|
+
|
|
359
|
+
def __init__(self, formula, solver='g4', incr=False, expect_interrupt=False, verbose=0):
|
|
360
|
+
"""
|
|
361
|
+
Constructor.
|
|
362
|
+
"""
|
|
363
|
+
|
|
364
|
+
assert solver in SolverNames.gluecard3 or \
|
|
365
|
+
solver in SolverNames.gluecard4 or \
|
|
366
|
+
solver in SolverNames.minicard or \
|
|
367
|
+
solver in SolverNames.cadical195, '{0} does not support native cardinality constraints'.format(solver)
|
|
368
|
+
|
|
369
|
+
super(LSUPlus, self).__init__(formula, solver=solver, incr=incr,
|
|
370
|
+
expect_interrupt=expect_interrupt, verbose=verbose)
|
|
371
|
+
|
|
372
|
+
# we are using CaDiCaL195 and it can use external linear engine
|
|
373
|
+
if solver in SolverNames.cadical195:
|
|
374
|
+
self.oracle.activate_atmost()
|
|
375
|
+
|
|
376
|
+
# adding atmost constraints
|
|
377
|
+
for am in formula.atms:
|
|
378
|
+
self.oracle.add_atmost(*am)
|
|
379
|
+
|
|
380
|
+
def _assert_lt(self, cost):
|
|
381
|
+
"""
|
|
382
|
+
Overrides _assert_lt of :class:`.LSU` in order to use Minicard's
|
|
383
|
+
native support for cardinality constraints
|
|
384
|
+
|
|
385
|
+
:param cost: the cost of the next MaxSAT solution is enforced to
|
|
386
|
+
be *lower* than this current cost
|
|
387
|
+
|
|
388
|
+
:type cost: int
|
|
389
|
+
"""
|
|
390
|
+
|
|
391
|
+
self.oracle.add_atmost(self.sels, cost-1)
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
#
|
|
395
|
+
#==============================================================================
|
|
396
|
+
def parse_options():
|
|
397
|
+
"""
|
|
398
|
+
Parses command-line options.
|
|
399
|
+
"""
|
|
400
|
+
|
|
401
|
+
try:
|
|
402
|
+
opts, args = getopt.getopt(sys.argv[1:], 'hims:t:v', ['help', 'incr', 'model', 'solver=', 'timeout=', 'verbose'])
|
|
403
|
+
except getopt.GetoptError as err:
|
|
404
|
+
sys.stderr.write(str(err).capitalize())
|
|
405
|
+
print_usage()
|
|
406
|
+
sys.exit(1)
|
|
407
|
+
|
|
408
|
+
solver = 'g4'
|
|
409
|
+
incr = False
|
|
410
|
+
verbose = 1
|
|
411
|
+
print_model = False
|
|
412
|
+
timeout = None
|
|
413
|
+
|
|
414
|
+
for opt, arg in opts:
|
|
415
|
+
if opt in ('-h', '--help'):
|
|
416
|
+
print_usage()
|
|
417
|
+
sys.exit(0)
|
|
418
|
+
elif opt in ('-i', '--incr'):
|
|
419
|
+
incr = True
|
|
420
|
+
elif opt in ('-m', '--model'):
|
|
421
|
+
print_model = True
|
|
422
|
+
elif opt in ('-s', '--solver'):
|
|
423
|
+
solver = str(arg)
|
|
424
|
+
elif opt in ('-t', '--timeout'):
|
|
425
|
+
if str(arg) != 'none':
|
|
426
|
+
timeout = float(arg)
|
|
427
|
+
elif opt in ('-v', '--verbose'):
|
|
428
|
+
verbose += 1
|
|
429
|
+
else:
|
|
430
|
+
assert False, 'Unhandled option: {0} {1}'.format(opt, arg)
|
|
431
|
+
|
|
432
|
+
return incr, print_model, solver, timeout, verbose, args
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
#
|
|
436
|
+
#==============================================================================
|
|
437
|
+
def print_usage():
|
|
438
|
+
"""
|
|
439
|
+
Prints usage message.
|
|
440
|
+
"""
|
|
441
|
+
|
|
442
|
+
print('Usage: ' + os.path.basename(sys.argv[0]) + ' [options] dimacs-file')
|
|
443
|
+
print('Options:')
|
|
444
|
+
print(' -h, --help Show this message')
|
|
445
|
+
print(' -i, --incr Enable incremental model (for Glucose only)')
|
|
446
|
+
print(' -m, --model Print model')
|
|
447
|
+
print(' -s, --solver=<string> SAT solver to use')
|
|
448
|
+
print(' Available values: cd15, cd19, g3, g4, mc, m22, mgh (default = g4)')
|
|
449
|
+
print(' -t, --timeout=<float> Set time limit for MaxSAT solver')
|
|
450
|
+
print(' Available values: [0 .. FLOAT_MAX], none (default: none)')
|
|
451
|
+
print(' -v, --verbose Be verbose')
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
#
|
|
455
|
+
#==============================================================================
|
|
456
|
+
if __name__ == '__main__':
|
|
457
|
+
incr, print_model, solver, timeout, verbose, files = parse_options()
|
|
458
|
+
|
|
459
|
+
if files:
|
|
460
|
+
# reading standard CNF or WCNF
|
|
461
|
+
if re.search(r'cnf(\.(gz|bz2|lzma|xz|zst))?$', files[0]):
|
|
462
|
+
if re.search(r'\.wcnf(\.(gz|bz2|lzma|xz|zst))?$', files[0]):
|
|
463
|
+
formula = WCNF(from_file=files[0])
|
|
464
|
+
else: # expecting '*.cnf'
|
|
465
|
+
formula = CNF(from_file=files[0]).weighted()
|
|
466
|
+
|
|
467
|
+
lsu = LSU(formula, solver=solver, incr=incr,
|
|
468
|
+
expect_interrupt=(timeout != None), verbose=verbose)
|
|
469
|
+
|
|
470
|
+
# reading WCNF+
|
|
471
|
+
elif re.search(r'\.wcnf[p,+](\.(gz|bz2|lzma|xz|zst))?$', files[0]):
|
|
472
|
+
formula = WCNFPlus(from_file=files[0])
|
|
473
|
+
lsu = LSUPlus(formula, solver=solver, incr=incr,
|
|
474
|
+
expect_interrupt=(timeout != None), verbose=verbose)
|
|
475
|
+
else:
|
|
476
|
+
assert False, 'Unknown input file extension'
|
|
477
|
+
|
|
478
|
+
# setting a timer if necessary
|
|
479
|
+
if timeout is not None:
|
|
480
|
+
if verbose > 1:
|
|
481
|
+
print('c timeout: {0}'.format(timeout))
|
|
482
|
+
|
|
483
|
+
timer = Timer(timeout, lambda s: s.interrupt(), [lsu])
|
|
484
|
+
timer.start()
|
|
485
|
+
|
|
486
|
+
if lsu.solve():
|
|
487
|
+
if print_model:
|
|
488
|
+
print('v ' + ' '.join([str(l) for l in lsu.get_model()]), '0')
|
|
489
|
+
|
|
490
|
+
if verbose > 1:
|
|
491
|
+
print('c oracle time: {0:.4f}'.format(lsu.oracle_time()))
|
|
492
|
+
|
|
493
|
+
if timeout is not None:
|
|
494
|
+
timer.cancel()
|
|
495
|
+
else:
|
|
496
|
+
print_usage()
|