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