python-sat 1.8.dev25__cp310-cp310-macosx_11_0_arm64.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.
Files changed (48) hide show
  1. pycard.cpython-310-darwin.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-310-darwin.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
pysat/examples/bica.py ADDED
@@ -0,0 +1,691 @@
1
+ #!/usr/bin/env python
2
+ #-*- coding:utf-8 -*-
3
+ ##
4
+ ## bica.py
5
+ ##
6
+ ## Created on: Jul 28, 2025
7
+ ## Author: Alexey Ignatiev
8
+ ## E-mail: alexey.ignatiev@monash.edu
9
+ ##
10
+
11
+ """
12
+ ===============
13
+ List of classes
14
+ ===============
15
+
16
+ .. autosummary::
17
+ :nosignatures:
18
+
19
+ Bica
20
+
21
+ ==================
22
+ Module description
23
+ ==================
24
+
25
+ A reimplementation of the Bica algorithm for SAT-based minimisation /
26
+ simplification of Boolean formulas [1]_. Given an arbitrary Boolean
27
+ formula, it computes its smallest size prime cover, i.e. it constructs a
28
+ smallest CNF (DNF, resp.) representation comprising the formula's prime
29
+ implicates (implicants, reps.), which is *equivalent* to the original
30
+ formula.
31
+
32
+ The original Bica algorithm is inspired by the well-known Quine-McCluskey
33
+ algorithm [2]_ [3]_ [4]_. It is *entirely* SAT-based and can deal with
34
+ arbitrary Boolean formulas. The algorithm involves two steps: first, it
35
+ enumerates all the prime implicants (or implicates, depending on the
36
+ user's choice) of the formula by utilising the :class:`.Primer` algorithm
37
+ [5]_; second, it computes the formula's smallest prime cover by means of
38
+ reducing the problem to the computation of a smallest minimal
39
+ unsatisfiable subformula (SMUS), invoking the :class:`.OptUx` SMUS solver
40
+ [6]_.
41
+
42
+ The word "bica" is Portuguese and means a cup of extremely strong and
43
+ high-quality coffee (often seen as a synonym of espresso). This way, the
44
+ Bica algorithm continues the *coffee inspiration* of the `Espresso logic
45
+ minimizer
46
+ <https://ptolemy.berkeley.edu/projects/embedded/pubs/downloads/espresso/>`_
47
+ [7]_, hence signifying the construction of the formula's *essence* or
48
+ *crux*. (In fact, this reimplementation was initially planned to have the
49
+ name *Crux*, to relate with `one of the most prominent constellations of
50
+ the southern sky <https://en.wikipedia.org/wiki/Crux>`_, often used in
51
+ navigation to determine the Southern Celestial Pole.)
52
+
53
+ .. [1] Alexey Ignatiev, Alessandro Previti, Joao Marques-Silva.
54
+ *SAT-Based Formula Simplification*. SAT 2015. pp. 287-298
55
+
56
+ .. [2] Willard V. Quine. *The Problem of Simplifying Truth Functions*.
57
+ American Mathematical Monthly 59(8). 1952. pp. 521-531
58
+
59
+ .. [3] Willard V. Quine. *A Way to Simplify Truth Functions*.
60
+ American Mathematical Monthly 62(9). 1955. pp. 627-631
61
+
62
+ .. [4] Edward J. McCluskey. *Minimization of Boolean Functions*. Bell
63
+ System Technical Journal 35(6). 1956. pp 1417-1444
64
+
65
+ .. [5] Alessandro Previti, Alexey Ignatiev, António Morgado,
66
+ Joao Marques-Silva. *Prime Compilation of Non-Clausal Formulae.*
67
+ IJCAI 2015. pp. 1980-1988
68
+
69
+ .. [6] Alexey Ignatiev, Alessandro Previti, Mark H. Liffiton, Joao
70
+ Marques-Silva. *Smallest MUS Extraction with Minimal Hitting Set
71
+ Dualization*. CP 2015. pp. 173-182
72
+
73
+ .. [7] Robert K. Brayton, Alberto L. Sangiovanni-Vincentelli,, Curtis T.
74
+ McMullen, Gary D. Hachtel. *Logic Minimization Algorithms for VLSI
75
+ Synthesis*. Kluwer Academic Publishers. 1984
76
+
77
+ The file provides a class :class:`Bica`, which contains the above
78
+ algorithm reimplementation. It can be applied to any formula in the
79
+ :class:`.CNF` or :class:`.Formula` format.
80
+
81
+ The implementation can be used as an executable (the list of available
82
+ command-line options can be shown using ``bica.py -h``) in the following
83
+ way:
84
+
85
+ ::
86
+
87
+ $ xzcat formula.cnf.xz
88
+ p cnf 7 7
89
+ -1 2 0
90
+ 1 -2 0
91
+ 1 2 -3 4 0
92
+ 1 2 3 -4 0
93
+ 1 2 3 4 -5 6 0
94
+ 1 2 3 4 5 -6 0
95
+ 1 2 3 4 5 6 7 0
96
+
97
+ $ bica.py -v formula.cnf.xz
98
+ c prime -1 +2 0
99
+ c prime +1 -2 0
100
+ c prime +1 -3 +4 0
101
+ c prime +2 -3 +4 0
102
+ c prime +1 +3 -4 0
103
+ c prime +2 +3 -4 0
104
+ c prime +1 +3 -5 +6 0
105
+ c prime +1 +3 +5 -6 0
106
+ c prime +1 +3 +5 +7 0
107
+ c prime +1 +3 +6 +7 0
108
+ c prime +1 +4 +5 +7 0
109
+ c prime +1 +4 +6 +7 0
110
+ c prime +1 +4 +5 -6 0
111
+ c prime +1 +4 -5 +6 0
112
+ c prime +2 +4 -5 +6 0
113
+ c prime +2 +3 -5 +6 0
114
+ c prime +2 +3 +5 -6 0
115
+ c prime +2 +4 +5 -6 0
116
+ c prime +2 +3 +5 +7 0
117
+ c prime +2 +4 +5 +7 0
118
+ c prime +2 +3 +6 +7 0
119
+ c prime +2 +4 +6 +7 0
120
+ p cnf 7 7
121
+ -1 2 0
122
+ 1 -2 0
123
+ 2 -3 4 0
124
+ 2 3 -4 0
125
+ 2 3 -5 6 0
126
+ 2 4 5 -6 0
127
+ 2 4 6 7 0
128
+ o 7
129
+ c primer time: 0.0002
130
+ c optux time: 0.0001
131
+ c total time: 0.0004
132
+
133
+ Alternatively, the algorithm can be accessed and invoked through the
134
+ standard ``import`` interface of Python, e.g.
135
+
136
+ .. code-block:: python
137
+
138
+ >>> from pysat.examples.bica import Bica
139
+ >>> from pysat.formula import Atom, CNF, Formula
140
+ >>>
141
+ >>> x, y, z = [Atom(v + 1) for v in range(3)]
142
+ >>> formula = ~(~x >> y) | (x & z)
143
+ >>>
144
+ >>> with Bica(formula) as bica:
145
+ ... for minf in bica.enumerate():
146
+ ... minf = CNF(from_clauses=[bica.primes[i - 1] for i in minf])
147
+ ... print(minf)
148
+ CNF(from_string='p cnf 3 2\\n-1 3 0\\n-2 1 0')
149
+
150
+ As the example above demonstrates, Bica can enumerate all irreducible
151
+ prime covers of an input formula (or as many as the user wants). In this
152
+ particular example, the formula :math:`f\\triangleq\\neg{(\\neg{x}
153
+ \\rightarrow y)} \\vee (x \\wedge z)` has the only irreducible prime cover
154
+ :math:`(\\neg{x} \\vee z) \\vee (\\neg{y} \\vee x)`.
155
+
156
+ ==============
157
+ Module details
158
+ ==============
159
+ """
160
+
161
+ #
162
+ #==============================================================================
163
+ import collections
164
+ import getopt
165
+ import os
166
+ from pysat.examples.optux import OptUx
167
+ from pysat.examples.primer import Primer
168
+ from pysat.formula import IDPool, CNF, Neg, WCNF
169
+ from pysat.solvers import Solver
170
+ import re
171
+ import sys
172
+
173
+
174
+ #
175
+ #==============================================================================
176
+ class Bica:
177
+ """
178
+ A simple reimplementation of the Bica algorithm. Although the original
179
+ implementation of Bica was also written in Python, both phases of the
180
+ algorithm (prime enumeration and prime cover computation) were written
181
+ in C++ and interfaced through the file IO. The current implementation
182
+ relies on pure Python alternatives for both of the phases. Namely, it
183
+ first calls :class:`.Primer` to enumerate all the primes of a given
184
+ input formula followed by the computation of a smallest size cover
185
+ with :class:`.OptUx`.
186
+
187
+ Importantly, thanks to the capabilities of :class:`.OptUx`, the
188
+ current implementation allows one to enumerate multiple (or all)
189
+ smallest size prime covers. Alternatively, one can even opt for
190
+ computing **a minimal** prime cover (not a minimum one).
191
+
192
+ The second phase of the approach also allows a user to compute the
193
+ target representation either *unweighted* or *weighted*. In the former
194
+ case, the size is measured as the number of primes included in the
195
+ minimal representation. In the latter case, the lenght of each prime
196
+ is taken into account such that the overall size is counted as the sum
197
+ of lengths of the primes included. This is controlled with the use of
198
+ input parameter ``weighted``.
199
+
200
+ Additionally, one may additionally want to specify the negation of the
201
+ input formula, which is required either in first phase of the
202
+ algorithm or in both phases, depending on whether the user wants to
203
+ compute a DNF or CNF representation. If no negated formula is
204
+ provided, Bica will create one internally.
205
+
206
+ As both phases of the algorithm rely on implicit hitting set
207
+ enumeration, they share the same input parameters. To allow a user to
208
+ apply various parameters for the two phases, :class:`.Hitman`'s
209
+ parameters of the :class:`.Primer` phase are prefixed with a ``p``
210
+ while the same parameters used by :class:`.OptUx` are prefixed with an
211
+ ``o``.
212
+
213
+ The complete list of initialiser's arguments is as follows:
214
+
215
+ :param formula: input formula whose prime representation is sought
216
+ :param negated: input's formula negation (if any)
217
+ :param target: either ``'cnf'`` or ``'dnf'``
218
+ :param psolver: SAT oracle name
219
+ :param padapt: detect and adapt intrinsic AtMost1 constraints
220
+ :param pdcalls: apply clause D oracle calls (for unsorted enumeration only)
221
+ :param pexhaust: do core exhaustion
222
+ :param pminz: do heuristic core reduction
223
+ :param ppuresat: use pure SAT-based hitting set enumeration
224
+ :param psearch: dual prime reduction strategy
225
+ :param punsorted: apply unsorted MUS enumeration
226
+ :param ptrim: do core trimming at most this number of times
227
+ :param osolver: SAT oracle name
228
+ :param oadapt: detect and adapt intrinsic AtMost1 constraints
229
+ :param odcalls: apply clause D oracle calls (for unsorted enumeration only)
230
+ :param oexhaust: do core exhaustion
231
+ :param ominz: do heuristic core reduction
232
+ :param onodisj: do not enumerate disjoint MCSes with OptUx
233
+ :param opuresat: use pure SAT-based hitting set enumeration
234
+ :param ounsorted: apply unsorted MUS enumeration
235
+ :param otrim: do core trimming at most this number of times
236
+ :param weighted: get a minimal cover wrt. the total number of literals
237
+ :param verbose: verbosity level
238
+
239
+ :type formula: :class:`.Formula` or :class:`.CNF`
240
+ :type negated: :class:`.Formula` or :class:`.CNF`
241
+ :type target: str
242
+ :type psolver: str
243
+ :type padapt: bool
244
+ :type pdcalls: bool
245
+ :type pexhaust: bool
246
+ :type pminz: bool
247
+ :type ppuresat: str
248
+ :type psearch: str
249
+ :type punsorted: bool
250
+ :type ptrim: int
251
+ :type osolver: str
252
+ :type oadapt: bool
253
+ :type odcalls: bool
254
+ :type oexhaust: bool
255
+ :type ominz: bool
256
+ :type onodisj: bool
257
+ :type opuresat: str
258
+ :type ounsorted: bool
259
+ :type otrim: int
260
+ :type weighted: bool
261
+ :type verbose: int
262
+ """
263
+
264
+ def __init__(self, formula, negated=None, target='cnf', psolver='cd19',
265
+ padapt=False, pdcalls=False, pexhaust=False, pminz=False,
266
+ ppuresat=False, psearch='lin', punsorted=False, ptrim=False,
267
+ osolver='mgh', oadapt=False, odcalls=False, oexhaust=False,
268
+ ominz=False, onodisj=False, opuresat=False, ounsorted=False,
269
+ otrim=False, weighted=False, verbose=0):
270
+ """
271
+ Initialiser.
272
+ """
273
+
274
+ # copying some of the arguments
275
+ self.form = formula
276
+ self.fneg = negated
277
+ self.target = target
278
+ self.verbose = verbose
279
+ self.weighted = weighted
280
+
281
+ # Primer's parameters
282
+ self.psolver = psolver
283
+ self.padapt = padapt
284
+ self.pdcalls = pdcalls
285
+ self.pexhaust = pexhaust
286
+ self.pminz = pminz
287
+ self.ppuresat = ppuresat
288
+ self.psearch = psearch
289
+ self.punsorted = punsorted
290
+ self.ptrim = ptrim
291
+
292
+ # OptUx's parameters
293
+ self.osolver = osolver
294
+ self.oadapt = oadapt
295
+ self.odcalls = odcalls
296
+ self.oexhaust = oexhaust
297
+ self.ominz = ominz
298
+ self.onodisj = onodisj
299
+ self.opuresat = opuresat
300
+ self.ounsorted = ounsorted
301
+ self.otrim = otrim
302
+
303
+ # oracles solving the two subproblems
304
+ self.primer, self.optux, self.primes = None, None, []
305
+
306
+ # if no negated formula was given, we create one
307
+ if self.fneg is None:
308
+ self.fneg = Neg(self.form)
309
+
310
+ # input formula for OptUx to be gradually constructed
311
+ # during prime enumeration phase;
312
+ self.pform = WCNF()
313
+ if self.target == 'dnf':
314
+ for cl in self.form:
315
+ self.pform.append(cl)
316
+ else:
317
+ # if the target is CNF, we need to add the negated formula
318
+ for cl in self.fneg:
319
+ self.pform.append(cl)
320
+
321
+ self._init_primer()
322
+
323
+ def _init_primer(self):
324
+ """
325
+ Constructs and initialises the Primer object.
326
+ """
327
+
328
+ implicates = False if self.target == 'dnf' else True
329
+
330
+ self.primer = Primer(self.form, negated=self.fneg,
331
+ solver=self.psolver, implicates=implicates,
332
+ adapt=self.padapt, dcalls=self.pdcalls,
333
+ exhaust=self.pexhaust, minz=self.pminz,
334
+ puresat=self.ppuresat, search=self.psearch,
335
+ unsorted=self.punsorted, trim=self.ptrim,
336
+ verbose=self.verbose - 1)
337
+
338
+ def __del__(self):
339
+ """
340
+ Destructor.
341
+ """
342
+
343
+ self.delete()
344
+
345
+ def __enter__(self):
346
+ """
347
+ 'with' constructor.
348
+ """
349
+
350
+ return self
351
+
352
+ def __exit__(self, exc_type, exc_value, traceback):
353
+ """
354
+ 'with' destructor.
355
+ """
356
+
357
+ self.delete()
358
+
359
+ def delete(self):
360
+ """
361
+ Explicit destructor of both primer and optux. Also, clears the
362
+ list of primes computed.
363
+
364
+ (The former is constructed in Bica's initialiser while the latter
365
+ is created on demand, once the first phase of the algorithm has
366
+ been finished, i.e. when all the primes have been enumerated.)
367
+ """
368
+
369
+ self.primes = []
370
+
371
+ if self.primer:
372
+ self.primer.delete()
373
+ self.primer = None
374
+
375
+ if self.optux:
376
+ self.optux.delete()
377
+ self.optux = None
378
+
379
+ def compute(self):
380
+ """
381
+ Computes a single minimum representation of the input formula as a
382
+ list of indices of prime implicants (or implicates) determined to
383
+ comprise the representation.
384
+
385
+ Note that the indices in the returned list start from ``1``, i.e.
386
+ the user is supposed to subtract ``1`` for each of them to get the
387
+ correct list of primes. Consider the following example:
388
+
389
+ .. code-block:: python
390
+
391
+ >>> from pysat.examples.bica import Bica
392
+ >>> from pysat.formula import CNF
393
+ >>>
394
+ >>> cnf = CNF(from_clauses=[[-1, 2], [-2, 3], [-3, 4], [4, 5]])
395
+ >>>
396
+ >>> with Bica(formula) as bica:
397
+ ... for minf in bica.enumerate():
398
+ ... minf = CNF(from_clauses=[bica.primes[i - 1] for i in minf])
399
+ ... print(minf)
400
+ ... print(f'all primes implicates: {bica.primes}')
401
+ CNF(from_string='p cnf 4 3\\n4 0\\n-2 3 0\\n-1 2 0')
402
+ all prime implicates: [[4], [-2, 3], [-1, 3], [-1, 2]]
403
+
404
+ :rtype: list(int)
405
+ """
406
+
407
+ # first, collecing all the primes
408
+ if not self.primes:
409
+ for prime in self.primer.enumerate():
410
+ self.primes.append(prime)
411
+
412
+ # recording the prime
413
+ if self.target == 'cnf':
414
+ self.pform.append(prime, weight=len(prime) if self.weighted else 1)
415
+ else:
416
+ self.pform.append([-l for l in prime], weight=len(prime) if self.weighted else 1)
417
+
418
+ # reporting it
419
+ if self.verbose > 1:
420
+ print('c prime {0} 0'.format(' '.join(['{0}{1}'.format('+' if v > 0 else '', v) for v in prime])))
421
+
422
+ if not self.optux:
423
+ # creating an OptUx object
424
+ self.optux = OptUx(self.pform, solver=self.osolver,
425
+ adapt=self.oadapt, cover=None,
426
+ dcalls=self.odcalls, exhaust=self.oexhaust,
427
+ minz=self.ominz, nodisj=self.onodisj,
428
+ puresat=self.opuresat, unsorted=self.ounsorted,
429
+ trim=self.otrim, verbose=self.verbose)
430
+
431
+ return self.optux.compute()
432
+
433
+ def enumerate(self):
434
+ """
435
+ This is generator method iterating through minimum representations
436
+ and enumerating them until no more of them exists, or a user
437
+ decides to stop the process.
438
+
439
+ .. code-block:: python
440
+
441
+ >>> from pysat.examples.bica import Bica
442
+ >>> from pysat.formula import *
443
+ >>>
444
+ >>> cnf = CNF(from_file='test.cnf')
445
+ >>> print(cnf)
446
+ CNF(from_string='c n orig vars 5\\np cnf 11 5\\n-1 2 0\\n1 -2 0\\n1 2 -3 4 0\\n1 2 3 -4 0\\n1 2 3 4 5 0')
447
+ >>>
448
+ >>> with Bica(cnf) as bica:
449
+ ... for minf in bica.enumerate():
450
+ ... print(minf) # prime indices start from 1!
451
+ [1, 2, 8, 9, 10]
452
+ [1, 2, 3, 8, 10]
453
+ [1, 2, 3, 6, 10]
454
+ [1, 2, 3, 4, 8]
455
+ [1, 2, 3, 4, 6]
456
+ [1, 2, 4, 7, 8]
457
+ [1, 2, 4, 8, 9]
458
+ [1, 2, 4, 5, 8]
459
+ [1, 2, 4, 6, 7]
460
+ [1, 2, 4, 5, 6]
461
+ [1, 2, 4, 6, 9]
462
+ [1, 2, 6, 7, 10]
463
+ [1, 2, 7, 8, 10]
464
+ [1, 2, 5, 8, 10]
465
+ [1, 2, 5, 6, 10]
466
+ [1, 2, 6, 9, 10]
467
+
468
+ :rtype: list(int)
469
+ """
470
+
471
+ done = False
472
+
473
+ while not done:
474
+ minf = self.compute()
475
+
476
+ if minf is not None:
477
+ yield minf
478
+ else:
479
+ done = True
480
+
481
+ def oracle_time(self):
482
+ """
483
+ This method computes and returns the total SAT solving time
484
+ involved, including the time spent by :class:`.Primer` and
485
+ :class:`.OptUx`, which implement the first and second phases
486
+ of the algorithm, respectively.
487
+
488
+ :rtype: float
489
+ """
490
+
491
+ return self.primer.oracle_time() + self.optux.oracle_time()
492
+
493
+
494
+ class Crux(Bica):
495
+ """
496
+ A clone of Bica, to be used interchangeably.
497
+ """
498
+
499
+ pass
500
+
501
+
502
+ #
503
+ #==============================================================================
504
+ def parse_options():
505
+ """
506
+ Parses command-line options:
507
+ """
508
+
509
+ try:
510
+ opts, args = getopt.getopt(sys.argv[1:],
511
+ 'aAdDe:hmMnp:P:r:R:s:S:t:T:uUvwxX',
512
+ ['padapt', 'oadapt', 'pdcalls', 'odcalls',
513
+ 'enum=', 'help', 'pminimize', 'ominimize',
514
+ 'no-disj', 'ppuresat=', 'opuresat=',
515
+ 'reduce=', 'repr=', 'psolver=',
516
+ 'osolver=', 'ptrim=', 'otrim=',
517
+ 'punsorted', 'ounsorted', 'verbose',
518
+ 'weighted', 'pexhaust', 'oexhaust'])
519
+ except getopt.GetoptError as err:
520
+ sys.stderr.write(str(err).capitalize())
521
+ usage()
522
+ sys.exit(1)
523
+
524
+ to_enum = 1
525
+ mode = 'cnf'
526
+ search = 'lin'
527
+ verbose = 1
528
+ weighted = False
529
+
530
+ padapt = False
531
+ oadapt = False
532
+ pdcalls = False
533
+ odcalls = False
534
+ pexhaust = False
535
+ oexhaust = False
536
+ pminz = False
537
+ ominz = False
538
+ nodisj = False
539
+ psolver = 'cd19'
540
+ osolver = 'mgh'
541
+ ppuresat = False
542
+ opuresat = False
543
+ punsorted = False
544
+ ounsorted = False
545
+ ptrim = 0
546
+ otrim = 0
547
+
548
+ for opt, arg in opts:
549
+ if opt in ('-a', '--padapt'):
550
+ padapt = True
551
+ elif opt in ('-A', '--oadapt'):
552
+ oadapt = True
553
+ elif opt in ('-d', '--pdcalls'):
554
+ pdcalls = True
555
+ elif opt in ('-D', '--odcalls'):
556
+ odcalls = True
557
+ elif opt in ('-e', '--enum'):
558
+ to_enum = str(arg)
559
+ if to_enum != 'all':
560
+ to_enum = int(to_enum)
561
+ elif opt in ('-h', '--help'):
562
+ usage()
563
+ sys.exit(0)
564
+ elif opt in ('-m', '--pminimize'):
565
+ pminz = True
566
+ elif opt in ('-M', '--ominimize'):
567
+ ominz = True
568
+ elif opt in ('-n', '--no-disj'):
569
+ nodisj = True
570
+ elif opt in ('-p', '--ppuresat'):
571
+ ppuresat = str(arg)
572
+ elif opt in ('-P', '--opuresat'):
573
+ opuresat = str(arg)
574
+ elif opt in ('-r', '--reduce'):
575
+ search = str(arg)
576
+ assert search in ('lin', 'bin'), 'Wrong minimisation method: {0}'.format(search)
577
+ elif opt in ('-R', '--repr'):
578
+ mode = str(arg)
579
+ elif opt in ('-s', '--psolver'):
580
+ psolver = str(arg)
581
+ elif opt in ('-S', '--osolver'):
582
+ osolver = str(arg)
583
+ elif opt in ('-u', '--punsorted'):
584
+ punsorted = True
585
+ elif opt in ('-U', '--ounsorted'):
586
+ ounsorted = True
587
+ elif opt in ('-t', '--ptrim'):
588
+ ptrim = int(arg)
589
+ elif opt in ('-T', '--otrim'):
590
+ otrim = int(arg)
591
+ elif opt in ('-v', '--verbose'):
592
+ verbose += 1
593
+ elif opt in ('-w', '--weighted'):
594
+ weighted = True
595
+ elif opt in ('-x', '--pexhaust'):
596
+ pexhaust = True
597
+ elif opt in ('-X', '--oexhaust'):
598
+ oexhaust = True
599
+ else:
600
+ assert False, 'Unhandled option: {0} {1}'.format(opt, arg)
601
+
602
+ return to_enum, mode, padapt, oadapt, pdcalls, odcalls, pexhaust, \
603
+ oexhaust, pminz, ominz, nodisj, ptrim, otrim, search, psolver, \
604
+ osolver, ppuresat, opuresat, punsorted, ounsorted, verbose, \
605
+ weighted, args
606
+
607
+
608
+ #
609
+ #==============================================================================
610
+ def usage():
611
+ """
612
+ Prints usage message.
613
+ """
614
+
615
+ print('Usage:', os.path.basename(sys.argv[0]), '[options]')
616
+ print('Options:')
617
+ print(' -a, --padapt Try to adapt (simplify) input formula [Primer]')
618
+ print(' -A, --oadapt Try to adapt (simplify) input formula [OptUx]')
619
+ print(' -d, --pdcalls Apply clause D calls (in unsorted enumeration only) [Primer]')
620
+ print(' -D, --odcalls Apply clause D calls (in unsorted enumeration only) [OptUx]')
621
+ print(' -e, --enum=<int> Enumerate this many "top-k" solutions')
622
+ print(' Available values: [1 .. INT_MAX], all (default = 1)')
623
+ print(' -h, --help Print this help message')
624
+ print(' -m, --pminimize Use a heuristic unsatisfiable core minimizer [Primer]')
625
+ print(' -M, --ominimize Use a heuristic unsatisfiable core minimizer [OptUx]')
626
+ print(' -n, --no-disj Do not enumerate disjoint MCSes [OptUx]')
627
+ print(' -p, --ppuresat=<string> Use a pure SAT-based hitting set enumerator [Primer]')
628
+ print(' Available values: cd15, cd19, lgl, mgh (default = mgh)')
629
+ print(' Requires: unsorted mode, i.e. \'-u\'')
630
+ print(' -P, --opuresat=<string> Use a pure SAT-based hitting set enumerator [OptUx]')
631
+ print(' Available values: cd15, cd19, lgl, mgh (default = mgh)')
632
+ print(' Requires: unsorted mode, i.e. \'-U\'')
633
+ print(' -r, --reduce Dual prime minimiser [Primer]')
634
+ print(' Available values: lin, bin (default = lin)')
635
+ print(' -R, --repr=<string> Target representation')
636
+ print(' Available values: dnf, cnf (default = cnf)')
637
+ print(' -s, --psolver SAT solver to use [Primer]')
638
+ print(' Available values: cd, cd15, cd19, g3, g41, g42, lgl, mcb, mcm, mpl, m22, mc, mg3, mgh (default = cd19)')
639
+ print(' -S, --osolver SAT solver to use [OptUx]')
640
+ print(' Available values: cd, cd15, cd19, g3, g41, g42, lgl, mcb, mcm, mpl, m22, mc, mg3, mgh (default = mgh)')
641
+ print(' -t, --ptrim=<int> How many times to trim unsatisfiable cores [Primer]')
642
+ print(' Available values: [0 .. INT_MAX] (default = 0)')
643
+ print(' -T, --otrim=<int> How many times to trim unsatisfiable cores [OptUx]')
644
+ print(' Available values: [0 .. INT_MAX] (default = 0)')
645
+ print(' -u, --punsorted Enumerate MUSes in an unsorted way using LBX [Primer]')
646
+ print(' -U, --ounsorted Enumerate MUSes in an unsorted way using LBX [OptUx]')
647
+ print(' -v, --verbose Be verbose')
648
+ print(' -w, --weighted Target optimal representations with respect the total number of literals')
649
+ print(' -x, --pexhaust Exhaust new unsatisfiable cores [Primer]')
650
+ print(' -X, --oexhaust Exhaust new unsatisfiable cores [OptUx]')
651
+
652
+
653
+ #
654
+ #==============================================================================
655
+ if __name__ == '__main__':
656
+ # parse command-line options
657
+ to_enum, mode, padapt, oadapt, pdcalls, odcalls, pexhaust, oexhaust, \
658
+ pminz, ominz, nodisj, ptrim, otrim, search, psolver, osolver, \
659
+ ppuresat, opuresat, punsorted, ounsorted, verbose, weighted, \
660
+ files = parse_options()
661
+
662
+ if files:
663
+ # read CNF from file
664
+ assert re.search(r'cnf(\.(gz|bz2|lzma|xz|zst))?$', files[0]), 'Unknown input file extension'
665
+ formula = CNF(from_file=files[0])
666
+
667
+ # creating an object of Primer
668
+ with Bica(formula, negated=None, target=mode, psolver=psolver,
669
+ padapt=padapt, pdcalls=pdcalls, pexhaust=pexhaust,
670
+ pminz=pminz, ppuresat=ppuresat, psearch=search,
671
+ punsorted=punsorted, ptrim=ptrim, osolver=osolver,
672
+ oadapt=oadapt, odcalls=odcalls, oexhaust=oexhaust,
673
+ ominz=ominz, onodisj=nodisj, opuresat=opuresat,
674
+ ounsorted=ounsorted, otrim=otrim, weighted=weighted,
675
+ verbose=verbose) as bica:
676
+
677
+ for i, minf in enumerate(bica.enumerate()):
678
+ if verbose > 1:
679
+ minf = CNF(from_clauses=[bica.primes[i - 1] for i in minf])
680
+ minf.to_fp(sys.stdout, as_dnf=True if mode == 'dnf' else False)
681
+
682
+ print('o {0}'.format(bica.optux.cost))
683
+
684
+ # checking if we are done
685
+ if to_enum and i + 1 == to_enum:
686
+ break
687
+
688
+ # reporting the total oracle time
689
+ print('c primer time: {0:.4f}'.format(bica.primer.oracle_time()))
690
+ print('c optux time: {0:.4f}'.format(bica.optux.oracle_time()))
691
+ print('c total time: {0:.4f}'.format(bica.oracle_time()))