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
pysat/process.py
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
#-*- coding:utf-8 -*-
|
|
3
|
+
##
|
|
4
|
+
## process.py
|
|
5
|
+
##
|
|
6
|
+
## Created on: Jan 17, 2023
|
|
7
|
+
## Author: Christos Karamanos
|
|
8
|
+
## E-mail: karamanos.christos@gmail.com
|
|
9
|
+
##
|
|
10
|
+
|
|
11
|
+
"""
|
|
12
|
+
===============
|
|
13
|
+
List of classes
|
|
14
|
+
===============
|
|
15
|
+
|
|
16
|
+
.. autosummary::
|
|
17
|
+
:nosignatures:
|
|
18
|
+
|
|
19
|
+
Processor
|
|
20
|
+
|
|
21
|
+
==================
|
|
22
|
+
Module description
|
|
23
|
+
==================
|
|
24
|
+
|
|
25
|
+
This module provides access to the preprocessor functionality of `CaDiCaL
|
|
26
|
+
1.5.3 <https://github.com/arminbiere/cadical>`__. It can be used to
|
|
27
|
+
process [1]_ (also see references therein) a given CNF formula and output
|
|
28
|
+
a another formula, which is guaranteed to be *equisatisfiable* with the
|
|
29
|
+
original formula. The processor can be invoked for a user-provided number
|
|
30
|
+
of rounds. Also, the following preprocessing techniques can be used when
|
|
31
|
+
running the processor:
|
|
32
|
+
|
|
33
|
+
- blocked clause elimination
|
|
34
|
+
- covered clause elimination
|
|
35
|
+
- globally-blocked clause elimination
|
|
36
|
+
- equivalent literal substitution
|
|
37
|
+
- bounded variable elimination
|
|
38
|
+
- failed literal probing
|
|
39
|
+
- hyper binary resolution
|
|
40
|
+
- clause subsumption
|
|
41
|
+
- clause vivification
|
|
42
|
+
|
|
43
|
+
.. [1] Armin Biere, Matti Järvisalo, Benjamin Kiesl. *Preprocessing in SAT
|
|
44
|
+
Solving*. In *Handbook of Satisfiability - Second Edition*. pp. 391-435
|
|
45
|
+
|
|
46
|
+
Importantly, the module provides a user with a possibility to freeze some
|
|
47
|
+
of the formula's variables so that they aren't eliminated, which may be
|
|
48
|
+
useful when unsatisfiability preserving processing is required - usable in
|
|
49
|
+
MCS and MUS enumeration as well as MaxSAT solving.
|
|
50
|
+
|
|
51
|
+
Note that the numerous parameters used in CaDiCaL for tweaking the
|
|
52
|
+
preprocessor's behavior are currently unavailable here. (Default values
|
|
53
|
+
are used.)
|
|
54
|
+
|
|
55
|
+
.. code-block:: python
|
|
56
|
+
|
|
57
|
+
>>> from pysat.formula import CNF
|
|
58
|
+
>>> from pysat.process import Processor
|
|
59
|
+
>>> from pysat.solvers import Solver
|
|
60
|
+
>>>
|
|
61
|
+
>>> cnf = CNF(from_clauses=[[1, 2], [3, 2], [-1, 4, -2], [3, -2], [3, 4]])
|
|
62
|
+
>>> processor = Processor(bootstrap_with=cnf)
|
|
63
|
+
>>>
|
|
64
|
+
>>> processed = processor.process()
|
|
65
|
+
>>> print(processed.clauses)
|
|
66
|
+
[]
|
|
67
|
+
>>> print(processed.status)
|
|
68
|
+
True
|
|
69
|
+
>>>
|
|
70
|
+
>>> with Solver(bootstrap_with=processed) as solver:
|
|
71
|
+
... solver.solve()
|
|
72
|
+
True
|
|
73
|
+
... print('proc model:', solver.get_model())
|
|
74
|
+
proc model: []
|
|
75
|
+
... print('orig model:', processor.restore(solver.get_model()))
|
|
76
|
+
orig model: [1, -2, 3, -4]
|
|
77
|
+
>>>
|
|
78
|
+
>>> processor.delete()
|
|
79
|
+
|
|
80
|
+
==============
|
|
81
|
+
Module details
|
|
82
|
+
==============
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
#
|
|
86
|
+
#==============================================================================
|
|
87
|
+
from pysat.formula import CNF
|
|
88
|
+
from pysat.solvers import Cadical153
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
#
|
|
92
|
+
#==============================================================================
|
|
93
|
+
class Processor(object):
|
|
94
|
+
"""
|
|
95
|
+
This class provides interface to CaDiCaL's preprocessor. The only
|
|
96
|
+
input parameter is ``bootstrap_with``, which is expected to be a
|
|
97
|
+
:class:`.CNF` formula or a list (or iterable) of clauses.
|
|
98
|
+
|
|
99
|
+
:param bootstrap_with: a list of clauses for processor initialization.
|
|
100
|
+
:type bootstrap_with: :class:`.CNF` or iterable(iterable(int))
|
|
101
|
+
|
|
102
|
+
Once created and used, a processor must be deleted with the
|
|
103
|
+
:meth:`delete` method. Alternatively, if created using the ``with``
|
|
104
|
+
statement, deletion is done automatically when the end of the ``with``
|
|
105
|
+
block is reached. It is *important* to keep the processor if a user
|
|
106
|
+
wants to restore a model of the original formula.
|
|
107
|
+
|
|
108
|
+
The main methods of this class are :meth:`process` and
|
|
109
|
+
:meth:`restore`. The former calls CaDiCaL's preprocessor while the
|
|
110
|
+
latter can be used to reconstruct a model of the original formula
|
|
111
|
+
given a model for the processed formula as illustrated below.
|
|
112
|
+
|
|
113
|
+
Note how keeping the :class:`Processor` object is needed for model
|
|
114
|
+
restoration. (If it is deleted, the information needed for model
|
|
115
|
+
reconstruction is lost.)
|
|
116
|
+
|
|
117
|
+
.. code-block:: python
|
|
118
|
+
|
|
119
|
+
>>> from pysat.process import Processor
|
|
120
|
+
>>> from pysat.solvers import Solver
|
|
121
|
+
>>>
|
|
122
|
+
>>> processor = Processor(bootstrap_with=[[-1, 2], [1, -2]])
|
|
123
|
+
>>> processor.append_formula([[-2, 3], [1]])
|
|
124
|
+
>>> processor.add_clause([-3, 4])
|
|
125
|
+
>>>
|
|
126
|
+
>>> processed = processor.process()
|
|
127
|
+
>>> print(processed.clauses)
|
|
128
|
+
[]
|
|
129
|
+
>>> print(processed.status)
|
|
130
|
+
True
|
|
131
|
+
>>>
|
|
132
|
+
>>> with Solver(bootstrap_with=processed) as solver:
|
|
133
|
+
... solver.solve()
|
|
134
|
+
True
|
|
135
|
+
... print('proc model:', solver.get_model())
|
|
136
|
+
proc model: []
|
|
137
|
+
... print('orig model:', processor.restore(solver.get_model()))
|
|
138
|
+
orig model: [1, 2, 3, 4]
|
|
139
|
+
>>>
|
|
140
|
+
>>> processor.delete()
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
def __init__(self, bootstrap_with=None):
|
|
144
|
+
"""
|
|
145
|
+
Basic constructor.
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
# immediately creating a CaDiCaL object
|
|
149
|
+
self.cadical = Cadical153()
|
|
150
|
+
|
|
151
|
+
# status of processor is True by default meaning
|
|
152
|
+
# that the input formula *is not* unsatisfiable
|
|
153
|
+
self.status = True
|
|
154
|
+
|
|
155
|
+
if bootstrap_with:
|
|
156
|
+
self.append_formula(bootstrap_with)
|
|
157
|
+
|
|
158
|
+
def __del__(self):
|
|
159
|
+
"""
|
|
160
|
+
Default destructor.
|
|
161
|
+
"""
|
|
162
|
+
|
|
163
|
+
self.delete()
|
|
164
|
+
|
|
165
|
+
def __enter__(self):
|
|
166
|
+
"""
|
|
167
|
+
'with' constructor.
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
return self
|
|
171
|
+
|
|
172
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
173
|
+
"""
|
|
174
|
+
'with' destructor.
|
|
175
|
+
"""
|
|
176
|
+
|
|
177
|
+
self.delete()
|
|
178
|
+
|
|
179
|
+
def delete(self):
|
|
180
|
+
"""
|
|
181
|
+
Actual destructor.
|
|
182
|
+
"""
|
|
183
|
+
|
|
184
|
+
if self.cadical:
|
|
185
|
+
self.cadical.delete()
|
|
186
|
+
self.cadical = None
|
|
187
|
+
|
|
188
|
+
def add_clause(self, clause):
|
|
189
|
+
"""
|
|
190
|
+
Add a single clause to the processor.
|
|
191
|
+
|
|
192
|
+
:param clause: a clause to add
|
|
193
|
+
:type clause: list(int) or any iterable(int)
|
|
194
|
+
|
|
195
|
+
.. code-block:: python
|
|
196
|
+
|
|
197
|
+
>>> processor = Processor()
|
|
198
|
+
>>> processor.add_clause([-1, 2, 3])
|
|
199
|
+
"""
|
|
200
|
+
|
|
201
|
+
if self.cadical:
|
|
202
|
+
self.cadical.add_clause(clause)
|
|
203
|
+
|
|
204
|
+
def append_formula(self, formula):
|
|
205
|
+
"""
|
|
206
|
+
Add a given list of clauses into the solver.
|
|
207
|
+
|
|
208
|
+
:param formula: a list of clauses.
|
|
209
|
+
:type formula: iterable(iterable(int)), or :class:`.CNF`
|
|
210
|
+
|
|
211
|
+
.. code-block:: python
|
|
212
|
+
|
|
213
|
+
>>> cnf = CNF()
|
|
214
|
+
... # assume the formula contains clauses
|
|
215
|
+
>>> processor = Processor()
|
|
216
|
+
>>> processor.append_formula(cnf)
|
|
217
|
+
"""
|
|
218
|
+
|
|
219
|
+
if self.cadical:
|
|
220
|
+
self.cadical.append_formula(formula)
|
|
221
|
+
|
|
222
|
+
def process(self, rounds=1, block=False, cover=False, condition=False,
|
|
223
|
+
decompose=True, elim=True, probe=True, probehbr=True,
|
|
224
|
+
subsume=True, vivify=True, freeze=[]):
|
|
225
|
+
"""
|
|
226
|
+
Runs CaDiCaL's preprocessor for the internal formula for a given
|
|
227
|
+
number of rounds and using the techniques specified in the
|
|
228
|
+
arguments. Note that the default values of all the arguments used
|
|
229
|
+
are set as in the default configuration of CaDiCaL 1.5.3.
|
|
230
|
+
|
|
231
|
+
As the result, the method returns a :class:`.CNF` object
|
|
232
|
+
containing the processed formula. Additionally to the clauses, the
|
|
233
|
+
formula contains a ``status`` variable, which is set to ``False``
|
|
234
|
+
if the preprocessor found the original formula to be unsatisfiable
|
|
235
|
+
(and ``True`` otherwise). The same status value is set to the
|
|
236
|
+
``status`` variable of the processor itself.
|
|
237
|
+
|
|
238
|
+
It is important to note that activation of some of the
|
|
239
|
+
preprocessing techniques conditionally depends on the activation
|
|
240
|
+
of other preprocessing techniques. For instance, subsumed, blocked
|
|
241
|
+
and covered clause elimination is invoked only if bounded variable
|
|
242
|
+
elimination is active. Subsumption elimination in turn may trigger
|
|
243
|
+
vivification and transitive reduction if the corresponding flags
|
|
244
|
+
are set.
|
|
245
|
+
|
|
246
|
+
Finally, note that the ``freeze`` argument can be used to keep
|
|
247
|
+
some of the variables of the original formula unchanged during
|
|
248
|
+
preprocessing. If convenient, the list may contain literals too
|
|
249
|
+
(negative integers).
|
|
250
|
+
|
|
251
|
+
:param rounds: number of preprocessing rounds
|
|
252
|
+
:type rounds: int
|
|
253
|
+
|
|
254
|
+
:param block: apply blocked clause elimination
|
|
255
|
+
:type block: bool
|
|
256
|
+
|
|
257
|
+
:param cover: apply covered clause elimination
|
|
258
|
+
:type cover: bool
|
|
259
|
+
|
|
260
|
+
:param condition: detect conditional autarkies and apply globally-blocked clause elimination
|
|
261
|
+
:type condition: bool
|
|
262
|
+
|
|
263
|
+
:param decompose: detect strongly connected components (SCCs) in the binary implication graph (BIG) and apply equivalent literal substitution (ELS)
|
|
264
|
+
:type decompose: bool
|
|
265
|
+
|
|
266
|
+
:param elim: apply bounded variable elimination
|
|
267
|
+
:type elim: bool
|
|
268
|
+
|
|
269
|
+
:param probe: apply failed literal probing
|
|
270
|
+
:type probe: bool
|
|
271
|
+
|
|
272
|
+
:param probehbr: learn hyper binary resolvents while probing
|
|
273
|
+
:type probehbr: bool
|
|
274
|
+
|
|
275
|
+
:param subsume: apply global forward clause subsumption
|
|
276
|
+
:type subsume: bool
|
|
277
|
+
|
|
278
|
+
:param vivify: apply clause vivification
|
|
279
|
+
:type vivify: bool
|
|
280
|
+
|
|
281
|
+
:param freeze: a list of variables / literals to be kept during preprocessing
|
|
282
|
+
:type freeze: list(int) or any iterable(int)
|
|
283
|
+
|
|
284
|
+
:return: processed formula
|
|
285
|
+
:rtype: :class:`.CNF`
|
|
286
|
+
|
|
287
|
+
.. code-block:: python
|
|
288
|
+
|
|
289
|
+
>>> from pysat.process import Processor
|
|
290
|
+
>>>
|
|
291
|
+
>>> processor = Processor(bootstrap_with=[[-1, 2], [-2, 3], [-1, -3]])
|
|
292
|
+
>>> processor.add_clause([1])
|
|
293
|
+
>>>
|
|
294
|
+
>>> processed = processor.process()
|
|
295
|
+
>>> print(processed.clauses)
|
|
296
|
+
[[]]
|
|
297
|
+
>>> print(processed.status)
|
|
298
|
+
False # this means the processor decided the formula to be unsatisfiable
|
|
299
|
+
>>>
|
|
300
|
+
>>> with Solver(bootstrap_with=processed) as solver:
|
|
301
|
+
... solver.solve()
|
|
302
|
+
False
|
|
303
|
+
>>> processor.delete()
|
|
304
|
+
"""
|
|
305
|
+
|
|
306
|
+
if self.cadical:
|
|
307
|
+
self.status, result = self.cadical.process(rounds, block, cover,
|
|
308
|
+
condition, decompose,
|
|
309
|
+
elim, probe, probehbr,
|
|
310
|
+
subsume, vivify,
|
|
311
|
+
freeze)
|
|
312
|
+
|
|
313
|
+
# making the status Boolean
|
|
314
|
+
self.status = False if self.status == 20 else True
|
|
315
|
+
|
|
316
|
+
# saving it in the output formula
|
|
317
|
+
result = CNF(from_clauses=result)
|
|
318
|
+
result.status = self.status
|
|
319
|
+
|
|
320
|
+
return result
|
|
321
|
+
|
|
322
|
+
def get_status(self):
|
|
323
|
+
"""
|
|
324
|
+
Preprocessor's status as the result of the previous call to
|
|
325
|
+
:meth:`process()`. A ``False`` status indicates that the formula
|
|
326
|
+
is found to be unsatisfiable by the preprocessor. Otherwise, the
|
|
327
|
+
status equals ``True``.
|
|
328
|
+
|
|
329
|
+
:rtype: bool
|
|
330
|
+
"""
|
|
331
|
+
|
|
332
|
+
return self.status
|
|
333
|
+
|
|
334
|
+
def restore(self, model):
|
|
335
|
+
"""
|
|
336
|
+
Reconstruct a model for the original formula given a model for the
|
|
337
|
+
processed formula. Done by using CaDiCaL's extend() and
|
|
338
|
+
reconstruction stack functionality.
|
|
339
|
+
|
|
340
|
+
:param model: a model for the preprocessed formula
|
|
341
|
+
:type model: iterable(int)
|
|
342
|
+
|
|
343
|
+
:return: extended model satisfying the original formula
|
|
344
|
+
:rtype: list(int)
|
|
345
|
+
|
|
346
|
+
.. code-block:: python
|
|
347
|
+
|
|
348
|
+
>>> from pysat.process import Processor
|
|
349
|
+
>>>
|
|
350
|
+
>>> with Processor(bootstrap_with=[[-1, 2], [-2, 3]]) as proc:
|
|
351
|
+
... proc.add_clause([1])
|
|
352
|
+
... processed = proc.process()
|
|
353
|
+
... with Solver(bootstrap_with=processed) as solver:
|
|
354
|
+
... solver.solve()
|
|
355
|
+
... print('model:', proc.restore(solver.get_model()))
|
|
356
|
+
...
|
|
357
|
+
model: [1, 2, 3]
|
|
358
|
+
"""
|
|
359
|
+
|
|
360
|
+
assert self.status, 'Cannot restore a model for an unsatisfiable formula!'
|
|
361
|
+
|
|
362
|
+
if self.cadical:
|
|
363
|
+
return self.cadical.restore(model)
|