python-sat 1.8.dev20__tar.gz → 1.8.dev21__tar.gz
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.
- {python_sat-1.8.dev20/python_sat.egg-info → python_sat-1.8.dev21}/PKG-INFO +12 -2
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/examples/lbx.py +45 -8
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/examples/mcsls.py +42 -8
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/examples/optux.py +30 -8
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/examples/rc2.py +82 -34
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/pysat/__init__.py +1 -1
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/pysat/process.py +16 -2
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/pysat/solvers.py +4 -2
- {python_sat-1.8.dev20 → python_sat-1.8.dev21/python_sat.egg-info}/PKG-INFO +12 -2
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/python_sat.egg-info/SOURCES.txt +0 -1
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/patches/glucose421.patch +366 -408
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/pysolvers.cc +100 -34
- python_sat-1.8.dev21/tests/test_process.py +67 -0
- python_sat-1.8.dev20/solvers/cadical170.tar.gz +0 -0
- python_sat-1.8.dev20/tests/test_process.py +0 -26
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/LICENSE.txt +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/MANIFEST.in +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/README.rst +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/allies/__init__.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/allies/approxmc.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/allies/unigen.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/cardenc/bitwise.hh +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/cardenc/card.hh +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/cardenc/clset.hh +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/cardenc/common.hh +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/cardenc/itot.hh +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/cardenc/ladder.hh +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/cardenc/mto.hh +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/cardenc/pairwise.hh +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/cardenc/ptypes.hh +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/cardenc/pycard.cc +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/cardenc/seqcounter.hh +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/cardenc/sortcard.hh +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/cardenc/utils.hh +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/examples/__init__.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/examples/bica.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/examples/fm.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/examples/genhard.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/examples/hitman.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/examples/lsu.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/examples/models.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/examples/musx.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/examples/primer.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/examples/usage.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/pysat/_fileio.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/pysat/_utils.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/pysat/card.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/pysat/engines.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/pysat/formula.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/pysat/pb.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/python_sat.egg-info/dependency_links.txt +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/python_sat.egg-info/requires.txt +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/python_sat.egg-info/top_level.txt +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/requirements.txt +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/setup.cfg +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/setup.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/cadical103.tar.gz +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/cadical153.tar.gz +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/cadical195.tar.gz +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/glucose30.tar.gz +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/glucose41.tar.gz +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/glucose421.tar.gz +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/lingeling.tar.gz +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/maplechrono.zip +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/maplecm.zip +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/maplesat.zip +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/mergesat3.tar.gz +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/minicard.tar.gz +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/minisat22.tar.gz +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/minisatgh.zip +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/patches/cadical103.patch +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/patches/cadical153.patch +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/patches/cadical195.patch +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/patches/glucose30.patch +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/patches/glucose41.patch +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/patches/gluecard30.patch +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/patches/gluecard41.patch +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/patches/lingeling.patch +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/patches/maplechrono.patch +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/patches/maplecm.patch +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/patches/maplesat.patch +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/patches/mergesat3.patch +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/patches/minicard.patch +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/patches/minisat22.patch +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/patches/minisatgh.patch +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/solvers/prepare.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/tests/test_accum_stats.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/tests/test_atmost.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/tests/test_atmost1.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/tests/test_atmostk.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/tests/test_boolengine.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/tests/test_clausification.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/tests/test_cnf.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/tests/test_equals1.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/tests/test_formula_unique.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/tests/test_propagate.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/tests/test_unique_model.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/tests/test_unique_mus.py +0 -0
- {python_sat-1.8.dev20 → python_sat-1.8.dev21}/tests/test_warmstart.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: python-sat
|
|
3
|
-
Version: 1.8.
|
|
3
|
+
Version: 1.8.dev21
|
|
4
4
|
Summary: A Python library for prototyping with SAT oracles
|
|
5
5
|
Home-page: https://github.com/pysathq/pysat
|
|
6
6
|
Author: Alexey Ignatiev, Joao Marques-Silva, Antonio Morgado
|
|
@@ -19,6 +19,16 @@ Provides-Extra: pblib
|
|
|
19
19
|
Requires-Dist: pypblib>=0.0.3; extra == "pblib"
|
|
20
20
|
Provides-Extra: unigen
|
|
21
21
|
Requires-Dist: pyunigen>=4.1.20; extra == "unigen"
|
|
22
|
+
Dynamic: author
|
|
23
|
+
Dynamic: author-email
|
|
24
|
+
Dynamic: description
|
|
25
|
+
Dynamic: description-content-type
|
|
26
|
+
Dynamic: home-page
|
|
27
|
+
Dynamic: license
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
Dynamic: provides-extra
|
|
30
|
+
Dynamic: requires-dist
|
|
31
|
+
Dynamic: summary
|
|
22
32
|
|
|
23
33
|
|
|
24
34
|
A Python library providing a simple interface to a number of state-of-art
|
|
@@ -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
|
from six.moves import range
|
|
@@ -112,25 +113,37 @@ class LBX(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
|
|
@@ -166,10 +179,27 @@ class LBX(object):
|
|
|
166
179
|
self.topv += 1
|
|
167
180
|
sel = self.topv
|
|
168
181
|
|
|
169
|
-
|
|
182
|
+
if process == 0:
|
|
183
|
+
self.oracle.add_clause(cl + [-sel])
|
|
184
|
+
else:
|
|
185
|
+
# adding to formula's hard clauses
|
|
186
|
+
# if any preprocessing is required
|
|
187
|
+
hard.append(cl + [-sel])
|
|
170
188
|
|
|
171
189
|
self.sels.append(sel)
|
|
172
190
|
|
|
191
|
+
# finally, applying formula processing, if any
|
|
192
|
+
if process:
|
|
193
|
+
# the processor is immediately destroyed,
|
|
194
|
+
# as we do not need to restore the models
|
|
195
|
+
with Processor(bootstrap_with=hard) as processor:
|
|
196
|
+
proc = processor.process(rounds=process, freeze=self.sels)
|
|
197
|
+
self.oracle.append_formula(proc)
|
|
198
|
+
|
|
199
|
+
# we won't have access to the original soft
|
|
200
|
+
# clauses in the case of formula preprocessing
|
|
201
|
+
self.soft = [[l] for l in self.sels]
|
|
202
|
+
|
|
173
203
|
def __del__(self):
|
|
174
204
|
"""
|
|
175
205
|
Destructor.
|
|
@@ -514,10 +544,11 @@ def parse_options():
|
|
|
514
544
|
|
|
515
545
|
try:
|
|
516
546
|
opts, args = getopt.getopt(sys.argv[1:],
|
|
517
|
-
'de:
|
|
547
|
+
'de:hp:p:s:v',
|
|
518
548
|
['dcalls',
|
|
519
549
|
'enum=',
|
|
520
550
|
'help',
|
|
551
|
+
'process=',
|
|
521
552
|
'solver=',
|
|
522
553
|
'verbose'])
|
|
523
554
|
except getopt.GetoptError as err:
|
|
@@ -527,6 +558,7 @@ def parse_options():
|
|
|
527
558
|
|
|
528
559
|
dcalls = False
|
|
529
560
|
to_enum = 1
|
|
561
|
+
process = 0
|
|
530
562
|
solver = 'm22'
|
|
531
563
|
verbose = 0
|
|
532
564
|
|
|
@@ -540,6 +572,8 @@ def parse_options():
|
|
|
540
572
|
elif opt in ('-h', '--help'):
|
|
541
573
|
usage()
|
|
542
574
|
sys.exit(0)
|
|
575
|
+
elif opt in ('-p', '--process'):
|
|
576
|
+
process = int(arg)
|
|
543
577
|
elif opt in ('-s', '--solver'):
|
|
544
578
|
solver = str(arg)
|
|
545
579
|
elif opt in ('-v', '--verbose'):
|
|
@@ -547,7 +581,7 @@ def parse_options():
|
|
|
547
581
|
else:
|
|
548
582
|
assert False, 'Unhandled option: {0} {1}'.format(opt, arg)
|
|
549
583
|
|
|
550
|
-
return dcalls, to_enum, solver, verbose, args
|
|
584
|
+
return dcalls, to_enum, solver, process, verbose, args
|
|
551
585
|
|
|
552
586
|
|
|
553
587
|
#
|
|
@@ -563,6 +597,8 @@ def usage():
|
|
|
563
597
|
print(' -e, --enum=<string> How many solutions to compute')
|
|
564
598
|
print(' Available values: [1 .. all] (default: 1)')
|
|
565
599
|
print(' -h, --help')
|
|
600
|
+
print(' -p, --process=<int> Number of processing rounds')
|
|
601
|
+
print(' Available values: [0 .. INT_MAX] (default = 0)')
|
|
566
602
|
print(' -s, --solver SAT solver to use')
|
|
567
603
|
print(' Available values: cd15, cd19, g3, g4, lgl, mcb, mcm, mpl, m22, mc, mgh (default = m22)')
|
|
568
604
|
print(' -v, --verbose Be verbose')
|
|
@@ -571,7 +607,7 @@ def usage():
|
|
|
571
607
|
#
|
|
572
608
|
#==============================================================================
|
|
573
609
|
if __name__ == '__main__':
|
|
574
|
-
dcalls, to_enum, solver, verbose, files = parse_options()
|
|
610
|
+
dcalls, to_enum, solver, process, verbose, files = parse_options()
|
|
575
611
|
|
|
576
612
|
if type(to_enum) == str:
|
|
577
613
|
to_enum = 0
|
|
@@ -584,7 +620,8 @@ if __name__ == '__main__':
|
|
|
584
620
|
else: # expecting '*.cnf[,p,+].*'
|
|
585
621
|
formula = CNFPlus(from_file=files[0]).weighted()
|
|
586
622
|
|
|
587
|
-
with LBX(formula, use_cld=dcalls, solver_name=solver,
|
|
623
|
+
with LBX(formula, use_cld=dcalls, solver_name=solver, process=process,
|
|
624
|
+
use_timer=True) as mcsls:
|
|
588
625
|
for i, mcs in enumerate(mcsls.enumerate()):
|
|
589
626
|
if verbose:
|
|
590
627
|
print('c MCS:', ' '.join([str(cl_id) for cl_id in mcs]), '0')
|
|
@@ -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,25 +113,37 @@ 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
|
|
@@ -167,13 +180,27 @@ class MCSls(object):
|
|
|
167
180
|
sel = self.topv
|
|
168
181
|
|
|
169
182
|
new_cl.append(-sel) # creating a new selector
|
|
170
|
-
|
|
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)
|
|
171
190
|
else:
|
|
172
191
|
sel = cl[0]
|
|
173
192
|
|
|
174
193
|
self.sels.append(sel)
|
|
175
194
|
self.smap[sel] = len(self.sels)
|
|
176
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
|
+
|
|
177
204
|
def __del__(self):
|
|
178
205
|
"""
|
|
179
206
|
Destructor.
|
|
@@ -489,10 +516,11 @@ def parse_options():
|
|
|
489
516
|
|
|
490
517
|
try:
|
|
491
518
|
opts, args = getopt.getopt(sys.argv[1:],
|
|
492
|
-
'de:
|
|
519
|
+
'de:hp:s:v',
|
|
493
520
|
['dcalls',
|
|
494
521
|
'enum=',
|
|
495
522
|
'help',
|
|
523
|
+
'process=',
|
|
496
524
|
'solver=',
|
|
497
525
|
'verbose'])
|
|
498
526
|
except getopt.GetoptError as err:
|
|
@@ -502,6 +530,7 @@ def parse_options():
|
|
|
502
530
|
|
|
503
531
|
dcalls = False
|
|
504
532
|
to_enum = 1
|
|
533
|
+
process = 0
|
|
505
534
|
solver = 'm22'
|
|
506
535
|
verbose = 0
|
|
507
536
|
|
|
@@ -515,6 +544,8 @@ def parse_options():
|
|
|
515
544
|
elif opt in ('-h', '--help'):
|
|
516
545
|
usage()
|
|
517
546
|
sys.exit(0)
|
|
547
|
+
elif opt in ('-p', '--process'):
|
|
548
|
+
process = int(arg)
|
|
518
549
|
elif opt in ('-s', '--solver'):
|
|
519
550
|
solver = str(arg)
|
|
520
551
|
elif opt in ('-v', '--verbose'):
|
|
@@ -522,7 +553,7 @@ def parse_options():
|
|
|
522
553
|
else:
|
|
523
554
|
assert False, 'Unhandled option: {0} {1}'.format(opt, arg)
|
|
524
555
|
|
|
525
|
-
return dcalls, to_enum, solver, verbose, args
|
|
556
|
+
return dcalls, to_enum, solver, process, verbose, args
|
|
526
557
|
|
|
527
558
|
|
|
528
559
|
#
|
|
@@ -538,6 +569,8 @@ def usage():
|
|
|
538
569
|
print(' -e, --enum=<string> How many solutions to compute')
|
|
539
570
|
print(' Available values: [1 .. all] (default: 1)')
|
|
540
571
|
print(' -h, --help')
|
|
572
|
+
print(' -p, --process=<int> Number of processing rounds')
|
|
573
|
+
print(' Available values: [0 .. INT_MAX] (default = 0)')
|
|
541
574
|
print(' -s, --solver SAT solver to use')
|
|
542
575
|
print(' Available values: cd15, cd19, g3, g4, lgl, mcb, mcm, mpl, m22, mc, mgh (default = m22)')
|
|
543
576
|
print(' -v, --verbose Be verbose')
|
|
@@ -546,7 +579,7 @@ def usage():
|
|
|
546
579
|
#
|
|
547
580
|
#==============================================================================
|
|
548
581
|
if __name__ == '__main__':
|
|
549
|
-
dcalls, to_enum, solver, verbose, files = parse_options()
|
|
582
|
+
dcalls, to_enum, solver, process, verbose, files = parse_options()
|
|
550
583
|
|
|
551
584
|
if type(to_enum) == str:
|
|
552
585
|
to_enum = 0
|
|
@@ -559,7 +592,8 @@ if __name__ == '__main__':
|
|
|
559
592
|
else: # expecting '*.cnf[,p,+].*'
|
|
560
593
|
formula = CNFPlus(from_file=files[0]).weighted()
|
|
561
594
|
|
|
562
|
-
with MCSls(formula, use_cld=dcalls, solver_name=solver,
|
|
595
|
+
with MCSls(formula, use_cld=dcalls, solver_name=solver,
|
|
596
|
+
process=process, use_timer=True) as mcsls:
|
|
563
597
|
for i, mcs in enumerate(mcsls.enumerate()):
|
|
564
598
|
if verbose:
|
|
565
599
|
print('c MCS:', ' '.join([str(cl_id) for cl_id in mcs]), '0')
|
|
@@ -111,6 +111,7 @@ 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.process import Processor
|
|
114
115
|
from pysat.solvers import Solver, SolverNames
|
|
115
116
|
import re
|
|
116
117
|
import sys
|
|
@@ -168,6 +169,11 @@ class OptUx(object):
|
|
|
168
169
|
support *hard* phase setting, i.e. user preferences will not be
|
|
169
170
|
overwritten by the *phase saving* heuristic [8]_.
|
|
170
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
|
+
|
|
171
177
|
Finally, one more optional input parameter ``cover`` is to be used
|
|
172
178
|
when exhaustive enumeration of MUSes is not necessary and the tool can
|
|
173
179
|
stop as soon as a given formula is covered by the set of currently
|
|
@@ -198,6 +204,7 @@ class OptUx(object):
|
|
|
198
204
|
:param exhaust: do core exhaustion
|
|
199
205
|
:param minz: do heuristic core reduction
|
|
200
206
|
:param nodisj: do not enumerate disjoint MCSes
|
|
207
|
+
:param process: apply formula preprocessing this many times
|
|
201
208
|
:param puresat: use pure SAT-based hitting set enumeration
|
|
202
209
|
:param unsorted: apply unsorted MUS enumeration
|
|
203
210
|
:param trim: do core trimming at most this number of times
|
|
@@ -211,6 +218,7 @@ class OptUx(object):
|
|
|
211
218
|
:type exhaust: bool
|
|
212
219
|
:type minz: bool
|
|
213
220
|
:type nodisj: bool
|
|
221
|
+
:type process: int
|
|
214
222
|
:type puresat: str
|
|
215
223
|
:type unsorted: bool
|
|
216
224
|
:type trim: int
|
|
@@ -218,7 +226,7 @@ class OptUx(object):
|
|
|
218
226
|
"""
|
|
219
227
|
|
|
220
228
|
def __init__(self, formula, solver='g3', adapt=False, cover=None,
|
|
221
|
-
dcalls=False, exhaust=False, minz=False, nodisj=False,
|
|
229
|
+
dcalls=False, exhaust=False, minz=False, nodisj=False, process=0,
|
|
222
230
|
puresat=False, unsorted=False, trim=False, verbose=0):
|
|
223
231
|
"""
|
|
224
232
|
Constructor.
|
|
@@ -247,6 +255,15 @@ class OptUx(object):
|
|
|
247
255
|
self._process_soft(formula)
|
|
248
256
|
self.formula.nv = self.topv
|
|
249
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
|
+
|
|
250
267
|
# creating an unweighted copy
|
|
251
268
|
unweighted = self.formula.copy()
|
|
252
269
|
unweighted.wght = [1 for w in unweighted.wght]
|
|
@@ -554,11 +571,11 @@ def parse_options():
|
|
|
554
571
|
"""
|
|
555
572
|
|
|
556
573
|
try:
|
|
557
|
-
opts, args = getopt.getopt(sys.argv[1:], 'ac:de:hmnp:s:t:uvx',
|
|
574
|
+
opts, args = getopt.getopt(sys.argv[1:], 'ac:de:hmnp:P:s:t:uvx',
|
|
558
575
|
['adapt', 'cover=', 'dcalls', 'enum=',
|
|
559
576
|
'exhaust', 'help', 'minimize', 'no-disj',
|
|
560
|
-
'solver=', 'puresat=', '
|
|
561
|
-
'trim=', 'verbose'])
|
|
577
|
+
'solver=', 'puresat=', 'process=',
|
|
578
|
+
'unsorted', 'trim=', 'verbose'])
|
|
562
579
|
except getopt.GetoptError as err:
|
|
563
580
|
sys.stderr.write(str(err).capitalize() + '\n')
|
|
564
581
|
usage()
|
|
@@ -572,6 +589,7 @@ def parse_options():
|
|
|
572
589
|
no_disj = False
|
|
573
590
|
to_enum = 1
|
|
574
591
|
solver = 'g3'
|
|
592
|
+
process = 0
|
|
575
593
|
puresat = False
|
|
576
594
|
unsorted = False
|
|
577
595
|
trim = 0
|
|
@@ -599,6 +617,8 @@ def parse_options():
|
|
|
599
617
|
no_disj = True
|
|
600
618
|
elif opt in ('-p', '--puresat'):
|
|
601
619
|
puresat = str(arg)
|
|
620
|
+
elif opt in ('-P', '--process'):
|
|
621
|
+
process = int(arg)
|
|
602
622
|
elif opt in ('-s', '--solver'):
|
|
603
623
|
solver = str(arg)
|
|
604
624
|
elif opt in ('-u', '--unsorted'):
|
|
@@ -613,7 +633,7 @@ def parse_options():
|
|
|
613
633
|
assert False, 'Unhandled option: {0} {1}'.format(opt, arg)
|
|
614
634
|
|
|
615
635
|
return adapt, cover, dcalls, exhaust, minz, no_disj, trim, to_enum, \
|
|
616
|
-
solver, puresat, unsorted, verbose, args
|
|
636
|
+
solver, process, puresat, unsorted, verbose, args
|
|
617
637
|
|
|
618
638
|
|
|
619
639
|
#
|
|
@@ -637,6 +657,8 @@ def usage():
|
|
|
637
657
|
print(' -p, --puresat=<string> Use a pure SAT-based hitting set enumerator')
|
|
638
658
|
print(' Available values: cd15, cd19, lgl, mgh (default = mgh)')
|
|
639
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)')
|
|
640
662
|
print(' -s, --solver SAT solver to use')
|
|
641
663
|
print(' Available values: cd15, cd19, g3, g4, lgl, mcb, mcm, mpl, m22, mc, mgh (default = g3)')
|
|
642
664
|
print(' -t, --trim=<int> How many times to trim unsatisfiable cores')
|
|
@@ -650,7 +672,7 @@ def usage():
|
|
|
650
672
|
#==============================================================================
|
|
651
673
|
if __name__ == '__main__':
|
|
652
674
|
adapt, cover, dcalls, exhaust, minz, no_disj, trim, to_enum, solver, \
|
|
653
|
-
puresat, unsorted, verbose, files = parse_options()
|
|
675
|
+
process, puresat, unsorted, verbose, files = parse_options()
|
|
654
676
|
|
|
655
677
|
if files:
|
|
656
678
|
# reading standard CNF, WCNF, or (W)CNF+
|
|
@@ -667,8 +689,8 @@ if __name__ == '__main__':
|
|
|
667
689
|
# creating an object of OptUx
|
|
668
690
|
with OptUx(formula, solver=solver, adapt=adapt, cover=cover,
|
|
669
691
|
dcalls=dcalls, exhaust=exhaust, minz=minz, nodisj=no_disj,
|
|
670
|
-
puresat=puresat, unsorted=unsorted,
|
|
671
|
-
verbose=verbose) as optux:
|
|
692
|
+
process=process, puresat=puresat, unsorted=unsorted,
|
|
693
|
+
trim=trim, verbose=verbose) as optux:
|
|
672
694
|
|
|
673
695
|
# iterating over the necessary number of optimal MUSes
|
|
674
696
|
for i, mus in enumerate(optux.enumerate()):
|