python-sat 0.1.8.dev10__cp310-cp310-win_amd64.whl → 1.8.dev26__cp310-cp310-win_amd64.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.cp310-win_amd64.pyd +0 -0
- pysat/__init__.py +4 -4
- pysat/_fileio.py +30 -14
- pysat/allies/approxmc.py +22 -22
- pysat/allies/unigen.py +435 -0
- pysat/card.py +13 -12
- pysat/engines.py +1302 -0
- pysat/examples/bbscan.py +663 -0
- pysat/examples/bica.py +691 -0
- pysat/examples/fm.py +12 -8
- pysat/examples/genhard.py +24 -23
- pysat/examples/hitman.py +53 -37
- pysat/examples/lbx.py +56 -15
- pysat/examples/lsu.py +28 -14
- pysat/examples/mcsls.py +53 -15
- pysat/examples/models.py +6 -4
- pysat/examples/musx.py +15 -7
- pysat/examples/optux.py +71 -32
- pysat/examples/primer.py +620 -0
- pysat/examples/rc2.py +268 -69
- pysat/formula.py +3241 -229
- pysat/pb.py +85 -37
- pysat/process.py +16 -2
- pysat/solvers.py +2119 -724
- pysolvers.cp310-win_amd64.pyd +0 -0
- {python_sat-0.1.8.dev10.data → python_sat-1.8.dev26.data}/scripts/approxmc.py +22 -22
- python_sat-1.8.dev26.data/scripts/bbscan.py +663 -0
- python_sat-1.8.dev26.data/scripts/bica.py +691 -0
- {python_sat-0.1.8.dev10.data → python_sat-1.8.dev26.data}/scripts/fm.py +12 -8
- {python_sat-0.1.8.dev10.data → python_sat-1.8.dev26.data}/scripts/genhard.py +24 -23
- {python_sat-0.1.8.dev10.data → python_sat-1.8.dev26.data}/scripts/lbx.py +56 -15
- {python_sat-0.1.8.dev10.data → python_sat-1.8.dev26.data}/scripts/lsu.py +28 -14
- {python_sat-0.1.8.dev10.data → python_sat-1.8.dev26.data}/scripts/mcsls.py +53 -15
- {python_sat-0.1.8.dev10.data → python_sat-1.8.dev26.data}/scripts/models.py +6 -4
- {python_sat-0.1.8.dev10.data → python_sat-1.8.dev26.data}/scripts/musx.py +15 -7
- {python_sat-0.1.8.dev10.data → python_sat-1.8.dev26.data}/scripts/optux.py +71 -32
- python_sat-1.8.dev26.data/scripts/primer.py +620 -0
- {python_sat-0.1.8.dev10.data → python_sat-1.8.dev26.data}/scripts/rc2.py +268 -69
- python_sat-1.8.dev26.data/scripts/unigen.py +435 -0
- {python_sat-0.1.8.dev10.dist-info → python_sat-1.8.dev26.dist-info}/METADATA +19 -5
- python_sat-1.8.dev26.dist-info/RECORD +48 -0
- {python_sat-0.1.8.dev10.dist-info → python_sat-1.8.dev26.dist-info}/WHEEL +1 -1
- python_sat-0.1.8.dev10.dist-info/RECORD +0 -39
- {python_sat-0.1.8.dev10.dist-info → python_sat-1.8.dev26.dist-info/licenses}/LICENSE.txt +0 -0
- {python_sat-0.1.8.dev10.dist-info → python_sat-1.8.dev26.dist-info}/top_level.txt +0 -0
pysat/examples/mcsls.py
CHANGED
|
@@ -90,6 +90,7 @@ import getopt
|
|
|
90
90
|
from math import copysign
|
|
91
91
|
import os
|
|
92
92
|
from pysat.formula import CNFPlus, WCNFPlus
|
|
93
|
+
from pysat.process import Processor
|
|
93
94
|
from pysat.solvers import Solver, SolverNames
|
|
94
95
|
import re
|
|
95
96
|
import sys
|
|
@@ -112,30 +113,46 @@ class MCSls(object):
|
|
|
112
113
|
``use_cld`` is set to ``False``. Internal SAT solver's timer is also
|
|
113
114
|
disabled by default, i.e. ``use_timer`` is ``False``.
|
|
114
115
|
|
|
116
|
+
Additionally, the input formula can be preprocessed before running MCS
|
|
117
|
+
enumeration. This is controlled by the input parameter ``process``
|
|
118
|
+
whose integer value signifies the number of processing rounds to be
|
|
119
|
+
applied. The number of rounds is set to 0 by default.
|
|
120
|
+
|
|
115
121
|
:param formula: unsatisfiable partial CNF formula
|
|
116
122
|
:param use_cld: whether or not to use "clause :math:`D`"
|
|
117
123
|
:param solver_name: SAT oracle name
|
|
124
|
+
:param process: apply formula preprocessing this many times
|
|
118
125
|
:param use_timer: whether or not to use SAT solver's timer
|
|
119
126
|
|
|
120
127
|
:type formula: :class:`.WCNF`
|
|
121
128
|
:type use_cld: bool
|
|
122
129
|
:type solver_name: str
|
|
130
|
+
:type process: int
|
|
123
131
|
:type use_timer: bool
|
|
124
132
|
"""
|
|
125
133
|
|
|
126
|
-
def __init__(self, formula, use_cld=False, solver_name='m22',
|
|
134
|
+
def __init__(self, formula, use_cld=False, solver_name='m22', process=0,
|
|
135
|
+
use_timer=False):
|
|
127
136
|
"""
|
|
128
137
|
Constructor.
|
|
129
138
|
"""
|
|
130
139
|
|
|
140
|
+
# dealing with preprocessing, if required
|
|
141
|
+
hard = formula.hard if process > 0 else []
|
|
142
|
+
|
|
131
143
|
# bootstrapping the solver with hard clauses
|
|
132
|
-
self.oracle = Solver(name=solver_name,
|
|
133
|
-
|
|
144
|
+
self.oracle = Solver(name=solver_name,
|
|
145
|
+
bootstrap_with=formula.hard if process == 0 else [],
|
|
146
|
+
use_timer=use_timer)
|
|
134
147
|
self.solver = solver_name
|
|
135
148
|
|
|
136
149
|
# adding native cardinality constraints (if any) as hard clauses
|
|
137
150
|
# this can be done only if the Minicard solver is in use
|
|
138
151
|
if isinstance(formula, WCNFPlus) and formula.atms:
|
|
152
|
+
# we are using CaDiCaL195 and it can use external linear engine
|
|
153
|
+
if solver_name in SolverNames.cadical195:
|
|
154
|
+
self.oracle.activate_atmost()
|
|
155
|
+
|
|
139
156
|
assert self.oracle.supports_atmost(), \
|
|
140
157
|
'{0} does not support native cardinality constraints. Make sure you use the right type of formula.'.format(solver_name)
|
|
141
158
|
|
|
@@ -163,13 +180,27 @@ class MCSls(object):
|
|
|
163
180
|
sel = self.topv
|
|
164
181
|
|
|
165
182
|
new_cl.append(-sel) # creating a new selector
|
|
166
|
-
|
|
183
|
+
|
|
184
|
+
if process == 0:
|
|
185
|
+
self.oracle.add_clause(new_cl)
|
|
186
|
+
else:
|
|
187
|
+
# adding to formula's hard clauses
|
|
188
|
+
# if any preprocessing is required
|
|
189
|
+
hard.append(new_cl)
|
|
167
190
|
else:
|
|
168
191
|
sel = cl[0]
|
|
169
192
|
|
|
170
193
|
self.sels.append(sel)
|
|
171
194
|
self.smap[sel] = len(self.sels)
|
|
172
195
|
|
|
196
|
+
# finally, applying formula processing, if any
|
|
197
|
+
if process:
|
|
198
|
+
# the processor is immediately destroyed,
|
|
199
|
+
# as we do not need to restore the models
|
|
200
|
+
with Processor(bootstrap_with=hard) as processor:
|
|
201
|
+
proc = processor.process(rounds=process, freeze=self.sels)
|
|
202
|
+
self.oracle.append_formula(proc)
|
|
203
|
+
|
|
173
204
|
def __del__(self):
|
|
174
205
|
"""
|
|
175
206
|
Destructor.
|
|
@@ -485,10 +516,11 @@ def parse_options():
|
|
|
485
516
|
|
|
486
517
|
try:
|
|
487
518
|
opts, args = getopt.getopt(sys.argv[1:],
|
|
488
|
-
'de:
|
|
519
|
+
'de:hp:s:v',
|
|
489
520
|
['dcalls',
|
|
490
521
|
'enum=',
|
|
491
522
|
'help',
|
|
523
|
+
'process=',
|
|
492
524
|
'solver=',
|
|
493
525
|
'verbose'])
|
|
494
526
|
except getopt.GetoptError as err:
|
|
@@ -498,6 +530,7 @@ def parse_options():
|
|
|
498
530
|
|
|
499
531
|
dcalls = False
|
|
500
532
|
to_enum = 1
|
|
533
|
+
process = 0
|
|
501
534
|
solver = 'm22'
|
|
502
535
|
verbose = 0
|
|
503
536
|
|
|
@@ -511,6 +544,8 @@ def parse_options():
|
|
|
511
544
|
elif opt in ('-h', '--help'):
|
|
512
545
|
usage()
|
|
513
546
|
sys.exit(0)
|
|
547
|
+
elif opt in ('-p', '--process'):
|
|
548
|
+
process = int(arg)
|
|
514
549
|
elif opt in ('-s', '--solver'):
|
|
515
550
|
solver = str(arg)
|
|
516
551
|
elif opt in ('-v', '--verbose'):
|
|
@@ -518,7 +553,7 @@ def parse_options():
|
|
|
518
553
|
else:
|
|
519
554
|
assert False, 'Unhandled option: {0} {1}'.format(opt, arg)
|
|
520
555
|
|
|
521
|
-
return dcalls, to_enum, solver, verbose, args
|
|
556
|
+
return dcalls, to_enum, solver, process, verbose, args
|
|
522
557
|
|
|
523
558
|
|
|
524
559
|
#
|
|
@@ -534,28 +569,31 @@ def usage():
|
|
|
534
569
|
print(' -e, --enum=<string> How many solutions to compute')
|
|
535
570
|
print(' Available values: [1 .. all] (default: 1)')
|
|
536
571
|
print(' -h, --help')
|
|
572
|
+
print(' -p, --process=<int> Number of processing rounds')
|
|
573
|
+
print(' Available values: [0 .. INT_MAX] (default = 0)')
|
|
537
574
|
print(' -s, --solver SAT solver to use')
|
|
538
|
-
print(' Available values: g3, g4, lgl, mcb, mcm, mpl, m22, mc, mgh (default = m22)')
|
|
575
|
+
print(' Available values: cd15, cd19, g3, g4, lgl, mcb, mcm, mpl, m22, mc, mgh (default = m22)')
|
|
539
576
|
print(' -v, --verbose Be verbose')
|
|
540
577
|
|
|
541
578
|
|
|
542
579
|
#
|
|
543
580
|
#==============================================================================
|
|
544
581
|
if __name__ == '__main__':
|
|
545
|
-
dcalls, to_enum, solver, verbose, files = parse_options()
|
|
582
|
+
dcalls, to_enum, solver, process, verbose, files = parse_options()
|
|
546
583
|
|
|
547
584
|
if type(to_enum) == str:
|
|
548
585
|
to_enum = 0
|
|
549
586
|
|
|
550
587
|
if files:
|
|
551
588
|
# reading standard CNF, WCNF, or (W)CNF+
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
with MCSls(formula, use_cld=dcalls, solver_name=solver,
|
|
589
|
+
assert re.search(r'cnf[p|+]?(\.(gz|bz2|lzma|xz|zst))?$', files[0]), 'Unknown input file extension'
|
|
590
|
+
if re.search(r'\.wcnf[p|+]?(\.(gz|bz2|lzma|xz|zst))?$', files[0]):
|
|
591
|
+
formula = WCNFPlus(from_file=files[0])
|
|
592
|
+
else: # expecting '*.cnf[,p,+].*'
|
|
593
|
+
formula = CNFPlus(from_file=files[0]).weighted()
|
|
594
|
+
|
|
595
|
+
with MCSls(formula, use_cld=dcalls, solver_name=solver,
|
|
596
|
+
process=process, use_timer=True) as mcsls:
|
|
559
597
|
for i, mcs in enumerate(mcsls.enumerate()):
|
|
560
598
|
if verbose:
|
|
561
599
|
print('c MCS:', ' '.join([str(cl_id) for cl_id in mcs]), '0')
|
pysat/examples/models.py
CHANGED
|
@@ -87,10 +87,12 @@ def enumerate_models(formula, to_enum, solver, warm=False):
|
|
|
87
87
|
use_timer=True, warm_start=warm) as s:
|
|
88
88
|
# adding native cardinality constraints if needed
|
|
89
89
|
if formula.atmosts:
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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)
|
|
94
96
|
|
|
95
97
|
for atm in formula.atmosts:
|
|
96
98
|
s.add_atmost(*atm)
|
pysat/examples/musx.py
CHANGED
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
from __future__ import print_function
|
|
100
100
|
import getopt
|
|
101
101
|
import os
|
|
102
|
-
from pysat.formula import CNFPlus, WCNFPlus
|
|
102
|
+
from pysat.formula import CNFPlus, WCNFPlus, CNF
|
|
103
103
|
from pysat.solvers import Solver, SolverNames
|
|
104
104
|
import re
|
|
105
105
|
import sys
|
|
@@ -116,7 +116,7 @@ class MUSX(object):
|
|
|
116
116
|
soft clauses is still unsatisfiable together with the hard clauses.
|
|
117
117
|
|
|
118
118
|
The constructor of :class:`MUSX` objects receives a target
|
|
119
|
-
:class:`.WCNF` formula, a SAT solver name, and a verbosity level. Note
|
|
119
|
+
:class:`.CNF` or `.WCNF` formula, a SAT solver name, and a verbosity level. Note
|
|
120
120
|
that the default SAT solver is MiniSat22 (referred to as ``'m22'``, see
|
|
121
121
|
:class:`.SolverNames` for details). The default verbosity level is
|
|
122
122
|
``1``.
|
|
@@ -140,13 +140,21 @@ class MUSX(object):
|
|
|
140
140
|
# clause selectors and a mapping from selectors to clause ids
|
|
141
141
|
self.sels, self.vmap = [], {}
|
|
142
142
|
|
|
143
|
+
# to deal with a CNF* formula, we create its weighted version
|
|
144
|
+
if isinstance(formula, CNF):
|
|
145
|
+
formula = formula.weighted()
|
|
146
|
+
|
|
143
147
|
# constructing the oracle
|
|
144
148
|
self.oracle = Solver(name=solver, bootstrap_with=formula.hard,
|
|
145
149
|
use_timer=True)
|
|
146
150
|
|
|
147
151
|
if isinstance(formula, WCNFPlus) and formula.atms:
|
|
148
|
-
|
|
149
|
-
|
|
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)
|
|
150
158
|
|
|
151
159
|
for atm in formula.atms:
|
|
152
160
|
self.oracle.add_atmost(*atm)
|
|
@@ -219,7 +227,7 @@ class MUSX(object):
|
|
|
219
227
|
|
|
220
228
|
Soft clauses are (de)activated using the standard MiniSat-like
|
|
221
229
|
assumptions interface [2]_. Each soft clause :math:`c` is augmented
|
|
222
|
-
with a selector literal :math:`s`, e.g. :math:`(c)
|
|
230
|
+
with a selector literal :math:`s`, e.g. :math:`(c) \\gets (c \\vee
|
|
223
231
|
\\neg{s})`. As a result, clause :math:`c` can be activated by
|
|
224
232
|
assuming literal :math:`s`. The over-approximation provided as an
|
|
225
233
|
input is specified as a list of selector literals for clauses in
|
|
@@ -308,7 +316,7 @@ def usage():
|
|
|
308
316
|
print('Options:')
|
|
309
317
|
print(' -h, --help')
|
|
310
318
|
print(' -s, --solver SAT solver to use')
|
|
311
|
-
print(' Available values: g3, lgl, mcb, mcm, mpl, m22, mc, mgh (default: m22)')
|
|
319
|
+
print(' Available values: cd15, cd19, g3, lgl, mcb, mcm, mpl, m22, mc, mgh (default: m22)')
|
|
312
320
|
print(' -v, --verbose Be verbose')
|
|
313
321
|
|
|
314
322
|
|
|
@@ -319,7 +327,7 @@ if __name__ == '__main__':
|
|
|
319
327
|
|
|
320
328
|
if files:
|
|
321
329
|
# parsing the input formula
|
|
322
|
-
if re.search('\.wcnf[p|+]?(\.(gz|bz2|lzma|xz))?$', files[0]):
|
|
330
|
+
if re.search(r'\.wcnf[p|+]?(\.(gz|bz2|lzma|xz|zst))?$', files[0]):
|
|
323
331
|
formula = WCNFPlus(from_file=files[0])
|
|
324
332
|
else: # expecting '*.cnf[,p,+].*'
|
|
325
333
|
formula = CNFPlus(from_file=files[0]).weighted()
|
pysat/examples/optux.py
CHANGED
|
@@ -111,7 +111,8 @@ import os
|
|
|
111
111
|
from pysat.examples.hitman import Atom, Hitman
|
|
112
112
|
from pysat.examples.rc2 import RC2
|
|
113
113
|
from pysat.formula import CNFPlus, WCNFPlus
|
|
114
|
-
from pysat.
|
|
114
|
+
from pysat.process import Processor
|
|
115
|
+
from pysat.solvers import Solver, SolverNames
|
|
115
116
|
import re
|
|
116
117
|
import sys
|
|
117
118
|
|
|
@@ -130,10 +131,12 @@ class OptUx(object):
|
|
|
130
131
|
|
|
131
132
|
As a result, OptUx applies exhaustive *disjoint* minimal correction
|
|
132
133
|
subset (MCS) enumeration [1]_, [2]_, [3]_, [4]_ with the incremental
|
|
133
|
-
use of RC2 [5]_ as an underlying MaxSAT solver.
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
134
|
+
use of RC2 [5]_ as an underlying MaxSAT solver. Disjoint MCS
|
|
135
|
+
enumeration is run only if the corresponding input parameter
|
|
136
|
+
``nodisj`` is set to ``False``. Once disjoint MCSes are enumerated,
|
|
137
|
+
they are used to bootstrap a hitting set solver. This implementation
|
|
138
|
+
uses :class:`.Hitman` as a hitting set solver, which is again based on
|
|
139
|
+
RC2.
|
|
137
140
|
|
|
138
141
|
Note that in the main implicit hitting enumeration loop of the
|
|
139
142
|
algorithm, OptUx follows Forqes in that it does not reduce correction
|
|
@@ -166,6 +169,11 @@ class OptUx(object):
|
|
|
166
169
|
support *hard* phase setting, i.e. user preferences will not be
|
|
167
170
|
overwritten by the *phase saving* heuristic [8]_.
|
|
168
171
|
|
|
172
|
+
Additionally, the input formula can be preprocessed before running MUS
|
|
173
|
+
enumeration. This is controlled by the input parameter ``process``
|
|
174
|
+
whose integer value signifies the number of processing rounds to be
|
|
175
|
+
applied. The number of rounds is set to 0 by default.
|
|
176
|
+
|
|
169
177
|
Finally, one more optional input parameter ``cover`` is to be used
|
|
170
178
|
when exhaustive enumeration of MUSes is not necessary and the tool can
|
|
171
179
|
stop as soon as a given formula is covered by the set of currently
|
|
@@ -195,6 +203,8 @@ class OptUx(object):
|
|
|
195
203
|
:param dcalls: apply clause D oracle calls (for unsorted enumeration only)
|
|
196
204
|
:param exhaust: do core exhaustion
|
|
197
205
|
:param minz: do heuristic core reduction
|
|
206
|
+
:param nodisj: do not enumerate disjoint MCSes
|
|
207
|
+
:param process: apply formula preprocessing this many times
|
|
198
208
|
:param puresat: use pure SAT-based hitting set enumeration
|
|
199
209
|
:param unsorted: apply unsorted MUS enumeration
|
|
200
210
|
:param trim: do core trimming at most this number of times
|
|
@@ -207,6 +217,8 @@ class OptUx(object):
|
|
|
207
217
|
:type dcalls: bool
|
|
208
218
|
:type exhaust: bool
|
|
209
219
|
:type minz: bool
|
|
220
|
+
:type nodisj: bool
|
|
221
|
+
:type process: int
|
|
210
222
|
:type puresat: str
|
|
211
223
|
:type unsorted: bool
|
|
212
224
|
:type trim: int
|
|
@@ -214,8 +226,8 @@ class OptUx(object):
|
|
|
214
226
|
"""
|
|
215
227
|
|
|
216
228
|
def __init__(self, formula, solver='g3', adapt=False, cover=None,
|
|
217
|
-
dcalls=False, exhaust=False, minz=False,
|
|
218
|
-
|
|
229
|
+
dcalls=False, exhaust=False, minz=False, nodisj=False, process=0,
|
|
230
|
+
puresat=False, unsorted=False, trim=False, verbose=0):
|
|
219
231
|
"""
|
|
220
232
|
Constructor.
|
|
221
233
|
"""
|
|
@@ -243,13 +255,25 @@ class OptUx(object):
|
|
|
243
255
|
self._process_soft(formula)
|
|
244
256
|
self.formula.nv = self.topv
|
|
245
257
|
|
|
258
|
+
# applying formula processing (if any)
|
|
259
|
+
if process:
|
|
260
|
+
# the processor is immediately destroyed,
|
|
261
|
+
# as we do not need to restore the models
|
|
262
|
+
with Processor(bootstrap_with=self.formula.hard) as processor:
|
|
263
|
+
proc = processor.process(rounds=process, freeze=self.sels)
|
|
264
|
+
self.formula.hard = proc.clauses
|
|
265
|
+
self.formula.nv = max(self.formula.nv, proc.nv)
|
|
266
|
+
|
|
246
267
|
# creating an unweighted copy
|
|
247
268
|
unweighted = self.formula.copy()
|
|
248
269
|
unweighted.wght = [1 for w in unweighted.wght]
|
|
249
270
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
271
|
+
if not nodisj:
|
|
272
|
+
# enumerating disjoint MCSes (including unit-size MCSes)
|
|
273
|
+
to_hit, self.units = self._disjoint(unweighted, solver, adapt, exhaust,
|
|
274
|
+
minz, trim)
|
|
275
|
+
else:
|
|
276
|
+
to_hit, self.units, self.disj_time = [], [], 0.
|
|
253
277
|
|
|
254
278
|
if self.verbose > 2:
|
|
255
279
|
print('c mcses: {0} unit, {1} disj'.format(len(self.units),
|
|
@@ -286,9 +310,13 @@ class OptUx(object):
|
|
|
286
310
|
# SAT oracle bootstrapped with the hard clauses; note that
|
|
287
311
|
# clauses of the unit-size MCSes are enforced to be enabled
|
|
288
312
|
self.oracle = Solver(name=solver, bootstrap_with=unweighted.hard +
|
|
289
|
-
[[mcs] for mcs in self.units])
|
|
313
|
+
[[mcs] for mcs in self.units], use_timer=True)
|
|
290
314
|
|
|
291
315
|
if unweighted.atms:
|
|
316
|
+
if solver in SolverNames.cadical195:
|
|
317
|
+
# we are using CaDiCaL195 and it can use external linear engine
|
|
318
|
+
self.oracle.activate_atmost()
|
|
319
|
+
|
|
292
320
|
assert self.oracle.supports_atmost(), \
|
|
293
321
|
'{0} does not support native cardinality constraints. Make sure you use the right type of formula.'.format(self.solver)
|
|
294
322
|
|
|
@@ -434,7 +462,7 @@ class OptUx(object):
|
|
|
434
462
|
break
|
|
435
463
|
|
|
436
464
|
# extracting the MCS corresponding to the model
|
|
437
|
-
falsified =
|
|
465
|
+
falsified = [l for l in self.sels if model[abs(l) - 1] == -l]
|
|
438
466
|
|
|
439
467
|
# unit size or not?
|
|
440
468
|
if len(falsified) > 1:
|
|
@@ -500,7 +528,7 @@ class OptUx(object):
|
|
|
500
528
|
# the candidate subset is satisfiable,
|
|
501
529
|
# thus extracting a correction subset
|
|
502
530
|
model = self.oracle.get_model()
|
|
503
|
-
cs =
|
|
531
|
+
cs = [l for l in self.sels if model[abs(l) - 1] == -l]
|
|
504
532
|
|
|
505
533
|
# hitting the new correction subset
|
|
506
534
|
self.hitman.hit(cs, weights=self.weights)
|
|
@@ -543,10 +571,11 @@ def parse_options():
|
|
|
543
571
|
"""
|
|
544
572
|
|
|
545
573
|
try:
|
|
546
|
-
opts, args = getopt.getopt(sys.argv[1:], 'ac:de:
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
574
|
+
opts, args = getopt.getopt(sys.argv[1:], 'ac:de:hmnp:P:s:t:uvx',
|
|
575
|
+
['adapt', 'cover=', 'dcalls', 'enum=',
|
|
576
|
+
'exhaust', 'help', 'minimize', 'no-disj',
|
|
577
|
+
'solver=', 'puresat=', 'process=',
|
|
578
|
+
'unsorted', 'trim=', 'verbose'])
|
|
550
579
|
except getopt.GetoptError as err:
|
|
551
580
|
sys.stderr.write(str(err).capitalize() + '\n')
|
|
552
581
|
usage()
|
|
@@ -557,8 +586,10 @@ def parse_options():
|
|
|
557
586
|
dcalls = False
|
|
558
587
|
exhaust = False
|
|
559
588
|
minz = False
|
|
589
|
+
no_disj = False
|
|
560
590
|
to_enum = 1
|
|
561
|
-
solver = '
|
|
591
|
+
solver = 'g3'
|
|
592
|
+
process = 0
|
|
562
593
|
puresat = False
|
|
563
594
|
unsorted = False
|
|
564
595
|
trim = 0
|
|
@@ -582,8 +613,12 @@ def parse_options():
|
|
|
582
613
|
sys.exit(0)
|
|
583
614
|
elif opt in ('-m', '--minimize'):
|
|
584
615
|
minz = True
|
|
616
|
+
elif opt in ('-n', '--no-disj'):
|
|
617
|
+
no_disj = True
|
|
585
618
|
elif opt in ('-p', '--puresat'):
|
|
586
619
|
puresat = str(arg)
|
|
620
|
+
elif opt in ('-P', '--process'):
|
|
621
|
+
process = int(arg)
|
|
587
622
|
elif opt in ('-s', '--solver'):
|
|
588
623
|
solver = str(arg)
|
|
589
624
|
elif opt in ('-u', '--unsorted'):
|
|
@@ -597,8 +632,8 @@ def parse_options():
|
|
|
597
632
|
else:
|
|
598
633
|
assert False, 'Unhandled option: {0} {1}'.format(opt, arg)
|
|
599
634
|
|
|
600
|
-
return adapt, cover, dcalls, exhaust, minz, trim, to_enum,
|
|
601
|
-
puresat, unsorted, verbose, args
|
|
635
|
+
return adapt, cover, dcalls, exhaust, minz, no_disj, trim, to_enum, \
|
|
636
|
+
solver, process, puresat, unsorted, verbose, args
|
|
602
637
|
|
|
603
638
|
|
|
604
639
|
#
|
|
@@ -618,11 +653,14 @@ def usage():
|
|
|
618
653
|
print(' Available values: [1 .. INT_MAX], all (default: 1)')
|
|
619
654
|
print(' -h, --help Show this message')
|
|
620
655
|
print(' -m, --minimize Use a heuristic unsatisfiable core minimizer')
|
|
656
|
+
print(' -n, --no-disj Do not enumerate disjoint MCSes')
|
|
621
657
|
print(' -p, --puresat=<string> Use a pure SAT-based hitting set enumerator')
|
|
622
|
-
print(' Available values: cd15, lgl, mgh (default = mgh)')
|
|
658
|
+
print(' Available values: cd15, cd19, lgl, mgh (default = mgh)')
|
|
623
659
|
print(' Requires: unsorted mode, i.e. \'-u\'')
|
|
660
|
+
print(' -P, --process=<int> Number of processing rounds')
|
|
661
|
+
print(' Available values: [0 .. INT_MAX] (default = 0)')
|
|
624
662
|
print(' -s, --solver SAT solver to use')
|
|
625
|
-
print(' Available values: g3, g4, lgl, mcb, mcm, mpl, m22, mc, mgh (default =
|
|
663
|
+
print(' Available values: cd15, cd19, g3, g4, lgl, mcb, mcm, mpl, m22, mc, mgh (default = g3)')
|
|
626
664
|
print(' -t, --trim=<int> How many times to trim unsatisfiable cores')
|
|
627
665
|
print(' Available values: [0 .. INT_MAX] (default = 0)')
|
|
628
666
|
print(' -u, --unsorted Enumerate MUSes in an unsorted way')
|
|
@@ -633,25 +671,26 @@ def usage():
|
|
|
633
671
|
#
|
|
634
672
|
#==============================================================================
|
|
635
673
|
if __name__ == '__main__':
|
|
636
|
-
adapt, cover, dcalls, exhaust, minz, trim, to_enum, solver,
|
|
637
|
-
unsorted, verbose, files = parse_options()
|
|
674
|
+
adapt, cover, dcalls, exhaust, minz, no_disj, trim, to_enum, solver, \
|
|
675
|
+
process, puresat, unsorted, verbose, files = parse_options()
|
|
638
676
|
|
|
639
677
|
if files:
|
|
640
678
|
# reading standard CNF, WCNF, or (W)CNF+
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
679
|
+
assert re.search(r'cnf[p|+]?(\.(gz|bz2|lzma|xz|zst))?$', files[0]), 'Unknown input file extension'
|
|
680
|
+
if re.search(r'\.wcnf[p|+]?(\.(gz|bz2|lzma|xz|zst))?$', files[0]):
|
|
681
|
+
formula = WCNFPlus(from_file=files[0])
|
|
682
|
+
else: # expecting '*.cnf[,p,+].*'
|
|
683
|
+
formula = CNFPlus(from_file=files[0]).weighted()
|
|
646
684
|
|
|
647
685
|
if cover: # expecting '*.cnf[,p,+].*' only!
|
|
648
|
-
assert re.search(r'cnf[p|+]?(\.(gz|bz2|lzma|xz))?$', cover), '
|
|
686
|
+
assert re.search(r'cnf[p|+]?(\.(gz|bz2|lzma|xz|zst))?$', cover), 'Wrong file for formula to cover'
|
|
649
687
|
cover = CNFPlus(from_file=cover)
|
|
650
688
|
|
|
651
689
|
# creating an object of OptUx
|
|
652
690
|
with OptUx(formula, solver=solver, adapt=adapt, cover=cover,
|
|
653
|
-
|
|
654
|
-
|
|
691
|
+
dcalls=dcalls, exhaust=exhaust, minz=minz, nodisj=no_disj,
|
|
692
|
+
process=process, puresat=puresat, unsorted=unsorted,
|
|
693
|
+
trim=trim, verbose=verbose) as optux:
|
|
655
694
|
|
|
656
695
|
# iterating over the necessary number of optimal MUSes
|
|
657
696
|
for i, mus in enumerate(optux.enumerate()):
|