python-sat 1.8.dev25__cp312-cp312-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-312-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-312-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
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
#!python
|
|
2
|
+
#-*- coding:utf-8 -*-
|
|
3
|
+
##
|
|
4
|
+
## models.py
|
|
5
|
+
##
|
|
6
|
+
## Created on: Mar 4, 2018
|
|
7
|
+
## Author: Alexey S. Ignatiev
|
|
8
|
+
## E-mail: aignatiev@ciencias.ulisboa.pt
|
|
9
|
+
##
|
|
10
|
+
|
|
11
|
+
"""
|
|
12
|
+
===============
|
|
13
|
+
List of classes
|
|
14
|
+
===============
|
|
15
|
+
|
|
16
|
+
.. autosummary::
|
|
17
|
+
:nosignatures:
|
|
18
|
+
|
|
19
|
+
enumerate_models
|
|
20
|
+
|
|
21
|
+
==================
|
|
22
|
+
Module description
|
|
23
|
+
==================
|
|
24
|
+
|
|
25
|
+
The module implements a simple iterative enumeration of a given number of
|
|
26
|
+
models of :class:`.CNF` or :class:`CNFPlus` formula. In the latter case,
|
|
27
|
+
only :class:`.Minicard` can be used as a SAT solver. The module aims at
|
|
28
|
+
illustrating how one can work with model computation and enumeration.
|
|
29
|
+
|
|
30
|
+
The implementation facilitates the simplest use of a SAT oracle from the
|
|
31
|
+
*command line*. If one deals with the enumeration task from a Python
|
|
32
|
+
script, it is more convenient to exploit the internal model enumeration of
|
|
33
|
+
the :mod:`pysat.solvers` module. Concretely, see
|
|
34
|
+
:meth:`pysat.solvers.Solver.enum_models()`.
|
|
35
|
+
|
|
36
|
+
::
|
|
37
|
+
|
|
38
|
+
$ cat formula.cnf
|
|
39
|
+
p cnf 4 4
|
|
40
|
+
-1 2 0
|
|
41
|
+
-1 3 0
|
|
42
|
+
-2 4 0
|
|
43
|
+
3 -4 0
|
|
44
|
+
|
|
45
|
+
$ models.py -e all -s glucose3 formula.cnf
|
|
46
|
+
v -1 -2 +3 -4 0
|
|
47
|
+
v +1 +2 -3 +4 0
|
|
48
|
+
c nof models: 2
|
|
49
|
+
c accum time: 0.00s
|
|
50
|
+
c mean time: 0.00s
|
|
51
|
+
|
|
52
|
+
==============
|
|
53
|
+
Module details
|
|
54
|
+
==============
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
#
|
|
58
|
+
#==============================================================================
|
|
59
|
+
from __future__ import print_function
|
|
60
|
+
import getopt
|
|
61
|
+
import os
|
|
62
|
+
from pysat.formula import CNFPlus
|
|
63
|
+
from pysat.solvers import Solver, SolverNames
|
|
64
|
+
import sys
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
#
|
|
68
|
+
#==============================================================================
|
|
69
|
+
def enumerate_models(formula, to_enum, solver, warm=False):
|
|
70
|
+
"""
|
|
71
|
+
Enumeration procedure. It represents a loop iterating over satisfying
|
|
72
|
+
assignment for a given formula until either all or a given number of
|
|
73
|
+
them is enumerated.
|
|
74
|
+
|
|
75
|
+
:param formula: input WCNF formula
|
|
76
|
+
:param to_enum: number of models to compute
|
|
77
|
+
:param solver: name of SAT solver
|
|
78
|
+
:param warm: warm start flag
|
|
79
|
+
|
|
80
|
+
:type formula: :class:`.CNFPlus`
|
|
81
|
+
:type to_enum: int or 'all'
|
|
82
|
+
:type solver: str
|
|
83
|
+
:type warm: bool
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
with Solver(name=solver, bootstrap_with=formula.clauses,
|
|
87
|
+
use_timer=True, warm_start=warm) as s:
|
|
88
|
+
# adding native cardinality constraints if needed
|
|
89
|
+
if formula.atmosts:
|
|
90
|
+
# we are using CaDiCaL195 and it can use external linear engine
|
|
91
|
+
if solver in SolverNames.cadical195:
|
|
92
|
+
s.activate_atmost()
|
|
93
|
+
|
|
94
|
+
assert s.supports_atmost(), \
|
|
95
|
+
'{0} does not support native cardinality constraints'.format(solver)
|
|
96
|
+
|
|
97
|
+
for atm in formula.atmosts:
|
|
98
|
+
s.add_atmost(*atm)
|
|
99
|
+
|
|
100
|
+
# model enumeration and printing is done here
|
|
101
|
+
computed = 0
|
|
102
|
+
for i, model in enumerate(s.enum_models(), 1):
|
|
103
|
+
print('v {0} 0'.format(' '.join(['{0}{1}'.format('+' if v > 0 else '', v) for v in model])))
|
|
104
|
+
|
|
105
|
+
computed = i
|
|
106
|
+
if i == to_enum:
|
|
107
|
+
break
|
|
108
|
+
|
|
109
|
+
# some final statistics
|
|
110
|
+
print('c nof models: {0}'.format(computed))
|
|
111
|
+
print('c accum time: {0:.2f}s'.format(s.time_accum()))
|
|
112
|
+
|
|
113
|
+
if computed:
|
|
114
|
+
print('c mean time: {0:.2f}s'.format(s.time_accum() / computed))
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
#
|
|
118
|
+
#==============================================================================
|
|
119
|
+
def parse_options():
|
|
120
|
+
"""
|
|
121
|
+
Parses command-line options:
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
try:
|
|
125
|
+
opts, args = getopt.getopt(sys.argv[1:],
|
|
126
|
+
'e:h:s:w',
|
|
127
|
+
['enum=',
|
|
128
|
+
'help',
|
|
129
|
+
'solver=',
|
|
130
|
+
'warm'])
|
|
131
|
+
except getopt.GetoptError as err:
|
|
132
|
+
sys.stderr.write(str(err).capitalize())
|
|
133
|
+
usage()
|
|
134
|
+
sys.exit(1)
|
|
135
|
+
|
|
136
|
+
to_enum = 1
|
|
137
|
+
solver = 'g3'
|
|
138
|
+
warm = False
|
|
139
|
+
|
|
140
|
+
for opt, arg in opts:
|
|
141
|
+
if opt in ('-e', '--enum'):
|
|
142
|
+
to_enum = str(arg)
|
|
143
|
+
if to_enum == 'all':
|
|
144
|
+
to_enum = -1
|
|
145
|
+
else:
|
|
146
|
+
to_enum = int(to_enum)
|
|
147
|
+
elif opt in ('-h', '--help'):
|
|
148
|
+
usage()
|
|
149
|
+
sys.exit(0)
|
|
150
|
+
elif opt in ('-s', '--solver'):
|
|
151
|
+
solver = str(arg)
|
|
152
|
+
elif opt in ('-w', '--warm'):
|
|
153
|
+
warm = True
|
|
154
|
+
else:
|
|
155
|
+
assert False, 'Unhandled option: {0} {1}'.format(opt, arg)
|
|
156
|
+
|
|
157
|
+
return to_enum, solver, warm, args
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
#
|
|
161
|
+
#==============================================================================
|
|
162
|
+
def usage():
|
|
163
|
+
"""
|
|
164
|
+
Prints usage message.
|
|
165
|
+
"""
|
|
166
|
+
|
|
167
|
+
print('Usage:', os.path.basename(sys.argv[0]), '[options] dimacs-file')
|
|
168
|
+
print('Options:')
|
|
169
|
+
print(' -e, --enum=<int> Compute at most this number of models')
|
|
170
|
+
print(' Available values: [1 .. INT_MAX], all (default: 1)')
|
|
171
|
+
print(' -h, --help Show this message')
|
|
172
|
+
print(' -s, --solver=<string> SAT solver to use')
|
|
173
|
+
print(' Available values: cd, g3, g4, lgl, mcb, mcm, mpl, m22, mc, mgh (default = g3)')
|
|
174
|
+
print(' -w, --warm Use solver\'s warm start mode')
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
#
|
|
178
|
+
#==============================================================================
|
|
179
|
+
if __name__ == '__main__':
|
|
180
|
+
# parsing command-line options
|
|
181
|
+
to_enum, solver, warm, files = parse_options()
|
|
182
|
+
|
|
183
|
+
# reading an input formula either from a file or from stdin
|
|
184
|
+
if files:
|
|
185
|
+
formula = CNFPlus(from_file=files[0])
|
|
186
|
+
else:
|
|
187
|
+
formula = CNFPlus(from_fp=sys.stdin)
|
|
188
|
+
|
|
189
|
+
enumerate_models(formula, to_enum, solver, warm)
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
#!python
|
|
2
|
+
#-*- coding:utf-8 -*-
|
|
3
|
+
##
|
|
4
|
+
## musx.py
|
|
5
|
+
##
|
|
6
|
+
## Created on: Jan 25, 2018
|
|
7
|
+
## Author: Antonio Morgado, Alexey Ignatiev
|
|
8
|
+
## E-mail: {ajmorgado, aignatiev}@ciencias.ulisboa.pt
|
|
9
|
+
##
|
|
10
|
+
|
|
11
|
+
"""
|
|
12
|
+
===============
|
|
13
|
+
List of classes
|
|
14
|
+
===============
|
|
15
|
+
|
|
16
|
+
.. autosummary::
|
|
17
|
+
:nosignatures:
|
|
18
|
+
|
|
19
|
+
MUSX
|
|
20
|
+
|
|
21
|
+
==================
|
|
22
|
+
Module description
|
|
23
|
+
==================
|
|
24
|
+
|
|
25
|
+
This module implements a deletion-based algorithm [1]_ for extracting a
|
|
26
|
+
*minimal unsatisfiable subset* (*MUS*) of a given (unsafistiable) CNF
|
|
27
|
+
formula. This simplistic implementation can deal with *plain* and *partial*
|
|
28
|
+
CNF formulas, e.g. formulas in the DIMACS CNF and WCNF formats.
|
|
29
|
+
|
|
30
|
+
.. [1] Joao Marques-Silva. *Minimal Unsatisfiability: Models, Algorithms
|
|
31
|
+
and Applications*. ISMVL 2010. pp. 9-14
|
|
32
|
+
|
|
33
|
+
The following extraction procedure is implemented:
|
|
34
|
+
|
|
35
|
+
.. code-block:: python
|
|
36
|
+
|
|
37
|
+
# oracle: SAT solver (initialized)
|
|
38
|
+
# assump: full set of assumptions
|
|
39
|
+
|
|
40
|
+
i = 0
|
|
41
|
+
|
|
42
|
+
while i < len(assump):
|
|
43
|
+
to_test = assump[:i] + assump[(i + 1):]
|
|
44
|
+
if oracle.solve(assumptions=to_test):
|
|
45
|
+
i += 1
|
|
46
|
+
else:
|
|
47
|
+
assump = to_test
|
|
48
|
+
|
|
49
|
+
return assump
|
|
50
|
+
|
|
51
|
+
The implementation can be used as an executable (the list of available
|
|
52
|
+
command-line options can be shown using ``musx.py -h``) in the following
|
|
53
|
+
way:
|
|
54
|
+
|
|
55
|
+
::
|
|
56
|
+
|
|
57
|
+
$ cat formula.wcnf
|
|
58
|
+
p wcnf 3 6 4
|
|
59
|
+
1 1 0
|
|
60
|
+
1 2 0
|
|
61
|
+
1 3 0
|
|
62
|
+
4 -1 -2 0
|
|
63
|
+
4 -1 -3 0
|
|
64
|
+
4 -2 -3 0
|
|
65
|
+
|
|
66
|
+
$ musx.py -s glucose3 -vv formula.wcnf
|
|
67
|
+
c MUS approx: 1 2 0
|
|
68
|
+
c testing clid: 0 -> sat (keeping 0)
|
|
69
|
+
c testing clid: 1 -> sat (keeping 1)
|
|
70
|
+
c nof soft: 3
|
|
71
|
+
c MUS size: 2
|
|
72
|
+
v 1 2 0
|
|
73
|
+
c oracle time: 0.0001
|
|
74
|
+
|
|
75
|
+
Alternatively, the algorithm can be accessed and invoked through the
|
|
76
|
+
standard ``import`` interface of Python, e.g.
|
|
77
|
+
|
|
78
|
+
.. code-block:: python
|
|
79
|
+
|
|
80
|
+
>>> from pysat.examples.musx import MUSX
|
|
81
|
+
>>> from pysat.formula import WCNF
|
|
82
|
+
>>>
|
|
83
|
+
>>> wcnf = WCNF(from_file='formula.wcnf')
|
|
84
|
+
>>>
|
|
85
|
+
>>> musx = MUSX(wcnf, verbosity=0)
|
|
86
|
+
>>> musx.compute() # compute a minimally unsatisfiable set of clauses
|
|
87
|
+
[1, 2]
|
|
88
|
+
|
|
89
|
+
Note that the implementation is able to compute only one MUS (MUS
|
|
90
|
+
enumeration is not supported).
|
|
91
|
+
|
|
92
|
+
==============
|
|
93
|
+
Module details
|
|
94
|
+
==============
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
#
|
|
98
|
+
#==============================================================================
|
|
99
|
+
from __future__ import print_function
|
|
100
|
+
import getopt
|
|
101
|
+
import os
|
|
102
|
+
from pysat.formula import CNFPlus, WCNFPlus, CNF
|
|
103
|
+
from pysat.solvers import Solver, SolverNames
|
|
104
|
+
import re
|
|
105
|
+
import sys
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
#
|
|
109
|
+
#==============================================================================
|
|
110
|
+
class MUSX(object):
|
|
111
|
+
"""
|
|
112
|
+
MUS eXtractor using the deletion-based algorithm. The algorithm is
|
|
113
|
+
described in [1]_ (also see the module description above). Essentially,
|
|
114
|
+
the algorithm can be seen as an iterative process, which tries to
|
|
115
|
+
remove one soft clause at a time and check whether the remaining set of
|
|
116
|
+
soft clauses is still unsatisfiable together with the hard clauses.
|
|
117
|
+
|
|
118
|
+
The constructor of :class:`MUSX` objects receives a target
|
|
119
|
+
:class:`.CNF` or `.WCNF` formula, a SAT solver name, and a verbosity level. Note
|
|
120
|
+
that the default SAT solver is MiniSat22 (referred to as ``'m22'``, see
|
|
121
|
+
:class:`.SolverNames` for details). The default verbosity level is
|
|
122
|
+
``1``.
|
|
123
|
+
|
|
124
|
+
:param formula: input WCNF formula
|
|
125
|
+
:param solver: name of SAT solver
|
|
126
|
+
:param verbosity: verbosity level
|
|
127
|
+
|
|
128
|
+
:type formula: :class:`.WCNF`
|
|
129
|
+
:type solver: str
|
|
130
|
+
:type verbosity: int
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
def __init__(self, formula, solver='m22', verbosity=1):
|
|
134
|
+
"""
|
|
135
|
+
Constructor.
|
|
136
|
+
"""
|
|
137
|
+
|
|
138
|
+
topv, self.verbose = formula.nv, verbosity
|
|
139
|
+
|
|
140
|
+
# clause selectors and a mapping from selectors to clause ids
|
|
141
|
+
self.sels, self.vmap = [], {}
|
|
142
|
+
|
|
143
|
+
# to deal with a CNF* formula, we create its weighted version
|
|
144
|
+
if isinstance(formula, CNF):
|
|
145
|
+
formula = formula.weighted()
|
|
146
|
+
|
|
147
|
+
# constructing the oracle
|
|
148
|
+
self.oracle = Solver(name=solver, bootstrap_with=formula.hard,
|
|
149
|
+
use_timer=True)
|
|
150
|
+
|
|
151
|
+
if isinstance(formula, WCNFPlus) and formula.atms:
|
|
152
|
+
# we are using CaDiCaL195 and it can use external linear engine
|
|
153
|
+
if solver in SolverNames.cadical195:
|
|
154
|
+
self.oracle.activate_atmost()
|
|
155
|
+
|
|
156
|
+
assert self.oracle.supports_atmost(), ('{0} does not support native cardinality constraints. Make sure you'
|
|
157
|
+
' use the right type of formula.').format(solver)
|
|
158
|
+
|
|
159
|
+
for atm in formula.atms:
|
|
160
|
+
self.oracle.add_atmost(*atm)
|
|
161
|
+
|
|
162
|
+
# relaxing soft clauses and adding them to the oracle
|
|
163
|
+
for i, cl in enumerate(formula.soft):
|
|
164
|
+
topv += 1
|
|
165
|
+
|
|
166
|
+
self.sels.append(topv)
|
|
167
|
+
self.vmap[topv] = i
|
|
168
|
+
|
|
169
|
+
self.oracle.add_clause(cl + [-topv])
|
|
170
|
+
|
|
171
|
+
def __enter__(self):
|
|
172
|
+
"""
|
|
173
|
+
'with' constructor.
|
|
174
|
+
"""
|
|
175
|
+
|
|
176
|
+
return self
|
|
177
|
+
|
|
178
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
179
|
+
"""
|
|
180
|
+
'with' destructor.
|
|
181
|
+
"""
|
|
182
|
+
|
|
183
|
+
self.oracle.delete()
|
|
184
|
+
self.oracle = None
|
|
185
|
+
|
|
186
|
+
def delete(self):
|
|
187
|
+
"""
|
|
188
|
+
Explicit destructor of the internal SAT oracle.
|
|
189
|
+
"""
|
|
190
|
+
|
|
191
|
+
if self.oracle:
|
|
192
|
+
self.oracle.delete()
|
|
193
|
+
self.oracle = None
|
|
194
|
+
|
|
195
|
+
def compute(self):
|
|
196
|
+
"""
|
|
197
|
+
This is the main method of the :class:`MUSX` class. It computes a
|
|
198
|
+
set of soft clauses belonging to an MUS of the input formula.
|
|
199
|
+
First, the method checks whether the formula is satisfiable. If it
|
|
200
|
+
is, nothing else is done. Otherwise, an *unsatisfiable core* of the
|
|
201
|
+
formula is extracted, which is later used as an over-approximation
|
|
202
|
+
of an MUS refined in :func:`_compute`.
|
|
203
|
+
"""
|
|
204
|
+
|
|
205
|
+
# cheking whether or not the formula is unsatisfiable
|
|
206
|
+
if not self.oracle.solve(assumptions=self.sels):
|
|
207
|
+
# get an overapproximation of an MUS
|
|
208
|
+
approx = sorted(self.oracle.get_core())
|
|
209
|
+
|
|
210
|
+
if self.verbose:
|
|
211
|
+
print('c MUS approx:', ' '.join([str(self.vmap[sel] + 1) for sel in approx]), '0')
|
|
212
|
+
|
|
213
|
+
# iterate over clauses in the approximation and try to delete them
|
|
214
|
+
mus = self._compute(approx)
|
|
215
|
+
|
|
216
|
+
# return an MUS
|
|
217
|
+
return list(map(lambda x: self.vmap[x] + 1, mus))
|
|
218
|
+
|
|
219
|
+
def _compute(self, approx):
|
|
220
|
+
"""
|
|
221
|
+
Deletion-based MUS extraction. Given an over-approximation of an
|
|
222
|
+
MUS, i.e. an unsatisfiable core previously returned by a SAT
|
|
223
|
+
oracle, the method represents a loop, which at each iteration
|
|
224
|
+
removes a clause from the core and checks whether the remaining
|
|
225
|
+
clauses of the approximation are unsatisfiable together with the
|
|
226
|
+
hard clauses.
|
|
227
|
+
|
|
228
|
+
Soft clauses are (de)activated using the standard MiniSat-like
|
|
229
|
+
assumptions interface [2]_. Each soft clause :math:`c` is augmented
|
|
230
|
+
with a selector literal :math:`s`, e.g. :math:`(c) \\gets (c \\vee
|
|
231
|
+
\\neg{s})`. As a result, clause :math:`c` can be activated by
|
|
232
|
+
assuming literal :math:`s`. The over-approximation provided as an
|
|
233
|
+
input is specified as a list of selector literals for clauses in
|
|
234
|
+
the unsatisfiable core.
|
|
235
|
+
|
|
236
|
+
.. [2] Niklas Eén, Niklas Sörensson. *Temporal induction by
|
|
237
|
+
incremental SAT solving*. Electr. Notes Theor. Comput. Sci.
|
|
238
|
+
89(4). 2003. pp. 543-560
|
|
239
|
+
|
|
240
|
+
:param approx: an over-approximation of an MUS
|
|
241
|
+
:type approx: list(int)
|
|
242
|
+
|
|
243
|
+
Note that the method does not return. Instead, after its execution,
|
|
244
|
+
the input over-approximation is refined and contains an MUS.
|
|
245
|
+
"""
|
|
246
|
+
|
|
247
|
+
i = 0
|
|
248
|
+
|
|
249
|
+
while i < len(approx):
|
|
250
|
+
to_test = approx[:i] + approx[(i + 1):]
|
|
251
|
+
sel, clid = approx[i], self.vmap[approx[i]]
|
|
252
|
+
|
|
253
|
+
if self.verbose > 1:
|
|
254
|
+
print('c testing clid: {0}'.format(clid), end='')
|
|
255
|
+
|
|
256
|
+
if self.oracle.solve(assumptions=to_test):
|
|
257
|
+
if self.verbose > 1:
|
|
258
|
+
print(' -> sat (keeping {0})'.format(clid))
|
|
259
|
+
|
|
260
|
+
i += 1
|
|
261
|
+
else:
|
|
262
|
+
if self.verbose > 1:
|
|
263
|
+
print(' -> unsat (removing {0})'.format(clid))
|
|
264
|
+
|
|
265
|
+
approx = to_test
|
|
266
|
+
|
|
267
|
+
return approx
|
|
268
|
+
|
|
269
|
+
def oracle_time(self):
|
|
270
|
+
"""
|
|
271
|
+
Method for calculating and reporting the total SAT solving time.
|
|
272
|
+
"""
|
|
273
|
+
|
|
274
|
+
return self.oracle.time_accum()
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
#
|
|
278
|
+
#==============================================================================
|
|
279
|
+
def parse_options():
|
|
280
|
+
"""
|
|
281
|
+
Parses command-line option
|
|
282
|
+
"""
|
|
283
|
+
|
|
284
|
+
try:
|
|
285
|
+
opts, args = getopt.getopt(sys.argv[1:], 'hs:v', ['help', 'solver=', 'verbose'])
|
|
286
|
+
except getopt.GetoptError as err:
|
|
287
|
+
sys.stderr.write(str(err).capitalize())
|
|
288
|
+
usage()
|
|
289
|
+
sys.exit(1)
|
|
290
|
+
|
|
291
|
+
solver = 'm22'
|
|
292
|
+
verbose = 0
|
|
293
|
+
|
|
294
|
+
for opt, arg in opts:
|
|
295
|
+
if opt in ('-h', '--help'):
|
|
296
|
+
usage()
|
|
297
|
+
sys.exit(0)
|
|
298
|
+
elif opt in ('-s', '--solver'):
|
|
299
|
+
solver = str(arg)
|
|
300
|
+
elif opt in ('-v', '--verbose'):
|
|
301
|
+
verbose += 1
|
|
302
|
+
else:
|
|
303
|
+
assert False, 'Unhandled option: {0} {1}'.format(opt, arg)
|
|
304
|
+
|
|
305
|
+
return solver, verbose, args
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
#
|
|
309
|
+
#==============================================================================
|
|
310
|
+
def usage():
|
|
311
|
+
"""
|
|
312
|
+
Prints usage message.
|
|
313
|
+
"""
|
|
314
|
+
|
|
315
|
+
print('Usage:', os.path.basename(sys.argv[0]), '[options] dimacs-file')
|
|
316
|
+
print('Options:')
|
|
317
|
+
print(' -h, --help')
|
|
318
|
+
print(' -s, --solver SAT solver to use')
|
|
319
|
+
print(' Available values: cd15, cd19, g3, lgl, mcb, mcm, mpl, m22, mc, mgh (default: m22)')
|
|
320
|
+
print(' -v, --verbose Be verbose')
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
#
|
|
324
|
+
#==============================================================================
|
|
325
|
+
if __name__ == '__main__':
|
|
326
|
+
solver, verbose, files = parse_options()
|
|
327
|
+
|
|
328
|
+
if files:
|
|
329
|
+
# parsing the input formula
|
|
330
|
+
if re.search(r'\.wcnf[p|+]?(\.(gz|bz2|lzma|xz|zst))?$', files[0]):
|
|
331
|
+
formula = WCNFPlus(from_file=files[0])
|
|
332
|
+
else: # expecting '*.cnf[,p,+].*'
|
|
333
|
+
formula = CNFPlus(from_file=files[0]).weighted()
|
|
334
|
+
|
|
335
|
+
with MUSX(formula, solver=solver, verbosity=verbose) as musx:
|
|
336
|
+
mus = musx.compute()
|
|
337
|
+
|
|
338
|
+
if mus:
|
|
339
|
+
if verbose:
|
|
340
|
+
print('c nof soft: {0}'.format(len(formula.soft)))
|
|
341
|
+
print('c MUS size: {0}'.format(len(mus)))
|
|
342
|
+
|
|
343
|
+
print('v', ' '.join([str(clid) for clid in mus]), '0')
|
|
344
|
+
print('c oracle time: {0:.4f}'.format(musx.oracle_time()))
|