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.

Files changed (48) hide show
  1. pycard.cpython-312-x86_64-linux-gnu.so +0 -0
  2. pysat/__init__.py +24 -0
  3. pysat/_fileio.py +209 -0
  4. pysat/_utils.py +58 -0
  5. pysat/allies/__init__.py +0 -0
  6. pysat/allies/approxmc.py +385 -0
  7. pysat/allies/unigen.py +435 -0
  8. pysat/card.py +802 -0
  9. pysat/engines.py +1302 -0
  10. pysat/examples/__init__.py +0 -0
  11. pysat/examples/bbscan.py +663 -0
  12. pysat/examples/bica.py +691 -0
  13. pysat/examples/fm.py +527 -0
  14. pysat/examples/genhard.py +516 -0
  15. pysat/examples/hitman.py +653 -0
  16. pysat/examples/lbx.py +638 -0
  17. pysat/examples/lsu.py +496 -0
  18. pysat/examples/mcsls.py +610 -0
  19. pysat/examples/models.py +189 -0
  20. pysat/examples/musx.py +344 -0
  21. pysat/examples/optux.py +710 -0
  22. pysat/examples/primer.py +620 -0
  23. pysat/examples/rc2.py +1858 -0
  24. pysat/examples/usage.py +63 -0
  25. pysat/formula.py +5619 -0
  26. pysat/pb.py +463 -0
  27. pysat/process.py +363 -0
  28. pysat/solvers.py +7591 -0
  29. pysolvers.cpython-312-x86_64-linux-gnu.so +0 -0
  30. python_sat-1.8.dev25.data/scripts/approxmc.py +385 -0
  31. python_sat-1.8.dev25.data/scripts/bbscan.py +663 -0
  32. python_sat-1.8.dev25.data/scripts/bica.py +691 -0
  33. python_sat-1.8.dev25.data/scripts/fm.py +527 -0
  34. python_sat-1.8.dev25.data/scripts/genhard.py +516 -0
  35. python_sat-1.8.dev25.data/scripts/lbx.py +638 -0
  36. python_sat-1.8.dev25.data/scripts/lsu.py +496 -0
  37. python_sat-1.8.dev25.data/scripts/mcsls.py +610 -0
  38. python_sat-1.8.dev25.data/scripts/models.py +189 -0
  39. python_sat-1.8.dev25.data/scripts/musx.py +344 -0
  40. python_sat-1.8.dev25.data/scripts/optux.py +710 -0
  41. python_sat-1.8.dev25.data/scripts/primer.py +620 -0
  42. python_sat-1.8.dev25.data/scripts/rc2.py +1858 -0
  43. python_sat-1.8.dev25.data/scripts/unigen.py +435 -0
  44. python_sat-1.8.dev25.dist-info/METADATA +45 -0
  45. python_sat-1.8.dev25.dist-info/RECORD +48 -0
  46. python_sat-1.8.dev25.dist-info/WHEEL +6 -0
  47. python_sat-1.8.dev25.dist-info/licenses/LICENSE.txt +21 -0
  48. python_sat-1.8.dev25.dist-info/top_level.txt +3 -0
@@ -0,0 +1,189 @@
1
+ #!/usr/bin/env 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)
pysat/examples/musx.py ADDED
@@ -0,0 +1,344 @@
1
+ #!/usr/bin/env 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()))