python-sat 1.8.dev15__cp313-cp313-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.

Potentially problematic release.


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

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