python-sat 1.8.dev21__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 (46) 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/bica.py +692 -0
  12. pysat/examples/fm.py +527 -0
  13. pysat/examples/genhard.py +516 -0
  14. pysat/examples/hitman.py +653 -0
  15. pysat/examples/lbx.py +638 -0
  16. pysat/examples/lsu.py +494 -0
  17. pysat/examples/mcsls.py +610 -0
  18. pysat/examples/models.py +189 -0
  19. pysat/examples/musx.py +344 -0
  20. pysat/examples/optux.py +710 -0
  21. pysat/examples/primer.py +620 -0
  22. pysat/examples/rc2.py +1858 -0
  23. pysat/examples/usage.py +63 -0
  24. pysat/formula.py +5594 -0
  25. pysat/pb.py +442 -0
  26. pysat/process.py +363 -0
  27. pysat/solvers.py +7591 -0
  28. pysolvers.cpython-310-darwin.so +0 -0
  29. python_sat-1.8.dev21.data/scripts/approxmc.py +385 -0
  30. python_sat-1.8.dev21.data/scripts/bica.py +692 -0
  31. python_sat-1.8.dev21.data/scripts/fm.py +527 -0
  32. python_sat-1.8.dev21.data/scripts/genhard.py +516 -0
  33. python_sat-1.8.dev21.data/scripts/lbx.py +638 -0
  34. python_sat-1.8.dev21.data/scripts/lsu.py +494 -0
  35. python_sat-1.8.dev21.data/scripts/mcsls.py +610 -0
  36. python_sat-1.8.dev21.data/scripts/models.py +189 -0
  37. python_sat-1.8.dev21.data/scripts/musx.py +344 -0
  38. python_sat-1.8.dev21.data/scripts/optux.py +710 -0
  39. python_sat-1.8.dev21.data/scripts/primer.py +620 -0
  40. python_sat-1.8.dev21.data/scripts/rc2.py +1858 -0
  41. python_sat-1.8.dev21.data/scripts/unigen.py +435 -0
  42. python_sat-1.8.dev21.dist-info/METADATA +45 -0
  43. python_sat-1.8.dev21.dist-info/RECORD +46 -0
  44. python_sat-1.8.dev21.dist-info/WHEEL +6 -0
  45. python_sat-1.8.dev21.dist-info/licenses/LICENSE.txt +21 -0
  46. python_sat-1.8.dev21.dist-info/top_level.txt +3 -0
File without changes
pysat/examples/bica.py ADDED
@@ -0,0 +1,692 @@
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
+
265
+ def __init__(self, formula, negated=None, target='cnf', psolver='cd19',
266
+ padapt=False, pdcalls=False, pexhaust=False, pminz=False,
267
+ ppuresat=False, psearch='lin', punsorted=False, ptrim=False,
268
+ osolver='mgh', oadapt=False, odcalls=False, oexhaust=False,
269
+ ominz=False, onodisj=False, opuresat=False, ounsorted=False,
270
+ otrim=False, weighted=False, verbose=0):
271
+ """
272
+ Initialiser.
273
+ """
274
+
275
+ # copying some of the arguments
276
+ self.form = formula
277
+ self.fneg = negated
278
+ self.target = target
279
+ self.verbose = verbose
280
+ self.weighted = weighted
281
+
282
+ # Primer's parameters
283
+ self.psolver = psolver
284
+ self.padapt = padapt
285
+ self.pdcalls = pdcalls
286
+ self.pexhaust = pexhaust
287
+ self.pminz = pminz
288
+ self.ppuresat = ppuresat
289
+ self.psearch = psearch
290
+ self.punsorted = punsorted
291
+ self.ptrim = ptrim
292
+
293
+ # OptUx's parameters
294
+ self.osolver = osolver
295
+ self.oadapt = oadapt
296
+ self.odcalls = odcalls
297
+ self.oexhaust = oexhaust
298
+ self.ominz = ominz
299
+ self.onodisj = onodisj
300
+ self.opuresat = opuresat
301
+ self.ounsorted = ounsorted
302
+ self.otrim = otrim
303
+
304
+ # oracles solving the two subproblems
305
+ self.primer, self.optux, self.primes = None, None, []
306
+
307
+ # if no negated formula was given, we create one
308
+ if self.fneg is None:
309
+ self.fneg = Neg(self.form)
310
+
311
+ # input formula for OptUx to be gradually constructed
312
+ # during prime enumeration phase;
313
+ self.pform = WCNF()
314
+ if self.target == 'dnf':
315
+ for cl in self.form:
316
+ self.pform.append(cl)
317
+ else:
318
+ # if the target is CNF, we need to add the negated formula
319
+ for cl in self.fneg:
320
+ self.pform.append(cl)
321
+
322
+ self._init_primer()
323
+
324
+ def _init_primer(self):
325
+ """
326
+ Constructs and initialises the Primer object.
327
+ """
328
+
329
+ implicates = False if self.target == 'dnf' else True
330
+
331
+ self.primer = Primer(self.form, negated=self.fneg,
332
+ solver=self.psolver, implicates=implicates,
333
+ adapt=self.padapt, dcalls=self.pdcalls,
334
+ exhaust=self.pexhaust, minz=self.pminz,
335
+ puresat=self.ppuresat, search=self.psearch,
336
+ unsorted=self.punsorted, trim=self.ptrim,
337
+ verbose=self.verbose - 1)
338
+
339
+ def __del__(self):
340
+ """
341
+ Destructor.
342
+ """
343
+
344
+ self.delete()
345
+
346
+ def __enter__(self):
347
+ """
348
+ 'with' constructor.
349
+ """
350
+
351
+ return self
352
+
353
+ def __exit__(self, exc_type, exc_value, traceback):
354
+ """
355
+ 'with' destructor.
356
+ """
357
+
358
+ self.delete()
359
+
360
+ def delete(self):
361
+ """
362
+ Explicit destructor of both primer and optux. Also, clears the
363
+ list of primes computed.
364
+
365
+ (The former is constructed in Bica's initialiser while the latter
366
+ is created on demand, once the first phase of the algorithm has
367
+ been finished, i.e. when all the primes have been enumerated.)
368
+ """
369
+
370
+ self.primes = []
371
+
372
+ if self.primer:
373
+ self.primer.delete()
374
+ self.primer = None
375
+
376
+ if self.optux:
377
+ self.optux.delete()
378
+ self.optux = None
379
+
380
+ def compute(self):
381
+ """
382
+ Computes a single minimum representation of the input formula as a
383
+ list of indices of prime implicants (or implicates) determined to
384
+ comprise the representation.
385
+
386
+ Note that the indices in the returned list start from ``1``, i.e.
387
+ the user is supposed to subtract ``1`` for each of them to get the
388
+ correct list of primes. Consider the following example:
389
+
390
+ .. code-block:: python
391
+
392
+ >>> from pysat.examples.bica import Bica
393
+ >>> from pysat.formula import CNF
394
+ >>>
395
+ >>> cnf = CNF(from_clauses=[[-1, 2], [-2, 3], [-3, 4], [4, 5]])
396
+ >>>
397
+ >>> with Bica(formula) as bica:
398
+ ... for minf in bica.enumerate():
399
+ ... minf = CNF(from_clauses=[bica.primes[i - 1] for i in minf])
400
+ ... print(minf)
401
+ ... print(f'all primes implicates: {bica.primes}')
402
+ CNF(from_string='p cnf 4 3\\n4 0\\n-2 3 0\\n-1 2 0')
403
+ all prime implicates: [[4], [-2, 3], [-1, 3], [-1, 2]]
404
+
405
+ :rtype: list(int)
406
+ """
407
+
408
+ # first, collecing all the primes
409
+ if not self.primes:
410
+ for prime in self.primer.enumerate():
411
+ self.primes.append(prime)
412
+
413
+ # recording the prime
414
+ if self.target == 'cnf':
415
+ self.pform.append(prime, weight=len(prime) if self.weighted else 1)
416
+ else:
417
+ self.pform.append([-l for l in prime], weight=len(prime) if self.weighted else 1)
418
+
419
+ # reporting it
420
+ if self.verbose > 1:
421
+ print('c prime {0} 0'.format(' '.join(['{0}{1}'.format('+' if v > 0 else '', v) for v in prime])))
422
+
423
+ if not self.optux:
424
+ # creating an OptUx object
425
+ self.optux = OptUx(self.pform, solver=self.osolver,
426
+ adapt=self.oadapt, cover=None,
427
+ dcalls=self.odcalls, exhaust=self.oexhaust,
428
+ minz=self.ominz, nodisj=self.onodisj,
429
+ puresat=self.opuresat, unsorted=self.ounsorted,
430
+ trim=self.otrim, verbose=self.verbose)
431
+
432
+ return self.optux.compute()
433
+
434
+ def enumerate(self):
435
+ """
436
+ This is generator method iterating through minimum representations
437
+ and enumerating them until no more of them exists, or a user
438
+ decides to stop the process.
439
+
440
+ .. code-block:: python
441
+
442
+ >>> from pysat.examples.bica import Bica
443
+ >>> from pysat.formula import *
444
+ >>>
445
+ >>> cnf = CNF(from_file='test.cnf')
446
+ >>> print(cnf)
447
+ 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')
448
+ >>>
449
+ >>> with Bica(cnf) as bica:
450
+ ... for minf in bica.enumerate():
451
+ ... print(minf) # prime indices start from 1!
452
+ [1, 2, 8, 9, 10]
453
+ [1, 2, 3, 8, 10]
454
+ [1, 2, 3, 6, 10]
455
+ [1, 2, 3, 4, 8]
456
+ [1, 2, 3, 4, 6]
457
+ [1, 2, 4, 7, 8]
458
+ [1, 2, 4, 8, 9]
459
+ [1, 2, 4, 5, 8]
460
+ [1, 2, 4, 6, 7]
461
+ [1, 2, 4, 5, 6]
462
+ [1, 2, 4, 6, 9]
463
+ [1, 2, 6, 7, 10]
464
+ [1, 2, 7, 8, 10]
465
+ [1, 2, 5, 8, 10]
466
+ [1, 2, 5, 6, 10]
467
+ [1, 2, 6, 9, 10]
468
+
469
+ :rtype: list(int)
470
+ """
471
+
472
+ done = False
473
+
474
+ while not done:
475
+ minf = self.compute()
476
+
477
+ if minf is not None:
478
+ yield minf
479
+ else:
480
+ done = True
481
+
482
+ def oracle_time(self):
483
+ """
484
+ This method computes and returns the total SAT solving time
485
+ involved, including the time spent by :class:`.Primer` and
486
+ :class:`.OptUx`, which implement the first and second phases
487
+ of the algorithm, respectively.
488
+
489
+ :rtype: float
490
+ """
491
+
492
+ return self.primer.oracle_time() + self.optux.oracle_time()
493
+
494
+
495
+ class Crux(Bica):
496
+ """
497
+ A clone of Bica, to be used interchangeably.
498
+ """
499
+
500
+ pass
501
+
502
+
503
+ #
504
+ #==============================================================================
505
+ def parse_options():
506
+ """
507
+ Parses command-line options:
508
+ """
509
+
510
+ try:
511
+ opts, args = getopt.getopt(sys.argv[1:],
512
+ 'aAdDe:hmMnp:P:r:R:s:S:t:T:uUvwxX',
513
+ ['padapt', 'oadapt', 'pdcalls', 'odcalls',
514
+ 'enum=', 'help', 'pminimize', 'ominimize',
515
+ 'no-disj', 'ppuresat=', 'opuresat=',
516
+ 'reduce=', 'repr=', 'psolver=',
517
+ 'osolver=', 'ptrim=', 'otrim=',
518
+ 'punsorted', 'ounsorted', 'verbose',
519
+ 'weighted', 'pexhaust', 'oexhaust'])
520
+ except getopt.GetoptError as err:
521
+ sys.stderr.write(str(err).capitalize())
522
+ usage()
523
+ sys.exit(1)
524
+
525
+ to_enum = 1
526
+ mode = 'cnf'
527
+ search = 'lin'
528
+ verbose = 1
529
+ weighted = False
530
+
531
+ padapt = False
532
+ oadapt = False
533
+ pdcalls = False
534
+ odcalls = False
535
+ pexhaust = False
536
+ oexhaust = False
537
+ pminz = False
538
+ ominz = False
539
+ nodisj = False
540
+ psolver = 'cd19'
541
+ osolver = 'mgh'
542
+ ppuresat = False
543
+ opuresat = False
544
+ punsorted = False
545
+ ounsorted = False
546
+ ptrim = 0
547
+ otrim = 0
548
+
549
+ for opt, arg in opts:
550
+ if opt in ('-a', '--padapt'):
551
+ padapt = True
552
+ elif opt in ('-A', '--oadapt'):
553
+ oadapt = True
554
+ elif opt in ('-d', '--pdcalls'):
555
+ pdcalls = True
556
+ elif opt in ('-D', '--odcalls'):
557
+ odcalls = True
558
+ elif opt in ('-e', '--enum'):
559
+ to_enum = str(arg)
560
+ if to_enum != 'all':
561
+ to_enum = int(to_enum)
562
+ elif opt in ('-h', '--help'):
563
+ usage()
564
+ sys.exit(0)
565
+ elif opt in ('-m', '--pminimize'):
566
+ pminz = True
567
+ elif opt in ('-M', '--ominimize'):
568
+ ominz = True
569
+ elif opt in ('-n', '--no-disj'):
570
+ nodisj = True
571
+ elif opt in ('-p', '--ppuresat'):
572
+ ppuresat = str(arg)
573
+ elif opt in ('-P', '--opuresat'):
574
+ opuresat = str(arg)
575
+ elif opt in ('-r', '--reduce'):
576
+ search = str(arg)
577
+ assert search in ('lin', 'bin'), 'Wrong minimisation method: {0}'.format(search)
578
+ elif opt in ('-R', '--repr'):
579
+ mode = str(arg)
580
+ elif opt in ('-s', '--psolver'):
581
+ psolver = str(arg)
582
+ elif opt in ('-S', '--osolver'):
583
+ osolver = str(arg)
584
+ elif opt in ('-u', '--punsorted'):
585
+ punsorted = True
586
+ elif opt in ('-U', '--ounsorted'):
587
+ ounsorted = True
588
+ elif opt in ('-t', '--ptrim'):
589
+ ptrim = int(arg)
590
+ elif opt in ('-T', '--otrim'):
591
+ otrim = int(arg)
592
+ elif opt in ('-v', '--verbose'):
593
+ verbose += 1
594
+ elif opt in ('-w', '--weighted'):
595
+ weighted = True
596
+ elif opt in ('-x', '--pexhaust'):
597
+ pexhaust = True
598
+ elif opt in ('-X', '--oexhaust'):
599
+ oexhaust = True
600
+ else:
601
+ assert False, 'Unhandled option: {0} {1}'.format(opt, arg)
602
+
603
+ return to_enum, mode, padapt, oadapt, pdcalls, odcalls, pexhaust, \
604
+ oexhaust, pminz, ominz, nodisj, ptrim, otrim, search, psolver, \
605
+ osolver, ppuresat, opuresat, punsorted, ounsorted, verbose, \
606
+ weighted, args
607
+
608
+
609
+ #
610
+ #==============================================================================
611
+ def usage():
612
+ """
613
+ Prints usage message.
614
+ """
615
+
616
+ print('Usage:', os.path.basename(sys.argv[0]), '[options]')
617
+ print('Options:')
618
+ print(' -a, --padapt Try to adapt (simplify) input formula [Primer]')
619
+ print(' -A, --oadapt Try to adapt (simplify) input formula [OptUx]')
620
+ print(' -d, --pdcalls Apply clause D calls (in unsorted enumeration only) [Primer]')
621
+ print(' -D, --odcalls Apply clause D calls (in unsorted enumeration only) [OptUx]')
622
+ print(' -e, --enum=<int> Enumerate this many "top-k" solutions')
623
+ print(' Available values: [1 .. INT_MAX], all (default = 1)')
624
+ print(' -h, --help Print this help message')
625
+ print(' -m, --pminimize Use a heuristic unsatisfiable core minimizer [Primer]')
626
+ print(' -M, --ominimize Use a heuristic unsatisfiable core minimizer [OptUx]')
627
+ print(' -n, --no-disj Do not enumerate disjoint MCSes [OptUx]')
628
+ print(' -p, --ppuresat=<string> Use a pure SAT-based hitting set enumerator [Primer]')
629
+ print(' Available values: cd15, cd19, lgl, mgh (default = mgh)')
630
+ print(' Requires: unsorted mode, i.e. \'-u\'')
631
+ print(' -P, --opuresat=<string> Use a pure SAT-based hitting set enumerator [OptUx]')
632
+ print(' Available values: cd15, cd19, lgl, mgh (default = mgh)')
633
+ print(' Requires: unsorted mode, i.e. \'-U\'')
634
+ print(' -r, --reduce Dual prime minimiser [Primer]')
635
+ print(' Available values: lin, bin (default = lin)')
636
+ print(' -R, --repr=<string> Target representation')
637
+ print(' Available values: dnf, cnf (default = cnf)')
638
+ print(' -s, --psolver SAT solver to use [Primer]')
639
+ print(' Available values: cd, cd15, cd19, g3, g41, g42, lgl, mcb, mcm, mpl, m22, mc, mg3, mgh (default = cd19)')
640
+ print(' -S, --osolver SAT solver to use [OptUx]')
641
+ print(' Available values: cd, cd15, cd19, g3, g41, g42, lgl, mcb, mcm, mpl, m22, mc, mg3, mgh (default = mgh)')
642
+ print(' -t, --ptrim=<int> How many times to trim unsatisfiable cores [Primer]')
643
+ print(' Available values: [0 .. INT_MAX] (default = 0)')
644
+ print(' -T, --otrim=<int> How many times to trim unsatisfiable cores [OptUx]')
645
+ print(' Available values: [0 .. INT_MAX] (default = 0)')
646
+ print(' -u, --punsorted Enumerate MUSes in an unsorted way using LBX [Primer]')
647
+ print(' -U, --ounsorted Enumerate MUSes in an unsorted way using LBX [OptUx]')
648
+ print(' -v, --verbose Be verbose')
649
+ print(' -w, --weighted Target optimal representations with respect the total number of literals')
650
+ print(' -x, --pexhaust Exhaust new unsatisfiable cores [Primer]')
651
+ print(' -X, --oexhaust Exhaust new unsatisfiable cores [OptUx]')
652
+
653
+
654
+ #
655
+ #==============================================================================
656
+ if __name__ == '__main__':
657
+ # parse command-line options
658
+ to_enum, mode, padapt, oadapt, pdcalls, odcalls, pexhaust, oexhaust, \
659
+ pminz, ominz, nodisj, ptrim, otrim, search, psolver, osolver, \
660
+ ppuresat, opuresat, punsorted, ounsorted, verbose, weighted, \
661
+ files = parse_options()
662
+
663
+ if files:
664
+ # read CNF from file
665
+ if re.search(r'cnf(\.(gz|bz2|lzma|xz))?$', files[0]):
666
+ formula = CNF(from_file=files[0])
667
+
668
+ # creating an object of Primer
669
+ with Bica(formula, negated=None, target=mode, psolver=psolver,
670
+ padapt=padapt, pdcalls=pdcalls, pexhaust=pexhaust,
671
+ pminz=pminz, ppuresat=ppuresat, psearch=search,
672
+ punsorted=punsorted, ptrim=ptrim, osolver=osolver,
673
+ oadapt=oadapt, odcalls=odcalls, oexhaust=oexhaust,
674
+ ominz=ominz, onodisj=nodisj, opuresat=opuresat,
675
+ ounsorted=ounsorted, otrim=otrim, weighted=weighted,
676
+ verbose=verbose) as bica:
677
+
678
+ for i, minf in enumerate(bica.enumerate()):
679
+ if verbose > 1:
680
+ minf = CNF(from_clauses=[bica.primes[i - 1] for i in minf])
681
+ minf.to_fp(sys.stdout, as_dnf=True if mode == 'dnf' else False)
682
+
683
+ print('o {0}'.format(bica.optux.cost))
684
+
685
+ # checking if we are done
686
+ if to_enum and i + 1 == to_enum:
687
+ break
688
+
689
+ # reporting the total oracle time
690
+ print('c primer time: {0:.4f}'.format(bica.primer.oracle_time()))
691
+ print('c optux time: {0:.4f}'.format(bica.optux.oracle_time()))
692
+ print('c total time: {0:.4f}'.format(bica.oracle_time()))