python-sat 1.8.dev25__cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of python-sat might be problematic. Click here for more details.

Files changed (48) hide show
  1. pycard.cpython-314-x86_64-linux-gnu.so +0 -0
  2. pysat/__init__.py +24 -0
  3. pysat/_fileio.py +209 -0
  4. pysat/_utils.py +58 -0
  5. pysat/allies/__init__.py +0 -0
  6. pysat/allies/approxmc.py +385 -0
  7. pysat/allies/unigen.py +435 -0
  8. pysat/card.py +802 -0
  9. pysat/engines.py +1302 -0
  10. pysat/examples/__init__.py +0 -0
  11. pysat/examples/bbscan.py +663 -0
  12. pysat/examples/bica.py +691 -0
  13. pysat/examples/fm.py +527 -0
  14. pysat/examples/genhard.py +516 -0
  15. pysat/examples/hitman.py +653 -0
  16. pysat/examples/lbx.py +638 -0
  17. pysat/examples/lsu.py +496 -0
  18. pysat/examples/mcsls.py +610 -0
  19. pysat/examples/models.py +189 -0
  20. pysat/examples/musx.py +344 -0
  21. pysat/examples/optux.py +710 -0
  22. pysat/examples/primer.py +620 -0
  23. pysat/examples/rc2.py +1858 -0
  24. pysat/examples/usage.py +63 -0
  25. pysat/formula.py +5619 -0
  26. pysat/pb.py +463 -0
  27. pysat/process.py +363 -0
  28. pysat/solvers.py +7591 -0
  29. pysolvers.cpython-314-x86_64-linux-gnu.so +0 -0
  30. python_sat-1.8.dev25.data/scripts/approxmc.py +385 -0
  31. python_sat-1.8.dev25.data/scripts/bbscan.py +663 -0
  32. python_sat-1.8.dev25.data/scripts/bica.py +691 -0
  33. python_sat-1.8.dev25.data/scripts/fm.py +527 -0
  34. python_sat-1.8.dev25.data/scripts/genhard.py +516 -0
  35. python_sat-1.8.dev25.data/scripts/lbx.py +638 -0
  36. python_sat-1.8.dev25.data/scripts/lsu.py +496 -0
  37. python_sat-1.8.dev25.data/scripts/mcsls.py +610 -0
  38. python_sat-1.8.dev25.data/scripts/models.py +189 -0
  39. python_sat-1.8.dev25.data/scripts/musx.py +344 -0
  40. python_sat-1.8.dev25.data/scripts/optux.py +710 -0
  41. python_sat-1.8.dev25.data/scripts/primer.py +620 -0
  42. python_sat-1.8.dev25.data/scripts/rc2.py +1858 -0
  43. python_sat-1.8.dev25.data/scripts/unigen.py +435 -0
  44. python_sat-1.8.dev25.dist-info/METADATA +45 -0
  45. python_sat-1.8.dev25.dist-info/RECORD +48 -0
  46. python_sat-1.8.dev25.dist-info/WHEEL +6 -0
  47. python_sat-1.8.dev25.dist-info/licenses/LICENSE.txt +21 -0
  48. python_sat-1.8.dev25.dist-info/top_level.txt +3 -0
@@ -0,0 +1,610 @@
1
+ #!/usr/bin/env python
2
+ #-*- coding:utf-8 -*-
3
+ ##
4
+ ## mcsls.py
5
+ ##
6
+ ## Created on: Jan 9, 2017
7
+ ## Author: Alexey S. Ignatiev
8
+ ## E-mail: aignatiev@ciencias.ulisboa.pt
9
+ ##
10
+
11
+ """
12
+ ===============
13
+ List of classes
14
+ ===============
15
+
16
+ .. autosummary::
17
+ :nosignatures:
18
+
19
+ MCSls
20
+
21
+ ==================
22
+ Module description
23
+ ==================
24
+
25
+ This module implements a prototype of a BLS- and CLD-like algorithm for the
26
+ computation of a *minimal correction subset* (MCS) and/or MCS enumeration.
27
+ More concretely, the implementation follows the *basic linear search* (BLS)
28
+ for MCS exctraction augmented with *clause D* (CLD) oracle calls. As a
29
+ result, the algorithm is not an implementation of the BLS or CLD algorithms
30
+ as described in [1]_ but a mixture of both. Note that the corresponding
31
+ original low-level implementations of both can be found `online
32
+ <https://reason.di.fc.ul.pt/wiki/doku.php?id=mcsls>`_.
33
+
34
+ .. [1] Joao Marques-Silva, Federico Heras, Mikolas Janota, Alessandro
35
+ Previti, Anton Belov. *On Computing Minimal Correction Subsets*.
36
+ IJCAI 2013. pp. 615-622
37
+
38
+ The implementation can be used as an executable (the list of available
39
+ command-line options can be shown using ``mcsls.py -h``) in the following
40
+ way:
41
+
42
+ ::
43
+
44
+ $ xzcat formula.wcnf.xz
45
+ p wcnf 3 6 4
46
+ 1 1 0
47
+ 1 2 0
48
+ 1 3 0
49
+ 4 -1 -2 0
50
+ 4 -1 -3 0
51
+ 4 -2 -3 0
52
+
53
+ $ mcsls.py -d -e all -s glucose3 -vv formula.wcnf.xz
54
+ c MCS: 1 3 0
55
+ c cost: 2
56
+ c MCS: 2 3 0
57
+ c cost: 2
58
+ c MCS: 1 2 0
59
+ c cost: 2
60
+ c oracle time: 0.0002
61
+
62
+ Alternatively, the algorithm can be accessed and invoked through the
63
+ standard ``import`` interface of Python, e.g.
64
+
65
+ .. code-block:: python
66
+
67
+ >>> from pysat.examples.mcsls import MCSls
68
+ >>> from pysat.formula import WCNF
69
+ >>>
70
+ >>> wcnf = WCNF(from_file='formula.wcnf.xz')
71
+ >>>
72
+ >>> mcsls = MCSls(wcnf, use_cld=True, solver_name='g3')
73
+ >>> for mcs in mcsls.enumerate():
74
+ ... mcsls.block(mcs)
75
+ ... print(mcs)
76
+ [1, 3]
77
+ [2, 3]
78
+ [1, 2]
79
+
80
+ ==============
81
+ Module details
82
+ ==============
83
+ """
84
+
85
+ #
86
+ #==============================================================================
87
+ from __future__ import print_function
88
+ import collections
89
+ import getopt
90
+ from math import copysign
91
+ import os
92
+ from pysat.formula import CNFPlus, WCNFPlus
93
+ from pysat.process import Processor
94
+ from pysat.solvers import Solver, SolverNames
95
+ import re
96
+ import sys
97
+
98
+
99
+ #
100
+ #==============================================================================
101
+ class MCSls(object):
102
+ """
103
+ Algorithm BLS for computing MCSes, augmented with "clause :math:`D`"
104
+ calls. Given an unsatisfiable partial CNF formula, i.e. formula in the
105
+ :class:`.WCNF` format, this class can be used to compute a given number
106
+ of MCSes of the formula. The implementation follows the description of
107
+ the basic linear search (BLS) algorithm description in [1]_. It can use
108
+ any SAT solver available in PySAT. Additionally, the "clause :math:`D`"
109
+ heuristic can be used when enumerating MCSes.
110
+
111
+ The default SAT solver to use is ``m22`` (see :class:`.SolverNames`).
112
+ The "clause :math:`D`" heuristic is disabled by default, i.e.
113
+ ``use_cld`` is set to ``False``. Internal SAT solver's timer is also
114
+ disabled by default, i.e. ``use_timer`` is ``False``.
115
+
116
+ Additionally, the input formula can be preprocessed before running MCS
117
+ enumeration. This is controlled by the input parameter ``process``
118
+ whose integer value signifies the number of processing rounds to be
119
+ applied. The number of rounds is set to 0 by default.
120
+
121
+ :param formula: unsatisfiable partial CNF formula
122
+ :param use_cld: whether or not to use "clause :math:`D`"
123
+ :param solver_name: SAT oracle name
124
+ :param process: apply formula preprocessing this many times
125
+ :param use_timer: whether or not to use SAT solver's timer
126
+
127
+ :type formula: :class:`.WCNF`
128
+ :type use_cld: bool
129
+ :type solver_name: str
130
+ :type process: int
131
+ :type use_timer: bool
132
+ """
133
+
134
+ def __init__(self, formula, use_cld=False, solver_name='m22', process=0,
135
+ use_timer=False):
136
+ """
137
+ Constructor.
138
+ """
139
+
140
+ # dealing with preprocessing, if required
141
+ hard = formula.hard if process > 0 else []
142
+
143
+ # bootstrapping the solver with hard clauses
144
+ self.oracle = Solver(name=solver_name,
145
+ bootstrap_with=formula.hard if process == 0 else [],
146
+ use_timer=use_timer)
147
+ self.solver = solver_name
148
+
149
+ # adding native cardinality constraints (if any) as hard clauses
150
+ # this can be done only if the Minicard solver is in use
151
+ if isinstance(formula, WCNFPlus) and formula.atms:
152
+ # we are using CaDiCaL195 and it can use external linear engine
153
+ if solver_name in SolverNames.cadical195:
154
+ self.oracle.activate_atmost()
155
+
156
+ assert self.oracle.supports_atmost(), \
157
+ '{0} does not support native cardinality constraints. Make sure you use the right type of formula.'.format(solver_name)
158
+
159
+ for atm in formula.atms:
160
+ self.oracle.add_atmost(*atm)
161
+
162
+ self.topv = formula.nv # top variable id
163
+ self.sels = []
164
+ self.ucld = use_cld
165
+ self.smap = {}
166
+
167
+ # mappings between internal and external variables
168
+ VariableMap = collections.namedtuple('VariableMap', ['e2i', 'i2e'])
169
+ self.vmap = VariableMap(e2i={}, i2e={})
170
+
171
+ # at this point internal and external variables are the same
172
+ for v in range(1, formula.nv + 1):
173
+ self.vmap.e2i[v] = v
174
+ self.vmap.i2e[v] = v
175
+
176
+ for cl in formula.soft:
177
+ new_cl = cl[:]
178
+ if len(cl) > 1 or cl[0] < 0:
179
+ self.topv += 1
180
+ sel = self.topv
181
+
182
+ new_cl.append(-sel) # creating a new selector
183
+
184
+ if process == 0:
185
+ self.oracle.add_clause(new_cl)
186
+ else:
187
+ # adding to formula's hard clauses
188
+ # if any preprocessing is required
189
+ hard.append(new_cl)
190
+ else:
191
+ sel = cl[0]
192
+
193
+ self.sels.append(sel)
194
+ self.smap[sel] = len(self.sels)
195
+
196
+ # finally, applying formula processing, if any
197
+ if process:
198
+ # the processor is immediately destroyed,
199
+ # as we do not need to restore the models
200
+ with Processor(bootstrap_with=hard) as processor:
201
+ proc = processor.process(rounds=process, freeze=self.sels)
202
+ self.oracle.append_formula(proc)
203
+
204
+ def __del__(self):
205
+ """
206
+ Destructor.
207
+ """
208
+
209
+ self.delete()
210
+
211
+ def __enter__(self):
212
+ """
213
+ 'with' constructor.
214
+ """
215
+
216
+ return self
217
+
218
+ def __exit__(self, exc_type, exc_value, traceback):
219
+ """
220
+ 'with' destructor.
221
+ """
222
+
223
+ self.delete()
224
+
225
+ def delete(self):
226
+ """
227
+ Explicit destructor of the internal SAT oracle.
228
+ """
229
+
230
+ if self.oracle:
231
+ self.oracle.delete()
232
+ self.oracle = None
233
+
234
+ def add_clause(self, clause, soft=False):
235
+ """
236
+ The method for adding a new hard of soft clause to the problem
237
+ formula. Although the input formula is to be specified as an
238
+ argument of the constructor of :class:`MCSls`, adding clauses may
239
+ be helpful when *enumerating* MCSes of the formula. This way, the
240
+ clauses are added incrementally, i.e. *on the fly*.
241
+
242
+ The clause to add can be any iterable over integer literals. The
243
+ additional Boolean parameter ``soft`` can be set to ``True``
244
+ meaning the the clause being added is soft (note that parameter
245
+ ``soft`` is set to ``False`` by default).
246
+
247
+ Also note that besides pure clauses, the method can also expect
248
+ native cardinality constraints represented as a pair ``(lits,
249
+ bound)``. Only hard cardinality constraints can be added.
250
+
251
+ :param clause: a clause to add
252
+ :param soft: whether or not the clause is soft
253
+
254
+ :type clause: iterable(int)
255
+ :type soft: bool
256
+ """
257
+
258
+ # first, map external literals to internal literals
259
+ # introduce new variables if necessary
260
+ cl = list(map(lambda l: self._map_extlit(l), clause if not len(clause) == 2 or not type(clause[0]) in (list, tuple, set) else clause[0]))
261
+
262
+ if not soft:
263
+ if not len(clause) == 2 or not type(clause[0]) in (list, tuple, set):
264
+ # the clause is hard, and so we simply add it to the SAT oracle
265
+ self.oracle.add_clause(cl)
266
+ else:
267
+ # this should be a native cardinality constraint,
268
+ # which can be used only together with Minicard
269
+ assert self.oracle.supports_atmost(), \
270
+ '{0} does not support native cardinality constraints. Make sure you use the right type of formula.'.format(self.solver)
271
+
272
+ self.oracle.add_atmost(cl, clause[1])
273
+ else:
274
+ # soft clauses should be augmented with a selector
275
+ sel = cl[0]
276
+ if len(cl) > 1 or cl[0] < 0:
277
+ self.topv += 1
278
+ sel = self.topv
279
+
280
+ self.oracle.add_clause(cl + [-sel])
281
+
282
+ self.sels.append(sel)
283
+ self.smap[sel] = len(self.sels)
284
+
285
+ def compute(self, enable=[]):
286
+ """
287
+ Compute and return one solution. This method checks whether the
288
+ hard part of the formula is satisfiable, i.e. an MCS can be
289
+ extracted. If the formula is satisfiable, the model computed by the
290
+ SAT call is used as an *over-approximation* of the MCS in the
291
+ method :func:`_compute` invoked here, which implements the BLS
292
+
293
+ An MCS is reported as a list of integers, each representing a soft
294
+ clause index (the smallest index is ``1``).
295
+
296
+ An optional input parameter is ``enable``, which represents a
297
+ sequence (normally a list) of soft clause indices that a user
298
+ would prefer to enable/satisfy. Note that this may result in an
299
+ unsatisfiable oracle call, in which case ``None`` will be reported
300
+ as solution. Also, the smallest clause index is assumed to be
301
+ ``1``.
302
+
303
+ :param enable: a sequence of clause ids to enable
304
+ :type enable: iterable(int)
305
+
306
+ :rtype: list(int)
307
+ """
308
+
309
+ self.setd = []
310
+ self.solution = None
311
+ self.bb_assumps = [] # backbone assumptions
312
+ self.ss_assumps = [] # satisfied soft clause assumptions
313
+
314
+ if self.oracle.solve(assumptions=[self.sels[cl_id - 1] for cl_id in enable]):
315
+ # hard part is satisfiable => there is a solution
316
+ self._overapprox()
317
+ self._compute()
318
+
319
+ self.solution = [self.smap[-l] for l in self.bb_assumps]
320
+
321
+ return self.solution
322
+
323
+ def enumerate(self):
324
+ """
325
+ This method iterates through MCSes enumerating them until the
326
+ formula has no more MCSes. The method iteratively invokes
327
+ :func:`compute`. Note that the method does not block the MCSes
328
+ computed - this should be explicitly done by a user.
329
+ """
330
+
331
+ done = False
332
+ while not done:
333
+ mcs = self.compute()
334
+
335
+ if mcs != None:
336
+ yield mcs
337
+ else:
338
+ done = True
339
+
340
+ def block(self, mcs):
341
+ """
342
+ Block a (previously computed) MCS. The MCS should be given as an
343
+ iterable of integers. Note that this method is not automatically
344
+ invoked from :func:`enumerate` because a user may want to block
345
+ some of the MCSes conditionally depending on the needs. For
346
+ example, one may want to compute disjoint MCSes only in which case
347
+ this standard blocking is not appropriate.
348
+
349
+ :param mcs: an MCS to block
350
+ :type mcs: iterable(int)
351
+ """
352
+
353
+ self.oracle.add_clause([self.sels[cl_id - 1] for cl_id in mcs])
354
+
355
+ def _overapprox(self):
356
+ """
357
+ The method extracts a model corresponding to an over-approximation
358
+ of an MCS, i.e. it is the model of the hard part of the formula
359
+ (the corresponding oracle call is made in :func:`compute`).
360
+
361
+ Here, the set of selectors is divided into two parts:
362
+ ``self.ss_assumps``, which is an under-approximation of an MSS
363
+ (maximal satisfiable subset) and ``self.setd``, which is an
364
+ over-approximation of the target MCS. Both will be further refined
365
+ in :func:`_compute`.
366
+ """
367
+
368
+ model = self.oracle.get_model()
369
+
370
+ for sel in self.sels:
371
+ if len(model) < sel or model[sel - 1] > 0:
372
+ # soft clauses contain positive literals
373
+ # so if var is true then the clause is satisfied
374
+ self.ss_assumps.append(sel)
375
+ else:
376
+ self.setd.append(sel)
377
+
378
+ def _compute(self):
379
+ """
380
+ The main method of the class, which computes an MCS given its
381
+ over-approximation. The over-approximation is defined by a model
382
+ for the hard part of the formula obtained in :func:`_overapprox`
383
+ (the corresponding oracle is made in :func:`compute`).
384
+
385
+ The method is essentially a simple loop going over all literals
386
+ unsatisfied by the previous model, i.e. the literals of
387
+ ``self.setd`` and checking which literals can be satisfied. This
388
+ process can be seen a refinement of the over-approximation of the
389
+ MCS. The algorithm follows the pseudo-code of the BLS algorithm
390
+ presented in [1]_.
391
+
392
+ Additionally, if :class:`MCSls` was constructed with the
393
+ requirement to make "clause :math:`D`" calls, the method calls
394
+ :func:`do_cld_check` at every iteration of the loop using the
395
+ literals of ``self.setd`` not yet checked, as the contents of
396
+ "clause :math:`D`".
397
+ """
398
+
399
+ # unless clause D checks are used, test one literal at a time
400
+ # and add it either to satisfied of backbone assumptions
401
+ i = 0
402
+ while i < len(self.setd):
403
+ if self.ucld:
404
+ self.do_cld_check(self.setd[i:])
405
+ i = 0
406
+
407
+ if self.setd:
408
+ # if may be empty after the clause D check
409
+
410
+ self.ss_assumps.append(self.setd[i])
411
+ if not self.oracle.solve(assumptions=self.ss_assumps + self.bb_assumps):
412
+ self.ss_assumps.pop()
413
+ self.bb_assumps.append(-self.setd[i])
414
+
415
+ i += 1
416
+
417
+ def do_cld_check(self, cld):
418
+ """
419
+ Do the "clause :math:`D`" check. This method receives a list of
420
+ literals, which serves a "clause :math:`D`" [1]_, and checks
421
+ whether the formula conjoined with :math:`D` is satisfiable.
422
+
423
+ If clause :math:`D` cannot be satisfied together with the formula,
424
+ then negations of all of its literals are backbones of the formula
425
+ and the MCSls algorithm can stop. Otherwise, the literals satisfied
426
+ by the new model refine the MCS further.
427
+
428
+ Every time the method is called, a new fresh selector variable
429
+ :math:`s` is introduced, which augments the current clause
430
+ :math:`D`. The SAT oracle then checks if clause :math:`(D \\vee
431
+ \\neg{s})` can be satisfied together with the internal formula.
432
+ The :math:`D` clause is then disabled by adding a hard clause
433
+ :math:`(\\neg{s})`.
434
+
435
+ :param cld: clause :math:`D` to check
436
+ :type cld: list(int)
437
+ """
438
+
439
+ # adding a selector literal to clause D
440
+ # selector literals for clauses D currently
441
+ # cannot be reused, but this may change later
442
+ self.topv += 1
443
+ sel = self.topv
444
+ cld.append(-sel)
445
+
446
+ # adding clause D
447
+ self.oracle.add_clause(cld)
448
+ self.ss_assumps.append(sel)
449
+
450
+ self.setd = []
451
+ self.oracle.solve(assumptions=self.ss_assumps + self.bb_assumps)
452
+
453
+ self.ss_assumps.pop() # removing clause D assumption
454
+ if self.oracle.get_status() == True:
455
+ model = self.oracle.get_model()
456
+
457
+ for l in cld[:-1]:
458
+ # filtering all satisfied literals
459
+ if model[abs(l) - 1] > 0:
460
+ self.ss_assumps.append(l)
461
+ else:
462
+ self.setd.append(l)
463
+ else:
464
+ # clause D is unsatisfiable => all literals are backbones
465
+ self.bb_assumps.extend([-l for l in cld[:-1]])
466
+
467
+ # deactivating clause D
468
+ self.oracle.add_clause([-sel])
469
+
470
+ def _map_extlit(self, l):
471
+ """
472
+ Map an external variable to an internal one if necessary.
473
+
474
+ This method is used when new clauses are added to the formula
475
+ incrementally, which may result in introducing new variables
476
+ clashing with the previously used *clause selectors*. The method
477
+ makes sure no clash occurs, i.e. it maps the original variables
478
+ used in the new problem clauses to the newly introduced auxiliary
479
+ variables (see :func:`add_clause`).
480
+
481
+ Given an integer literal, a fresh literal is returned. The returned
482
+ integer has the same sign as the input literal.
483
+
484
+ :param l: literal to map
485
+ :type l: int
486
+
487
+ :rtype: int
488
+ """
489
+
490
+ v = abs(l)
491
+
492
+ if v in self.vmap.e2i:
493
+ return int(copysign(self.vmap.e2i[v], l))
494
+ else:
495
+ self.topv += 1
496
+
497
+ self.vmap.e2i[v] = self.topv
498
+ self.vmap.i2e[self.topv] = v
499
+
500
+ return int(copysign(self.topv, l))
501
+
502
+ def oracle_time(self):
503
+ """
504
+ Report the total SAT solving time.
505
+ """
506
+
507
+ return self.oracle.time_accum()
508
+
509
+
510
+ #
511
+ #==============================================================================
512
+ def parse_options():
513
+ """
514
+ Parses command-line options.
515
+ """
516
+
517
+ try:
518
+ opts, args = getopt.getopt(sys.argv[1:],
519
+ 'de:hp:s:v',
520
+ ['dcalls',
521
+ 'enum=',
522
+ 'help',
523
+ 'process=',
524
+ 'solver=',
525
+ 'verbose'])
526
+ except getopt.GetoptError as err:
527
+ sys.stderr.write(str(err).capitalize() + '\n')
528
+ usage()
529
+ sys.exit(1)
530
+
531
+ dcalls = False
532
+ to_enum = 1
533
+ process = 0
534
+ solver = 'm22'
535
+ verbose = 0
536
+
537
+ for opt, arg in opts:
538
+ if opt in ('-d', '--dcalls'):
539
+ dcalls = True
540
+ elif opt in ('-e', '--enum'):
541
+ to_enum = str(arg)
542
+ if to_enum != 'all':
543
+ to_enum = int(to_enum)
544
+ elif opt in ('-h', '--help'):
545
+ usage()
546
+ sys.exit(0)
547
+ elif opt in ('-p', '--process'):
548
+ process = int(arg)
549
+ elif opt in ('-s', '--solver'):
550
+ solver = str(arg)
551
+ elif opt in ('-v', '--verbose'):
552
+ verbose += 1
553
+ else:
554
+ assert False, 'Unhandled option: {0} {1}'.format(opt, arg)
555
+
556
+ return dcalls, to_enum, solver, process, verbose, args
557
+
558
+
559
+ #
560
+ #==============================================================================
561
+ def usage():
562
+ """
563
+ Prints help message.
564
+ """
565
+
566
+ print('Usage:', os.path.basename(sys.argv[0]), '[options] file')
567
+ print('Options:')
568
+ print(' -d, --dcalls Apply clause D calls')
569
+ print(' -e, --enum=<string> How many solutions to compute')
570
+ print(' Available values: [1 .. all] (default: 1)')
571
+ print(' -h, --help')
572
+ print(' -p, --process=<int> Number of processing rounds')
573
+ print(' Available values: [0 .. INT_MAX] (default = 0)')
574
+ print(' -s, --solver SAT solver to use')
575
+ print(' Available values: cd15, cd19, g3, g4, lgl, mcb, mcm, mpl, m22, mc, mgh (default = m22)')
576
+ print(' -v, --verbose Be verbose')
577
+
578
+
579
+ #
580
+ #==============================================================================
581
+ if __name__ == '__main__':
582
+ dcalls, to_enum, solver, process, verbose, files = parse_options()
583
+
584
+ if type(to_enum) == str:
585
+ to_enum = 0
586
+
587
+ if files:
588
+ # reading standard CNF, WCNF, or (W)CNF+
589
+ assert re.search(r'cnf[p|+]?(\.(gz|bz2|lzma|xz|zst))?$', files[0]), 'Unknown input file extension'
590
+ if re.search(r'\.wcnf[p|+]?(\.(gz|bz2|lzma|xz|zst))?$', files[0]):
591
+ formula = WCNFPlus(from_file=files[0])
592
+ else: # expecting '*.cnf[,p,+].*'
593
+ formula = CNFPlus(from_file=files[0]).weighted()
594
+
595
+ with MCSls(formula, use_cld=dcalls, solver_name=solver,
596
+ process=process, use_timer=True) as mcsls:
597
+ for i, mcs in enumerate(mcsls.enumerate()):
598
+ if verbose:
599
+ print('c MCS:', ' '.join([str(cl_id) for cl_id in mcs]), '0')
600
+
601
+ if verbose > 1:
602
+ cost = sum([formula.wght[cl_id - 1] for cl_id in mcs])
603
+ print('c cost:', cost)
604
+
605
+ if to_enum and i + 1 == to_enum:
606
+ break
607
+
608
+ mcsls.block(mcs)
609
+
610
+ print('c oracle time: {0:.4f}'.format(mcsls.oracle_time()))