python-sat 1.8.dev25__cp310-cp310-musllinux_1_2_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.
Files changed (50) hide show
  1. pycard.cpython-310-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-310-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 +50 -0
  46. python_sat-1.8.dev25.dist-info/WHEEL +5 -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
  49. python_sat.libs/libgcc_s-0cd532bd.so.1 +0 -0
  50. python_sat.libs/libstdc++-5d72f927.so.6.0.33 +0 -0
@@ -0,0 +1,620 @@
1
+ #!/usr/bin/env python
2
+ #-*- coding:utf-8 -*-
3
+ ##
4
+ ## primer.py
5
+ ##
6
+ ## Created on: Jul 23, 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
+ Primer
20
+
21
+ ==================
22
+ Module description
23
+ ==================
24
+
25
+ A reimplementation of the prime implicant (and implicate) enumeration
26
+ algorithm originally called Primer-B [1]_. The algorithm exploits the
27
+ minimal hitting duality between prime implicants and implicates of an
28
+ input formula and hence makes extensive use of a hitting set enumerator.
29
+ The input formula can be in a clausal or a non-clausal form, i.e. the
30
+ input can be given as an object of either :class:`.CNF` or
31
+ :class:`.Formula`.
32
+
33
+ The implementation relies on :class:`.Hitman` and supports both sorted and
34
+ unsorted hitting set enumeration. In the former case, hitting sets are
35
+ computed from smallest to largest, which is achieved with MaxSAT-based
36
+ hitting set enumeration, using :class:`.RC2` [2]_ [3]_ [4]_. In the latter
37
+ case, either an LBX-like MCS enumerator :class:`.LBX` [5]_ is used or
38
+ *pure* SAT-based minimal model enumeration [6]_.
39
+
40
+ .. [1] Alessandro Previti, Alexey Ignatiev, António Morgado,
41
+ Joao Marques-Silva. *Prime Compilation of Non-Clausal Formulae.*
42
+ IJCAI 2015. pp. 1980-1988
43
+
44
+ .. [2] António Morgado, Carmine Dodaro, Joao Marques-Silva. *Core-Guided
45
+ MaxSAT with Soft Cardinality Constraints*. CP 2014. pp. 564-573
46
+
47
+ .. [3] António Morgado, Alexey Ignatiev, Joao Marques-Silva. *MSCG: Robust
48
+ Core-Guided MaxSAT Solving*. JSAT 9. 2014. pp. 129-134
49
+
50
+ .. [4] Alexey Ignatiev, António Morgado, Joao Marques-Silva. *RC2: a
51
+ Python-based MaxSAT Solver*. MaxSAT Evaluation 2018. p. 22
52
+
53
+ .. [5] Carlos Mencía, Alessandro Previti, Joao Marques-Silva.
54
+ *Literal-Based MCS Extraction*. IJCAI. 2015. pp. 1973-1979
55
+
56
+ .. [6] Enrico Giunchiglia, Marco Maratea. *Solving Optimization Problems
57
+ with DLL*. ECAI 2006. pp. 377-381
58
+
59
+ The implementation can be used as an executable (the list of available
60
+ command-line options can be shown using ``primer.py -h``) in the following
61
+ way:
62
+
63
+ ::
64
+
65
+ $ xzcat formula.cnf.xz
66
+ p cnf 4 3
67
+ 1 2 4 0
68
+ 1 -2 3 0
69
+ -1 2 -4 0
70
+
71
+ $ primer.py -i -e all formula.cnf.xz
72
+ v +1 +2 0
73
+ v +2 +3 0
74
+ v +1 -4 0
75
+ v -1 +3 +4 0
76
+ v -1 -2 +4 0
77
+ c primes: 5
78
+ c oracle time: 0.0001
79
+ c oracle calls: 41
80
+
81
+ Alternatively, the algorithm can be accessed and invoked through the
82
+ standard ``import`` interface of Python, e.g.
83
+
84
+ .. code-block:: python
85
+
86
+ >>> from pysat.examples.primer import Primer
87
+ >>> from pysat.formula import CNF
88
+ >>>
89
+ >>> cnf = CNF(from_file='test.cnf.xz')
90
+ >>>
91
+ >>> with Primer(cnf, implicates=False) as primer:
92
+ ... for p in primer.enumerate():
93
+ ... print(f'prime: {p}')
94
+ ...
95
+ prime: [2, 3]
96
+ prime: [1, 2]
97
+ prime: [1, -4]
98
+ prime: [-1, 3, 4]
99
+ prime: [-1, -2, 4]
100
+
101
+ The tool can be instructed to enumerate either prime implicates or prime
102
+ implicants (a set of the dual primes covering the formula is computed as a
103
+ by-product of Primer's implicit hitting set algorithm). Namely, it targets
104
+ implicate enumeration *by default*; setting the Boolean parameter
105
+ ``implicates=False`` will force it to focus on prime implicants instead.
106
+ (In the command line, the same effect can be achieved if using the option
107
+ '-i'.)
108
+
109
+ A user may also want to compute :math:`k` primes instead of enumerating
110
+ them exhaustively. This may come in handy, for example, if the input
111
+ formula has an exponential number of primes. Command-line option `-e NUM`
112
+ is responsible for this. In the case of complete prime implicant
113
+ enumeration the algorithm will essentially end up computing the input
114
+ formula's *Blake Canonical Form* (BCF) [7]_.
115
+
116
+ .. [7] Archie Blake. *Canonical Expressions in Boolean Algebra.*
117
+ Dissertation. University of Chicago. 1937.
118
+
119
+ ==============
120
+ Module details
121
+ ==============
122
+ """
123
+
124
+ #
125
+ #==============================================================================
126
+ import getopt
127
+ import os
128
+ from pysat.examples.hitman import Hitman
129
+ from pysat.formula import IDPool, CNF, Neg
130
+ from pysat.solvers import Solver
131
+ import re
132
+ import sys
133
+
134
+
135
+ #
136
+ #==============================================================================
137
+ class Primer:
138
+ """
139
+ A simple Python-based reimplementation of the Primer-B algorithm. It
140
+ can be used for computing either :math:`k` prime implicates or
141
+ implicants of an input formula, or enumerating them all exhaustively
142
+ As the algorithm is based on implicit hitting set enumeration, a set
143
+ of dual primes (either prime implicants or implicates) covering the
144
+ input formula is computed as a by-product.
145
+
146
+ The input formula can be specified either in :class:`.CNF` or be a
147
+ generic Boolean :class:`.Formula`. In the latter case, the
148
+ implementation will clausify the formula and, importantly, report all
149
+ the primes using the integer variable IDs introduced by the
150
+ clausification process. As a result, a user is assumed responsible for
151
+ translating these back to the original :class:`Atom` objects, should
152
+ the need arise.
153
+
154
+ Additionally, the user may additionally specify the negation of the
155
+ formula (if not, Primer will create one in the process) and a few
156
+ input parameters controlling the run of the algorithm. All of these in
157
+ fact relate to the parameters of the hitting set enumerator, which is
158
+ the key component of the tool.
159
+
160
+ Namely, a user may specify the SAT solver of their choice to be used
161
+ by :class:`.Hitman` and the two extra SAT oracles as well as set the
162
+ parameters of MaxSAT/MCS/SAT-based hitting set enumeration. For
163
+ details on these parameters and what exactly they control, please
164
+ refer to to the description of :class:`.Hitman`.
165
+
166
+ Finally, when the algorithm determines a hitting set *not* to be a
167
+ target prime, a model is extracted evidencing this fact, which is then
168
+ reduced into a *dual prime*. The reduction process is based on MUS
169
+ extraction and can involve a linear literal traversal or dichotomic
170
+ similar to the ideas of QuickXPlain [8]_. The choice of the type of
171
+ literal traversal can be made using the ``search`` parameter, which
172
+ can be set either to ``'lin'`` or ``'bin'``.
173
+
174
+ .. [8] Ulrich Junker. *QUICKXPLAIN: Preferred Explanations and
175
+ Relaxations for Over-Constrained Problems.* AAAI 2004.
176
+ pp. 167-172
177
+
178
+ The complete list of input parameters is as follows:
179
+
180
+ :param formula: input formula whose prime representation is sought
181
+ :param negated: input's formula negation (if any)
182
+ :param solver: SAT oracle name
183
+ :param implicates: whether or not prime implicates to target
184
+ :param adapt: detect and adapt intrinsic AtMost1 constraints
185
+ :param dcalls: apply clause D oracle calls (for unsorted enumeration only)
186
+ :param exhaust: do core exhaustion
187
+ :param minz: do heuristic core reduction
188
+ :param puresat: use pure SAT-based hitting set enumeration
189
+ :param search: dual prime reduction strategy
190
+ :param unsorted: apply unsorted MUS enumeration
191
+ :param trim: do core trimming at most this number of times
192
+ :param verbose: verbosity level
193
+
194
+ :type formula: :class:`.Formula` or :class:`.CNF`
195
+ :type negated: :class:`.Formula` or :class:`.CNF`
196
+ :type solver: str
197
+ :type implicates: bool
198
+ :type adapt: bool
199
+ :type dcalls: bool
200
+ :type exhaust: bool
201
+ :type minz: bool
202
+ :type puresat: str
203
+ :type search: str
204
+ :type unsorted: bool
205
+ :type trim: int
206
+ :type verbose: int
207
+ """
208
+
209
+ def __init__(self, formula, negated=None, solver='cd19', implicates=True,
210
+ adapt=False, dcalls=False, exhaust=False, minz=False,
211
+ puresat=False, search='lin', unsorted=False, trim=False,
212
+ verbose=0):
213
+ """
214
+ Initialiser.
215
+ """
216
+
217
+ # copying some of the arguments
218
+ self.form = formula
219
+ self.fneg = negated
220
+ self.mode = bool(implicates)
221
+
222
+ # dual prime minimisation strategy
223
+ self.search = search
224
+
225
+ # verbosity level
226
+ self.verbose = verbose
227
+
228
+ # number of SAT oracle calls
229
+ self.calls = 0
230
+
231
+ # creating hitman
232
+ if not unsorted:
233
+ # MaxSAT-based hitting set enumerator
234
+ self.hitman = Hitman(bootstrap_with=[], solver=solver,
235
+ htype='sorted', mxs_adapt=adapt,
236
+ mxs_exhaust=exhaust, mxs_minz=minz,
237
+ mxs_trim=trim)
238
+ elif not puresat:
239
+ # MCS-based hitting set enumerator
240
+ self.hitman = Hitman(bootstrap_with=[], solver=solver,
241
+ htype='lbx', mcs_usecld=dcalls)
242
+ else:
243
+ # pure SAT-based hitting set enumerator with preferred phases
244
+ self.hitman = Hitman(bootstrap_with=[], solver=puresat,
245
+ htype='sat')
246
+
247
+ # creating the checker and reducer oracles
248
+ self.checker = Solver(name=solver, use_timer=True)
249
+ self.reducer = Solver(name=solver, use_timer=True)
250
+
251
+ # populate all the oracles with all the relevant clauses
252
+ self.init_oracles()
253
+
254
+ def __del__(self):
255
+ """
256
+ Destructor.
257
+ """
258
+
259
+ self.delete()
260
+
261
+ def __enter__(self):
262
+ """
263
+ 'with' constructor.
264
+ """
265
+
266
+ return self
267
+
268
+ def __exit__(self, exc_type, exc_value, traceback):
269
+ """
270
+ 'with' destructor.
271
+ """
272
+
273
+ self.delete()
274
+
275
+ def delete(self):
276
+ """
277
+ Explicit destructor of the internal hitting set enumerator and
278
+ the SAT oracles.
279
+ """
280
+
281
+ self.calls = 0
282
+
283
+ if self.hitman:
284
+ self.hitman.delete()
285
+ self.hitman = None
286
+
287
+ if self.checker:
288
+ self.checker.delete()
289
+ self.checker = None
290
+
291
+ if self.reducer:
292
+ self.reducer.delete()
293
+ self.reducer = None
294
+
295
+ def init_oracles(self):
296
+ """
297
+ Encodes the formula in dual-rail representation and initialises
298
+ the hitting set enumerator as well as the two additional SAT
299
+ oracles.
300
+
301
+ In particular, this method initialises the hitting set enumerator
302
+ with the dual-rail clauses :math:`(\\neg{p_i} \\vee \\neg{n_i})`
303
+ for each variable :math:`v_i` of the formula. Additionally, the
304
+ two SAT oracles (*prime checker* and *dual reducer*) are fed the
305
+ input formula and its negation, or the other way around (depending
306
+ on whether the user aims at enumerating implicates of implicants).
307
+
308
+ Given the above, the method necessarily creates a clausal
309
+ representation of both the original formula and its negation,
310
+ """
311
+
312
+ # creating the negated formula
313
+ if self.fneg is None:
314
+ self.fneg = Neg(self.form)
315
+
316
+ # initialising the checker and reducer oracles
317
+ if self.mode is True:
318
+ self.checker.append_formula(self.form)
319
+ self.reducer.append_formula(self.fneg)
320
+ else:
321
+ self.checker.append_formula(self.fneg)
322
+ self.reducer.append_formula(self.form)
323
+
324
+ # list of original literals
325
+ self.lits = []
326
+
327
+ # initialising hitman, with all the dual-rail literals
328
+ self.dpool = IDPool()
329
+ for a in self.form.atoms():
330
+ if type(a) is int:
331
+ self.lits.append(+a)
332
+ self.lits.append(-a)
333
+ self.hitman.block([self.dpool.id(+a), self.dpool.id(-a)])
334
+ else:
335
+ self.lits.append(+a.name)
336
+ self.lits.append(-a.name)
337
+ self.hitman.block([self.dpool.id(a.name), self.dpool.id(-a.name)])
338
+
339
+ # converting the list of original literals into a set; it is
340
+ # to be used to filter out auxiliary variables from the model
341
+ self.lits = set(self.lits)
342
+
343
+ def compute(self):
344
+ """
345
+ Computes a single prime. Performs as many iterations of the
346
+ Primer-B algorithm as required to get the next prime. This often
347
+ involves the computation of the dual cover of the formula.
348
+
349
+ Returns a list of literals included in the result prime.
350
+
351
+ :rtype: list(int)
352
+ """
353
+
354
+ while True:
355
+ # computing a new candidate prime
356
+ hs = self.hitman.get()
357
+
358
+ if hs is None:
359
+ # no more hitting sets exist
360
+ break
361
+
362
+ # mapping dual-rail variables to original variables
363
+ prime = [self.dpool.obj(l) for l in hs]
364
+
365
+ self.calls += 1
366
+ if not self.checker.solve(assumptions=[(1 - 2 * self.mode) * l for l in prime]):
367
+ if self.verbose > 2:
368
+ print('c trgt: {0} 0 ✓'.format(' '.join(['{0}{1}'.format('+' if v > 0 else '', v) for v in prime])))
369
+
370
+ # this is a target prime: we block it and return
371
+ self.hitman.block(hs)
372
+ return prime
373
+ else:
374
+ if self.verbose > 2:
375
+ print('c trgt: {0} 0 ✗'.format(' '.join(['{0}{1}'.format('+' if v > 0 else '', v) for v in prime])))
376
+
377
+ # candidate is not a target prime, so we
378
+ # need to extract and hit a dual prime
379
+
380
+ # filtering the model so that it contains no auxiliary variables
381
+ model = [l for l in self.checker.get_model() if l in self.lits]
382
+
383
+ # model minimisation
384
+ dual = [(2 * self.mode - 1) * l for l in self.minimise_dual(model)]
385
+ self.hitman.hit([self.dpool.id(lit) for lit in dual])
386
+
387
+ if self.verbose > 2:
388
+ print('c dual: {0} 0'.format(' '.join(['{0}{1}'.format('+' if v > 0 else '', v) for v in dual])))
389
+
390
+ def minimise_dual(self, core):
391
+ """
392
+ Reduces a *dual* prime from the model of the checker oracle. The
393
+ procedure is initialised with the over-approximation of a prime
394
+ and builds on simple MUS extraction. Hence the name of the input
395
+ parameter to start from: `core`. The result of this method is a
396
+ dual prime.
397
+
398
+ The method traverses the dual to reduce either in the linear
399
+ fashion or runs dichotomic QuickXPlain-like literal traversal.
400
+ This is controlled by the input parameter ``search`` passed to the
401
+ constructor of :class:`Primer`.
402
+
403
+ :rtype: list(int)
404
+
405
+ """
406
+
407
+ def _do_linear(core):
408
+ """
409
+ Do linear search.
410
+ """
411
+
412
+ def _assump_needed(a):
413
+ if len(to_test) > 1:
414
+ to_test.remove(a)
415
+ self.calls += 1
416
+ if not self.reducer.solve(assumptions=to_test):
417
+ return False
418
+ to_test.add(a)
419
+ return True
420
+ else:
421
+ return True
422
+
423
+ to_test = set(core)
424
+ return list(filter(lambda a: _assump_needed(a), core))
425
+
426
+ def _do_binary(core):
427
+ """
428
+ Do dichotomic search similar to QuickXPlain.
429
+ """
430
+
431
+ wset = core[:]
432
+ filt_sz = len(wset) / 2.0
433
+ while filt_sz >= 1:
434
+ i = 0
435
+ while i < len(wset):
436
+ to_test = wset[:i] + wset[(i + int(filt_sz)):]
437
+ # actual binary hypotheses to test
438
+ self.calls += 1
439
+ if to_test and not self.reducer.solve(assumptions=to_test):
440
+ # assumps are not needed
441
+ wset = to_test
442
+ else:
443
+ # assumps are needed => check the next chunk
444
+ i += int(filt_sz)
445
+ # decreasing size of the set to filter
446
+ filt_sz /= 2.0
447
+ if filt_sz > len(wset) / 2.0:
448
+ # next size is too large => make it smaller
449
+ filt_sz = len(wset) / 2.0
450
+ return wset
451
+
452
+ if self.search == 'bin':
453
+ dual = _do_binary(core)
454
+ else: # by default, linear MUS extraction is used
455
+ dual = _do_linear(core)
456
+
457
+ return dual
458
+
459
+ def enumerate(self):
460
+ """
461
+ This is generator method iterating through primes and enumerating
462
+ them until the formula has no more primes, or a user decides to
463
+ stop the process (this is controlled from the outside).
464
+
465
+ :rtype: list(int)
466
+ """
467
+
468
+ done = False
469
+
470
+ while not done:
471
+ prime = self.compute()
472
+
473
+ if prime is not None:
474
+ yield prime
475
+ else:
476
+ done = True
477
+
478
+ def oracle_time(self):
479
+ """
480
+ This method computes and returns the total SAT solving time
481
+ involved, including the time spent by the hitting set enumerator
482
+ and the two SAT oracles.
483
+
484
+ :rtype: float
485
+ """
486
+
487
+ return self.hitman.oracle_time() + self.checker.time_accum() + self.reducer.time_accum()
488
+
489
+
490
+ #
491
+ #==============================================================================
492
+ def parse_options():
493
+ """
494
+ Parses command-line options:
495
+ """
496
+
497
+ try:
498
+ opts, args = getopt.getopt(sys.argv[1:], 'ade:himp:r:s:t:uvx',
499
+ ['adapt', 'dcalls', 'enum=', 'help',
500
+ 'implicants', 'minimize', 'puresat=',
501
+ 'reduce=', 'solver=', 'trim=', 'unsorted',
502
+ 'verbose', 'exhaust'])
503
+ except getopt.GetoptError as err:
504
+ sys.stderr.write(str(err).capitalize())
505
+ usage()
506
+ sys.exit(1)
507
+
508
+ to_enum = 1
509
+ mode = 1 # 1 = implicates, 0 = implicants
510
+ adapt = False
511
+ dcalls = False
512
+ exhaust = False
513
+ minz = False
514
+ search = 'lin'
515
+ solver = 'cd19'
516
+ puresat = False
517
+ unsorted = False
518
+ trim = 0
519
+ verbose = 1
520
+
521
+ for opt, arg in opts:
522
+ if opt in ('-a', '--adapt'):
523
+ adapt = True
524
+ elif opt in ('-d', '--dcalls'):
525
+ dcalls = True
526
+ elif opt in ('-e', '--enum'):
527
+ to_enum = str(arg)
528
+ if to_enum != 'all':
529
+ to_enum = int(to_enum)
530
+ elif opt in ('-h', '--help'):
531
+ usage()
532
+ sys.exit(0)
533
+ elif opt in ('-i', '--implicants'):
534
+ mode = 0
535
+ elif opt in ('-m', '--minimize'):
536
+ minz = True
537
+ elif opt in ('-p', '--puresat'):
538
+ puresat = str(arg)
539
+ elif opt in ('-r', '--reduce'):
540
+ search = str(arg)
541
+ assert search in ('lin', 'bin'), 'Wrong minimisation method: {0}'.format(search)
542
+ elif opt in ('-s', '--solver'):
543
+ solver = str(arg)
544
+ elif opt in ('-u', '--unsorted'):
545
+ unsorted = True
546
+ elif opt in ('-t', '--trim'):
547
+ trim = int(arg)
548
+ elif opt in ('-v', '--verbose'):
549
+ verbose += 1
550
+ elif opt in ('-x', '--exhaust'):
551
+ exhaust = True
552
+ else:
553
+ assert False, 'Unhandled option: {0} {1}'.format(opt, arg)
554
+
555
+ return to_enum, mode, adapt, dcalls, exhaust, minz, trim, \
556
+ search, solver, puresat, unsorted, verbose, args
557
+
558
+
559
+ #
560
+ #==============================================================================
561
+ def usage():
562
+ """
563
+ Prints usage message.
564
+ """
565
+
566
+ print('Usage:', os.path.basename(sys.argv[0]), '[options]')
567
+ print('Options:')
568
+ print(' -a, --adapt Try to adapt (simplify) input formula')
569
+ print(' -d, --dcalls Apply clause D calls (in unsorted enumeration only)')
570
+ print(' -e, --enum=<int> Enumerate this many primes')
571
+ print(' Available values: [1 .. INT_MAX], all (default = 1)')
572
+ print(' -h, --help Print this help message')
573
+ print(' -i, --implicants Target prime implicants instead of implicates')
574
+ print(' -m, --minimize Use a heuristic unsatisfiable core minimizer')
575
+ print(' -p, --puresat=<string> Use a pure SAT-based hitting set enumerator')
576
+ print(' Available values: cd15, cd19, lgl, mgh (default = mgh)')
577
+ print(' Requires: unsorted mode, i.e. \'-u\'')
578
+ print(' -r, --reduce Dual prime minimiser')
579
+ print(' Available values: lin, bin (default = lin)')
580
+ print(' -s, --solver SAT solver to use')
581
+ print(' Available values: cd, cd15, cd19, g3, g41, g42, lgl, mcb, mcm, mpl, m22, mc, mg3, mgh (default = cd19)')
582
+ print(' -t, --trim=<int> How many times to trim unsatisfiable cores')
583
+ print(' Available values: [0 .. INT_MAX] (default = 0)')
584
+ print(' -u, --unsorted Enumerate MUSes in an unsorted way using LBX')
585
+ print(' -v, --verbose Be verbose')
586
+ print(' -x, --exhaust Exhaust new unsatisfiable cores')
587
+
588
+ #
589
+ #==============================================================================
590
+ if __name__ == '__main__':
591
+ # parse command-line options
592
+ to_enum, mode, adapt, dcalls, exhaust, minz, trim, search, solver, \
593
+ puresat, unsorted, verbose, files = parse_options()
594
+
595
+ if files:
596
+ # read CNF from file
597
+ assert re.search(r'cnf(\.(gz|bz2|lzma|xz|zst))?$', files[0]), 'Unknown input file extension'
598
+ formula = CNF(from_file=files[0])
599
+
600
+ # creating an object of Primer
601
+ with Primer(formula, negated=None, solver=solver, implicates=mode,
602
+ adapt=adapt, dcalls=dcalls, exhaust=exhaust, minz=minz,
603
+ puresat=puresat, search=search, unsorted=unsorted,
604
+ trim=trim, verbose=verbose) as primer:
605
+
606
+ # iterating over the necessary number of primes
607
+ for i, prime in enumerate(primer.enumerate()):
608
+ # reporting the current solution
609
+ if verbose:
610
+ print('v {0} 0'.format(' '.join(['{0}{1}'.format('+' if v > 0 else '', v) for v in prime])))
611
+
612
+ # checking if we are done
613
+ if to_enum and i + 1 == to_enum:
614
+ break
615
+
616
+ # reporting the total oracle time
617
+ if verbose > 1:
618
+ print('c primes: {0}'.format(i + 1))
619
+ print('c oracle time: {0:.4f}'.format(primer.oracle_time()))
620
+ print('c oracle calls: {0}'.format(primer.calls))