python-sat 1.8.dev25__cp314-cp314-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-314-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-314-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,385 @@
1
+ #!python
2
+ #-*- coding:utf-8 -*-
3
+ ##
4
+ ## approxmc.py
5
+ ##
6
+ ## Created on: Apr 14, 2023
7
+ ## Author: Mate Soos
8
+ ## E-mail: soos.mate@gmail.com
9
+ ##
10
+
11
+ """
12
+ ===============
13
+ List of classes
14
+ ===============
15
+
16
+ .. autosummary::
17
+ :nosignatures:
18
+
19
+ Counter
20
+
21
+ ==================
22
+ Module description
23
+ ==================
24
+
25
+ This module provides interface to `ApproxMCv4
26
+ <https://github.com/meelgroup/approxmc/>`_, a state-of-the-art
27
+ *approximate* model counter utilising an improved version of CryptoMiniSat
28
+ to give approximate model counts to problems of size and complexity that
29
+ are out of reach for earlier approximate model counters. The original work
30
+ on ApproxMCv4 has been published in [1]_ and [2]_.
31
+
32
+ .. [1] Mate Soos, Kuldeep S. Meel. *BIRD: Engineering an Efficient CNF-XOR
33
+ SAT Solver and Its Applications to Approximate Model Counting*. AAAI
34
+ 2019. pp. 1592-1599
35
+
36
+ .. [2] Mate Soos, Stephan Gocht, Kuldeep S. Meel. *Tinted, Detached, and
37
+ Lazy CNF-XOR Solving and Its Applications to Counting and Sampling*.
38
+ CAV 2020. pp. 463-484
39
+
40
+ Note that to be functional, the module requires package ``pyapproxmc`` to
41
+ be installed:
42
+
43
+ ::
44
+
45
+ $ pip install pyapproxmc
46
+
47
+ The interface gives access to :class:`Counter`, which expects a formula in
48
+ :class:`.CNF` as input. Given a few additional (optional) arguments,
49
+ including a random seed, *tolerance factor* :math:`\\varepsilon`, and
50
+ *confidence* :math:`\\delta`, the class can be used to get an approximate
51
+ number of models of the formula, subject to the given tolerance factor and
52
+ confidence parameter.
53
+
54
+ Namely, given a CNF formula :math:`\\mathcal{F}` with
55
+ :math:`\\#\\mathcal{F}` as the exact number of models, and parameters
56
+ :math:`\\varepsilon\\in(0,1]` and :math:`\\delta\\in[0,1)`, the counter
57
+ computes and reports a value :math:`C`, which is an approximate number of
58
+ models of :math:`\\mathcal{F}`, such that
59
+ :math:`\\textrm{Pr}\\left[\\frac{1}{1+\\varepsilon}\\#\\mathcal{F}\\leq
60
+ C\\leq (1+\\varepsilon)\\#\\mathcal{F}\\right]\\geq 1-\\delta`.
61
+
62
+ The implementation can be used as an executable (the list of available
63
+ command-line options can be shown using ``approxmc.py -h``) in the
64
+ following way:
65
+
66
+ ::
67
+
68
+ $ xzcat formula.cnf.xz
69
+ p cnf 20 2
70
+ 1 2 3 0
71
+ 3 20 0
72
+
73
+ $ approxmc.py -p 1,2,3-9 formula.cnf.xz
74
+ s mc 448
75
+
76
+ Alternatively, the algorithm can be accessed and invoked through the
77
+ standard ``import`` interface of Python, e.g.
78
+
79
+ .. code-block:: python
80
+
81
+ >>> from pysat.allies.approxmc import Counter
82
+ >>> from pysat.formula import CNF
83
+ >>>
84
+ >>> cnf = CNF(from_file='formula.cnf.xz')
85
+ >>>
86
+ >>> with Counter(cnf) as counter:
87
+ ... print(counter.counter(projection=range(1, 10))
88
+ 448
89
+
90
+ As can be seen in the above example, besides model counting across all the
91
+ variables in a given input formula, the counter supports *projected* model
92
+ counting, i.e. when one needs to approximate the number of models with
93
+ respect to a given list of variables rather than with respect to all
94
+ variables appearing in the formula. This feature comes in handy when the
95
+ formula is obtained, for example, through Tseitin transformation [3]_ with
96
+ a number of auxiliary variables introduced.
97
+
98
+ .. [3] G. S. Tseitin. *On the complexity of derivations in the
99
+ propositional calculus*. Studies in Mathematics and Mathematical
100
+ Logic, Part II. pp. 115–125, 1968
101
+
102
+ ==============
103
+ Module details
104
+ ==============
105
+ """
106
+
107
+ #
108
+ #==============================================================================
109
+ from __future__ import print_function
110
+ import getopt
111
+ import os
112
+ from pysat.formula import CNF
113
+ import re
114
+ import sys
115
+
116
+ # we need pyapproxmc to be installed:
117
+ pyapproxmc_present = True
118
+ try:
119
+ import pyapproxmc
120
+ except ImportError:
121
+ pyapproxmc_present = False
122
+
123
+
124
+ #
125
+ #==============================================================================
126
+ class Counter(object):
127
+ """
128
+ A wrapper for `ApproxMC <https://github.com/meelgroup/approxmc/>`_, a
129
+ state-of-the-art *approximate* model counter. Given a formula in
130
+ :class:`.CNF`, this class can be used to get an approximate number of
131
+ models of the formula, subject to *tolerance factor* ``epsilon`` and
132
+ *confidence parameter* ``delta``.
133
+
134
+ Namely, given a CNF formula :math:`\\mathcal{F}` and parameters
135
+ :math:`\\varepsilon\\in(0,1]` and :math:`\\delta\\in[0,1)`, the
136
+ counter computes and reports a value :math:`C` such that
137
+ :math:`\\textrm{Pr}\\left[\\frac{1}{1+\\varepsilon}\\#\\mathcal{F}\\leq
138
+ C\\leq (1+\\varepsilon)\\#\\mathcal{F}\\right]\\geq 1-\\delta`. Here,
139
+ :math:`\\#\\mathcal{F}` denotes the exact model count for formula
140
+ :math:`\\mathcal{F}`.
141
+
142
+ The ``formula`` argument can be left unspecified at this stage. In
143
+ this case, a user is expected to add all the relevant clauses using
144
+ :meth:`add_clause`.
145
+
146
+ An additional parameter a user may want to specify is integer ``seed``
147
+ used by ApproxMC. The value of ``seed`` is set to ``1`` by default.
148
+
149
+ :param formula: CNF formula
150
+ :param seed: integer seed value
151
+ :param epsilon: tolerance factor
152
+ :param delta: confidence parameter
153
+ :param verbose: verbosity level
154
+
155
+ :type formula: :class:`.CNF`
156
+ :type seed: int
157
+ :type epsilon: float
158
+ :type delta: float
159
+ :type verbose: int
160
+
161
+ .. code-block:: python
162
+
163
+ >>> from pysat.allies.approxmc import Counter
164
+ >>> from pysat.formula import CNF
165
+ >>>
166
+ >>> cnf = CNF(from_file='some-formula.cnf')
167
+ >>> with Counter(formula=cnf, epsilon=0.1, delta=0.9) as counter:
168
+ ... num = counter.count() # an approximate number of models
169
+ """
170
+
171
+ def __init__(self, formula=None, seed=1, epsilon=0.8, delta=0.2, verbose=0):
172
+ """
173
+ Constructor.
174
+ """
175
+
176
+ assert pyapproxmc_present, 'Package \'pyapproxmc\' is unavailable. Check your installation.'
177
+
178
+ # there are no initial counts
179
+ self.cellc, self.hashc = None, None
180
+
181
+ # creating the Counter object
182
+ self.counter = pyapproxmc.Counter(verbosity=verbose, seed=seed,
183
+ epsilon=epsilon, delta=delta)
184
+
185
+ # adding clauses to the counter
186
+ if formula:
187
+ for clause in formula:
188
+ self.add_clause(clause)
189
+
190
+ def __del__(self):
191
+ """
192
+ Destructor.
193
+ """
194
+
195
+ self.delete()
196
+
197
+ def __enter__(self):
198
+ """
199
+ 'with' constructor.
200
+ """
201
+
202
+ return self
203
+
204
+ def __exit__(self, exc_type, exc_value, traceback):
205
+ """
206
+ 'with' destructor.
207
+ """
208
+
209
+ self.delete()
210
+
211
+ def add_clause(self, clause):
212
+ """
213
+ The method for adding a clause to the problem formula. Although
214
+ the input formula can be specified as an argument of the
215
+ constructor of :class:`Counter`, adding clauses may also be
216
+ helpful afterwards, *on the fly*.
217
+
218
+ The clause to add can be any iterable over integer literals.
219
+
220
+ :param clause: a clause to add
221
+ :type clause: iterable(int)
222
+
223
+ .. code-block:: python
224
+
225
+ >>> from pysat.allies.approxmc import Counter
226
+ >>>
227
+ >>> with Counter() as counter:
228
+ ... counter.add_clause(range(1, 4))
229
+ ... counter.add_clause([3, 20])
230
+ ...
231
+ ... print(counter.count())
232
+ 720896
233
+ """
234
+
235
+ self.counter.add_clause(clause)
236
+
237
+ def count(self, projection=None):
238
+ """
239
+
240
+ Given the formula provided by the user either in the constructor
241
+ of :class:`Counter` or through a series of calls to
242
+ :meth:`add_clause`, this method runs the ApproxMC counter with the
243
+ specified values of tolerance :math:`\\varepsilon` and confidence
244
+ :math:`\\delta` parameters, as well as the random ``seed`` value,
245
+ and returns the number of models estimated.
246
+
247
+ A user may specify an argument ``projection``, which is a list of
248
+ integers specifying the variables with respect to which projected
249
+ model counting should be performed. If ``projection`` is left as
250
+ ``None``, approximate model counting is performed wrt. all the
251
+ variables of the input formula.
252
+
253
+ :param projection: variables to project on
254
+ :type projection: list(int)
255
+
256
+ .. code-block:: python
257
+
258
+ >>> from pysat.allies.approxmc import Counter
259
+ >>> from pysat.card import CardEnc, EncType
260
+ >>>
261
+ >>> # cardinality constraint with auxiliary variables
262
+ >>> # there are exactly 70 models for the constraint
263
+ >>> # over the 8 original variables
264
+ >>> cnf = CardEnc.equals(lits=range(1, 9), bound=4, encoding=EncType.cardnetwrk)
265
+ >>>
266
+ >>> with Counter(formula=cnf, epsilon=0.05, delta=0.95) as counter:
267
+ ... print(counter.count())
268
+ 123840
269
+ >>>
270
+ >>> with Counter(formula=cnf, epsilon=0.05, delta=0.95) as counter:
271
+ ... print(counter.count(projection=range(1, 8)))
272
+ 70
273
+ """
274
+
275
+ if projection is not None:
276
+ self.cellc, self.hashc = self.counter.count(projection=projection)
277
+ else:
278
+ self.cellc, self.hashc = self.counter.count()
279
+
280
+ return self.cellc * (2 ** self.hashc)
281
+
282
+ def delete(self):
283
+ """
284
+ Explicit destructor of the internal Counter oracle.
285
+ Delete the actual counter object and sets it to ``None``.
286
+ """
287
+
288
+ if self.counter:
289
+ del self.counter
290
+ self.counter = None
291
+
292
+
293
+ #
294
+ #==============================================================================
295
+ def parse_options():
296
+ """
297
+ Parses command-line option
298
+ """
299
+
300
+ try:
301
+ opts, args = getopt.getopt(sys.argv[1:], 'd:e:hp:s:v:',
302
+ ['delta=', 'epsilon=', 'help', 'projection=', 'seed=', 'verbose='])
303
+ except getopt.GetoptError as err:
304
+ sys.stderr.write(str(err).capitalize())
305
+ usage()
306
+ sys.exit(1)
307
+
308
+ delta = 0.2
309
+ epsilon = 0.8
310
+ projection = None
311
+ seed = 1
312
+ verbose = 0
313
+
314
+ for opt, arg in opts:
315
+ if opt in ('-d', '--delta'):
316
+ delta = float(arg)
317
+ elif opt in ('-e', '--epsilon'):
318
+ epsilon = float(arg)
319
+ elif opt in ('-h', '--help'):
320
+ usage()
321
+ sys.exit(0)
322
+ elif opt in ('-p', '--projection'):
323
+ # parsing the list of variables
324
+ projection, values = [], str(arg).split(',')
325
+
326
+ # checking if there are intervals
327
+ for value in values:
328
+ if value.isnumeric():
329
+ projection.append(int(value))
330
+ elif '-' in value:
331
+ lb, ub = value.split('-')
332
+ assert int(lb) < int(ub)
333
+ projection.extend(list(range(int(lb), int(ub) + 1)))
334
+
335
+ # removing duplicates, if any
336
+ projection = sorted(set(projection))
337
+ elif opt in ('-s', '--seed'):
338
+ seed = int(arg)
339
+ elif opt in ('-v', '--verbose'):
340
+ verbose = int(arg)
341
+ else:
342
+ assert False, 'Unhandled option: {0} {1}'.format(opt, arg)
343
+
344
+ return delta, epsilon, projection, seed, verbose, args
345
+
346
+
347
+ #
348
+ #==============================================================================
349
+ def usage():
350
+ """
351
+ Prints usage message.
352
+ """
353
+
354
+ print('Usage:', os.path.basename(sys.argv[0]), '[options] dimacs-file')
355
+ print('Options:')
356
+ print(' -d, --delta=<float> Confidence parameter as per PAC guarantees')
357
+ print(' Available values: [0, 1) (default = 0.2)')
358
+ print(' -e, --epsilon=<float> Tolerance factor as per PAC guarantees')
359
+ print(' Available values: (0 .. 1], all (default = 0.8)')
360
+ print(' -p, --projection=<list> Do model counting projected on this set of variables')
361
+ print(' Available values: comma-separated-list, none (default = none)')
362
+ print(' -s, --seed=<int> Random seed')
363
+ print(' Available values: [0 .. INT_MAX] (default = 1)')
364
+ print(' -v, --verbose=<int> Verbosity level')
365
+ print(' Available values: [0 .. 15] (default = 0)')
366
+
367
+
368
+ #
369
+ #==============================================================================
370
+ if __name__ == '__main__':
371
+ delta, epsilon, projection, seed, verbose, files = parse_options()
372
+
373
+ # parsing the input formula
374
+ if files and re.search(r'\.cnf(\.(gz|bz2|lzma|xz))?$', files[0]):
375
+ formula = CNF(from_file=files[0])
376
+
377
+ # creating the counter object
378
+ with Counter(formula, seed=seed, epsilon=epsilon, delta=delta,
379
+ verbose=verbose) as counter:
380
+
381
+ # approximate model counting
382
+ count = counter.count(projection=projection)
383
+
384
+ # printing the result
385
+ print('s mc', count)