python-sat 1.9.dev19__tar.gz → 1.9.dev21__tar.gz
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.
- {python_sat-1.9.dev19/python_sat.egg-info → python_sat-1.9.dev21}/PKG-INFO +1 -1
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/examples/lbx.py +4 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/examples/mcsls.py +4 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/examples/rc2.py +46 -15
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/pysat/__init__.py +1 -1
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/pysat/process.py +78 -21
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/pysat/solvers.py +104 -16
- {python_sat-1.9.dev19 → python_sat-1.9.dev21/python_sat.egg-info}/PKG-INFO +1 -1
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/python_sat.egg-info/SOURCES.txt +1 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/patches/cadical153.patch +11 -11
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/patches/cadical195.patch +11 -11
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/patches/cadical300.patch +349 -30
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/pysolvers.cc +157 -19
- python_sat-1.9.dev21/tests/test_flip_bits.py +85 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/LICENSE.txt +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/MANIFEST.in +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/README.rst +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/allies/__init__.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/allies/approxmc.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/allies/unigen.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/cardenc/bitwise.hh +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/cardenc/card.hh +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/cardenc/clset.hh +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/cardenc/common.hh +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/cardenc/iseq.hh +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/cardenc/itot.hh +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/cardenc/ladder.hh +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/cardenc/mto.hh +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/cardenc/pairwise.hh +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/cardenc/ptypes.hh +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/cardenc/pycard.cc +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/cardenc/seqcounter.hh +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/cardenc/sortcard.hh +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/cardenc/utils.hh +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/examples/__init__.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/examples/bbscan.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/examples/bica.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/examples/fm.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/examples/genhard.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/examples/hitman.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/examples/lsu.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/examples/models.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/examples/musx.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/examples/optux.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/examples/primer.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/examples/usage.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/formula/pf_parse.cc +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/formula/pf_plus.cc +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/formula/pf_plus.hh +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/formula/pf_py.hh +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/formula/pf_scan.hh +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/formula/pf_weight.cc +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/formula/pf_weight.hh +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/formula/pyformula.cc +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/formula/pyformula.hh +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/pysat/_fileio.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/pysat/_utils.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/pysat/card.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/pysat/engines.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/pysat/formula.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/pysat/integer.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/pysat/pb.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/python_sat.egg-info/dependency_links.txt +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/python_sat.egg-info/requires.txt +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/python_sat.egg-info/top_level.txt +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/requirements.txt +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/setup.cfg +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/setup.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/cadical103.tar.gz +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/cadical153.tar.gz +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/cadical195.tar.gz +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/cadical300.tar.gz +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/ergo.tar.gz +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/glucose30.tar.gz +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/glucose41.tar.gz +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/glucose421.tar.gz +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/lingeling.tar.gz +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/maplechrono.zip +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/maplecm.zip +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/maplesat.zip +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/mergesat3.tar.gz +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/minicard.tar.gz +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/minisat22.tar.gz +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/minisatgh.zip +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/patches/cadical103.patch +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/patches/ergo.patch +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/patches/glucose30.patch +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/patches/glucose41.patch +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/patches/glucose421.patch +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/patches/gluecard30.patch +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/patches/gluecard41.patch +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/patches/kissat404.patch +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/patches/lingeling.patch +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/patches/maplechrono.patch +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/patches/maplecm.patch +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/patches/maplesat.patch +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/patches/mergesat3.patch +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/patches/minicard.patch +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/patches/minisat22.patch +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/patches/minisatep.patch +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/patches/minisatgh.patch +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/solvers/prepare.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_accum_stats.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_atmost.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_atmost1.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_atmostk.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_boolengine.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_clausification.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_cnf.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_empty_clause.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_empty_extclause.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_encode_pb_conditional.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_equals1.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_formula_parsing.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_formula_unique.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_hitman.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_idpool.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_integer.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_iseqcounter.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_lsu.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_oom.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_pb.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_process.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_proof.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_propagate.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_unique_model.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_unique_mus.py +0 -0
- {python_sat-1.9.dev19 → python_sat-1.9.dev21}/tests/test_warmstart.py +0 -0
|
@@ -247,6 +247,10 @@ class LBX(object):
|
|
|
247
247
|
native cardinality constraints represented as a pair ``(lits,
|
|
248
248
|
bound)``. Only hard cardinality constraints can be added.
|
|
249
249
|
|
|
250
|
+
Finally, note that clauses cannot be safely added if formula
|
|
251
|
+
processing is used (see parameter ``process``) as they may
|
|
252
|
+
refer to variables eliminated by the processor.
|
|
253
|
+
|
|
250
254
|
:param clause: a clause to add
|
|
251
255
|
:param soft: whether or not the clause is soft
|
|
252
256
|
|
|
@@ -248,6 +248,10 @@ class MCSls(object):
|
|
|
248
248
|
native cardinality constraints represented as a pair ``(lits,
|
|
249
249
|
bound)``. Only hard cardinality constraints can be added.
|
|
250
250
|
|
|
251
|
+
Finally, note that clauses cannot be safely added if formula
|
|
252
|
+
processing is used (see parameter ``process``) as they may
|
|
253
|
+
refer to variables eliminated by the processor.
|
|
254
|
+
|
|
251
255
|
:param clause: a clause to add
|
|
252
256
|
:param soft: whether or not the clause is soft
|
|
253
257
|
|
|
@@ -362,6 +362,9 @@ class RC2(object):
|
|
|
362
362
|
self.sels_set = set(self.sels)
|
|
363
363
|
self.sall = self.sels[:]
|
|
364
364
|
|
|
365
|
+
# original weights (as opposed to those after splitting)
|
|
366
|
+
self.owgt = dict(self.wght)
|
|
367
|
+
|
|
365
368
|
# we may end up having zero-weighed soft clauses
|
|
366
369
|
self.garbage = set([l for l in self.sels if self.wght[l] == 0])
|
|
367
370
|
if self.garbage:
|
|
@@ -403,6 +406,10 @@ class RC2(object):
|
|
|
403
406
|
native cardinality constraints represented as a pair ``(lits,
|
|
404
407
|
bound)``. Only hard cardinality constraints can be added.
|
|
405
408
|
|
|
409
|
+
Finally, note that clauses cannot be safely added if formula
|
|
410
|
+
processing is used (see parameter ``process``) as they may
|
|
411
|
+
refer to variables eliminated by the processor.
|
|
412
|
+
|
|
406
413
|
:param clause: a clause to add
|
|
407
414
|
:param weight: weight of the clause (if any)
|
|
408
415
|
|
|
@@ -475,6 +482,7 @@ class RC2(object):
|
|
|
475
482
|
# selector is not new; increment its weight
|
|
476
483
|
self.wght[selv] += weight
|
|
477
484
|
|
|
485
|
+
self.owgt[selv] = self.owgt.get(selv, 0) + weight
|
|
478
486
|
self.sall.append(selv)
|
|
479
487
|
self.sels_set.add(selv)
|
|
480
488
|
|
|
@@ -560,15 +568,15 @@ class RC2(object):
|
|
|
560
568
|
# so let's transform the None model returned to []
|
|
561
569
|
self.model = []
|
|
562
570
|
|
|
571
|
+
# if formula processing was used, we should restore the model
|
|
572
|
+
# for the original formula (before selectors are filtered out)
|
|
573
|
+
if self.processor:
|
|
574
|
+
self.model = self.processor.restore(self.model)
|
|
575
|
+
|
|
563
576
|
self.model = filter(lambda l: abs(l) in self.vmap.i2e, self.model)
|
|
564
577
|
self.model = map(lambda l: int(copysign(self.vmap.i2e[abs(l)], l)), self.model)
|
|
565
578
|
self.model = sorted(self.model, key=lambda l: abs(l))
|
|
566
579
|
|
|
567
|
-
# if formula processing was used, we should
|
|
568
|
-
# restore the model for the original formula
|
|
569
|
-
if self.processor:
|
|
570
|
-
self.model = self.processor.restore(self.model)
|
|
571
|
-
|
|
572
580
|
return self.model
|
|
573
581
|
|
|
574
582
|
def enumerate(self, block=0, expect_interrupt=False):
|
|
@@ -583,7 +591,8 @@ class RC2(object):
|
|
|
583
591
|
(MSSes) or minimal correction subsets (MCSes). To block MSSes, one
|
|
584
592
|
should set the ``block`` parameter to ``1``. To block MCSes, set
|
|
585
593
|
it to ``-1``. By the default (for blocking MaxSAT models),
|
|
586
|
-
``block`` is set to ``0``.
|
|
594
|
+
``block`` is set to ``0``. Note that if formula processing is
|
|
595
|
+
used (see parameter ``process``), only MCSes can be blocked.
|
|
587
596
|
|
|
588
597
|
This MaxSAT enumeration call can be asynchronously interrupted, in
|
|
589
598
|
which case the value of ``expect_interrupt`` must be set to
|
|
@@ -621,6 +630,9 @@ class RC2(object):
|
|
|
621
630
|
>>> rc2.delete()
|
|
622
631
|
"""
|
|
623
632
|
|
|
633
|
+
assert not self.processor or block == -1, \
|
|
634
|
+
'Only MCSes can be blocked if formula processing is used'
|
|
635
|
+
|
|
624
636
|
done = False
|
|
625
637
|
while not done:
|
|
626
638
|
model = self.compute(expect_interrupt=expect_interrupt)
|
|
@@ -1471,6 +1483,9 @@ class RC2Stratified(RC2, object):
|
|
|
1471
1483
|
# do clause hardening
|
|
1472
1484
|
self.hard = nohard == False
|
|
1473
1485
|
|
|
1486
|
+
# upper bound on the cost (trivial at first)
|
|
1487
|
+
self.ubnd = sum(self.owgt.values())
|
|
1488
|
+
|
|
1474
1489
|
# backing up selectors
|
|
1475
1490
|
self.bckp, self.bckp_set = self.sels, self.sels_set
|
|
1476
1491
|
self.sels = []
|
|
@@ -1571,15 +1586,15 @@ class RC2Stratified(RC2, object):
|
|
|
1571
1586
|
# so let's transform the None model returned to []
|
|
1572
1587
|
self.model = []
|
|
1573
1588
|
|
|
1589
|
+
# if formula processing was used, we should restore the model
|
|
1590
|
+
# for the original formula (before selectors are filtered out)
|
|
1591
|
+
if self.processor:
|
|
1592
|
+
self.model = self.processor.restore(self.model)
|
|
1593
|
+
|
|
1574
1594
|
self.model = filter(lambda l: abs(l) in self.vmap.i2e, self.model)
|
|
1575
1595
|
self.model = map(lambda l: int(copysign(self.vmap.i2e[abs(l)], l)), self.model)
|
|
1576
1596
|
self.model = sorted(self.model, key=lambda l: abs(l))
|
|
1577
1597
|
|
|
1578
|
-
# if formula processing was used, we should
|
|
1579
|
-
# restore the model for the original formula
|
|
1580
|
-
if self.processor:
|
|
1581
|
-
self.model = self.processor.restore(self.model)
|
|
1582
|
-
|
|
1583
1598
|
return self.model
|
|
1584
1599
|
|
|
1585
1600
|
def next_level(self):
|
|
@@ -1648,14 +1663,17 @@ class RC2Stratified(RC2, object):
|
|
|
1648
1663
|
to optimization levels up to the newly computed level. It
|
|
1649
1664
|
also reactivates previously deactivated clauses (see
|
|
1650
1665
|
:func:`process_sels` and :func:`process_sums` for
|
|
1651
|
-
details).
|
|
1666
|
+
details). Clauses whose weight exceeds the gap between
|
|
1667
|
+
the upper and lower bounds are hardened instead.
|
|
1652
1668
|
"""
|
|
1653
1669
|
|
|
1654
1670
|
end = min(self.levl + 1, len(self.blop))
|
|
1655
1671
|
|
|
1656
1672
|
for l in range(beg, end):
|
|
1657
1673
|
for sel in self.wstr[self.blop[l]]:
|
|
1658
|
-
if
|
|
1674
|
+
if self.hard and self.blop[l] > self.ubnd - self.cost:
|
|
1675
|
+
self.oracle.add_clause([sel])
|
|
1676
|
+
elif sel in self.bckp_set:
|
|
1659
1677
|
self.sels.append(sel)
|
|
1660
1678
|
else:
|
|
1661
1679
|
self.sums.append(sel)
|
|
@@ -1670,7 +1688,8 @@ class RC2Stratified(RC2, object):
|
|
|
1670
1688
|
This method does postprocessing of the current
|
|
1671
1689
|
optimization level after it is solved. This includes
|
|
1672
1690
|
*hardening* some of the soft clauses (depending on their
|
|
1673
|
-
remaining weights) and also garbage collection.
|
|
1691
|
+
remaining weights) and also garbage collection. The
|
|
1692
|
+
level's model is used to tighten the upper bound.
|
|
1674
1693
|
"""
|
|
1675
1694
|
|
|
1676
1695
|
# assumptions to remove
|
|
@@ -1679,9 +1698,15 @@ class RC2Stratified(RC2, object):
|
|
|
1679
1698
|
# sum of weights of the remaining levels
|
|
1680
1699
|
sumw = sum([w * len(self.wstr[w]) for w in self.blop[(self.levl + 1):]])
|
|
1681
1700
|
|
|
1701
|
+
# upper bound given by the current model;
|
|
1702
|
+
# selectors unknown to the oracle are deemed to be falsified
|
|
1703
|
+
model = self.oracle.get_model()
|
|
1704
|
+
cost = sum([w for s, w in six.iteritems(self.owgt) if abs(s) > len(model) or model[abs(s) - 1] != s])
|
|
1705
|
+
self.ubnd = min(self.ubnd, cost)
|
|
1706
|
+
|
|
1682
1707
|
# trying to harden selectors and sums
|
|
1683
1708
|
for s in self.sels + self.sums:
|
|
1684
|
-
if self.wght[s] > sumw:
|
|
1709
|
+
if self.wght[s] > min(sumw, self.ubnd - self.cost):
|
|
1685
1710
|
self.oracle.add_clause([s])
|
|
1686
1711
|
self.garbage.add(s)
|
|
1687
1712
|
|
|
@@ -1983,6 +2008,12 @@ if __name__ == '__main__':
|
|
|
1983
2008
|
else:
|
|
1984
2009
|
MXS = RC2
|
|
1985
2010
|
|
|
2011
|
+
if process and to_enum != 1 and block != -1:
|
|
2012
|
+
# no formula processing in case we enumerate multiple models or
|
|
2013
|
+
# MSSes, as blocking them refers to variables it may eliminate
|
|
2014
|
+
print('c formula processing is disabled for model enumeration')
|
|
2015
|
+
process = 0
|
|
2016
|
+
|
|
1986
2017
|
# starting the solver
|
|
1987
2018
|
with MXS(formula, solver=solver, adapt=adapt, exhaust=exhaust,
|
|
1988
2019
|
incr=incr, minz=minz, process=process, trim=trim,
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
==================
|
|
24
24
|
|
|
25
25
|
This module provides access to the preprocessor functionality of `CaDiCaL
|
|
26
|
-
|
|
26
|
+
<https://github.com/arminbiere/cadical>`__, version 1.5.3 by default
|
|
27
|
+
(versions 1.9.5 and 3.0.0 can be selected instead). It can be used to
|
|
27
28
|
process [1]_ (also see references therein) a given CNF formula and output
|
|
28
29
|
a another formula, which is guaranteed to be *equisatisfiable* with the
|
|
29
30
|
original formula. The processor can be invoked for a user-provided number
|
|
@@ -85,20 +86,30 @@
|
|
|
85
86
|
#
|
|
86
87
|
#==============================================================================
|
|
87
88
|
from pysat.formula import CNF
|
|
88
|
-
from pysat.solvers import Cadical153
|
|
89
|
+
from pysat.solvers import Cadical153, Cadical195, Cadical300, NoSuchSolverError, SolverNames
|
|
89
90
|
|
|
90
91
|
|
|
91
92
|
#
|
|
92
93
|
#==============================================================================
|
|
93
94
|
class Processor(object):
|
|
94
95
|
"""
|
|
95
|
-
This class provides interface to CaDiCaL's preprocessor. The
|
|
96
|
-
|
|
97
|
-
:class:`.CNF` formula or a list (or iterable) of clauses
|
|
96
|
+
This class provides interface to CaDiCaL's preprocessor. The input
|
|
97
|
+
parameters are ``bootstrap_with``, which is expected to be a
|
|
98
|
+
:class:`.CNF` formula or a list (or iterable) of clauses, and
|
|
99
|
+
``engine``, which is the name of a CaDiCaL version to use, i.e. one of
|
|
100
|
+
the names of :class:`.Cadical153` (default), :class:`.Cadical195`, and
|
|
101
|
+
:class:`.Cadical300`. Note that preprocessing in CaDiCaL 1.9.5 should
|
|
102
|
+
not differ from that of CaDiCaL 1.5.3, as the two versions apply the
|
|
103
|
+
same techniques. In contrast, CaDiCaL 3.0.0 additionally applies
|
|
104
|
+
congruence closure, SAT sweeping, and binary clause backbone
|
|
105
|
+
computation.
|
|
98
106
|
|
|
99
107
|
:param bootstrap_with: a list of clauses for processor initialization.
|
|
100
108
|
:type bootstrap_with: :class:`.CNF` or iterable(iterable(int))
|
|
101
109
|
|
|
110
|
+
:param engine: name of the CaDiCaL version to use
|
|
111
|
+
:type engine: str
|
|
112
|
+
|
|
102
113
|
Once created and used, a processor must be deleted with the
|
|
103
114
|
:meth:`delete` method. Alternatively, if created using the ``with``
|
|
104
115
|
statement, deletion is done automatically when the end of the ``with``
|
|
@@ -119,7 +130,7 @@ class Processor(object):
|
|
|
119
130
|
>>> from pysat.process import Processor
|
|
120
131
|
>>> from pysat.solvers import Solver
|
|
121
132
|
>>>
|
|
122
|
-
>>> processor = Processor(bootstrap_with=[[-1, 2], [1, -2]])
|
|
133
|
+
>>> processor = Processor(bootstrap_with=[[-1, 2], [1, -2]], engine='cd195')
|
|
123
134
|
>>> processor.append_formula([[-2, 3], [1]])
|
|
124
135
|
>>> processor.add_clause([-3, 4])
|
|
125
136
|
>>>
|
|
@@ -140,13 +151,23 @@ class Processor(object):
|
|
|
140
151
|
>>> processor.delete()
|
|
141
152
|
"""
|
|
142
153
|
|
|
143
|
-
def __init__(self, bootstrap_with=None):
|
|
154
|
+
def __init__(self, bootstrap_with=None, engine='cd15'):
|
|
144
155
|
"""
|
|
145
156
|
Basic constructor.
|
|
146
157
|
"""
|
|
147
158
|
|
|
159
|
+
self.cadical = None
|
|
160
|
+
|
|
148
161
|
# immediately creating a CaDiCaL object
|
|
149
|
-
|
|
162
|
+
engine_ = engine.lower()
|
|
163
|
+
if engine_ in SolverNames.cadical153:
|
|
164
|
+
self.cadical = Cadical153()
|
|
165
|
+
elif engine_ in SolverNames.cadical195:
|
|
166
|
+
self.cadical = Cadical195()
|
|
167
|
+
elif engine_ in SolverNames.cadical300:
|
|
168
|
+
self.cadical = Cadical300()
|
|
169
|
+
else:
|
|
170
|
+
raise(NoSuchSolverError(engine))
|
|
150
171
|
|
|
151
172
|
# status of processor is True by default meaning
|
|
152
173
|
# that the input formula *is not* unsatisfiable
|
|
@@ -219,14 +240,18 @@ class Processor(object):
|
|
|
219
240
|
if self.cadical:
|
|
220
241
|
self.cadical.append_formula(formula)
|
|
221
242
|
|
|
222
|
-
def process(self, rounds=1,
|
|
223
|
-
|
|
224
|
-
|
|
243
|
+
def process(self, rounds=1, backbone=True, block=False, condition=False,
|
|
244
|
+
congruence=True, cover=False, decompose=True, elim=True,
|
|
245
|
+
probe=True, probehbr=True, subsume=True, sweep=True,
|
|
246
|
+
ternary=True, transred=True, vivify=True, freeze=[]):
|
|
225
247
|
"""
|
|
226
248
|
Runs CaDiCaL's preprocessor for the internal formula for a given
|
|
227
249
|
number of rounds and using the techniques specified in the
|
|
228
250
|
arguments. Note that the default values of all the arguments used
|
|
229
|
-
are set as in the default configuration of CaDiCaL 1.5.3
|
|
251
|
+
are set as in the default configuration of CaDiCaL 1.5.3 and
|
|
252
|
+
3.0.0. Arguments ``backbone``, ``congruence``, and ``sweep`` are
|
|
253
|
+
used by CaDiCaL 3.0.0 only, as the older versions do not support
|
|
254
|
+
these techniques.
|
|
230
255
|
|
|
231
256
|
As the result, the method returns a :class:`.CNF` object
|
|
232
257
|
containing the processed formula. Additionally to the clauses, the
|
|
@@ -241,7 +266,11 @@ class Processor(object):
|
|
|
241
266
|
and covered clause elimination is invoked only if bounded variable
|
|
242
267
|
elimination is active. Subsumption elimination in turn may trigger
|
|
243
268
|
vivification and transitive reduction if the corresponding flags
|
|
244
|
-
are set.
|
|
269
|
+
are set. Also, in CaDiCaL 3.0.0, flag ``probe`` controls only
|
|
270
|
+
failed literal probing while the other techniques applied along
|
|
271
|
+
with probing are controlled by their own flags. Flag ``elim``
|
|
272
|
+
there controls both bounded variable elimination and its fast
|
|
273
|
+
variant applied at the beginning of preprocessing.
|
|
245
274
|
|
|
246
275
|
Finally, note that the ``freeze`` argument can be used to keep
|
|
247
276
|
some of the variables of the original formula unchanged during
|
|
@@ -251,15 +280,21 @@ class Processor(object):
|
|
|
251
280
|
:param rounds: number of preprocessing rounds
|
|
252
281
|
:type rounds: int
|
|
253
282
|
|
|
283
|
+
:param backbone: compute backbones of the binary clauses (CaDiCaL 3.0.0 only)
|
|
284
|
+
:type backbone: bool
|
|
285
|
+
|
|
254
286
|
:param block: apply blocked clause elimination
|
|
255
287
|
:type block: bool
|
|
256
288
|
|
|
257
|
-
:param cover: apply covered clause elimination
|
|
258
|
-
:type cover: bool
|
|
259
|
-
|
|
260
289
|
:param condition: detect conditional autarkies and apply globally-blocked clause elimination
|
|
261
290
|
:type condition: bool
|
|
262
291
|
|
|
292
|
+
:param congruence: detect AND, XOR, and ITE gates and merge equivalent gate outputs (CaDiCaL 3.0.0 only)
|
|
293
|
+
:type congruence: bool
|
|
294
|
+
|
|
295
|
+
:param cover: apply covered clause elimination
|
|
296
|
+
:type cover: bool
|
|
297
|
+
|
|
263
298
|
:param decompose: detect strongly connected components (SCCs) in the binary implication graph (BIG) and apply equivalent literal substitution (ELS)
|
|
264
299
|
:type decompose: bool
|
|
265
300
|
|
|
@@ -275,6 +310,15 @@ class Processor(object):
|
|
|
275
310
|
:param subsume: apply global forward clause subsumption
|
|
276
311
|
:type subsume: bool
|
|
277
312
|
|
|
313
|
+
:param sweep: apply SAT sweeping to detect equivalent literals and backbones (CaDiCaL 3.0.0 only)
|
|
314
|
+
:type sweep: bool
|
|
315
|
+
|
|
316
|
+
:param ternary: apply hyper ternary resolution
|
|
317
|
+
:type ternary: bool
|
|
318
|
+
|
|
319
|
+
:param transred: apply transitive reduction of the binary implication graph (BIG)
|
|
320
|
+
:type transred: bool
|
|
321
|
+
|
|
278
322
|
:param vivify: apply clause vivification
|
|
279
323
|
:type vivify: bool
|
|
280
324
|
|
|
@@ -304,11 +348,24 @@ class Processor(object):
|
|
|
304
348
|
"""
|
|
305
349
|
|
|
306
350
|
if self.cadical:
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
351
|
+
# techniques unavailable in the older versions of CaDiCaL
|
|
352
|
+
extra = {}
|
|
353
|
+
if isinstance(self.cadical, Cadical300):
|
|
354
|
+
extra = dict(backbone=backbone, congruence=congruence,
|
|
355
|
+
sweep=sweep)
|
|
356
|
+
|
|
357
|
+
self.status, result = self.cadical.process(rounds=rounds,
|
|
358
|
+
block=block,
|
|
359
|
+
condition=condition,
|
|
360
|
+
cover=cover,
|
|
361
|
+
decompose=decompose,
|
|
362
|
+
elim=elim, probe=probe,
|
|
363
|
+
probehbr=probehbr,
|
|
364
|
+
subsume=subsume,
|
|
365
|
+
ternary=ternary,
|
|
366
|
+
transred=transred,
|
|
367
|
+
vivify=vivify,
|
|
368
|
+
freeze=freeze, **extra)
|
|
312
369
|
|
|
313
370
|
# making the status Boolean
|
|
314
371
|
self.status = False if self.status == 20 else True
|
|
@@ -1359,6 +1359,64 @@ class Solver(object):
|
|
|
1359
1359
|
if self.solver:
|
|
1360
1360
|
return self.solver.propagate(assumptions, phase_saving)
|
|
1361
1361
|
|
|
1362
|
+
def flip_bits(self, assumptions=[], preferences=None, budget=100000):
|
|
1363
|
+
"""
|
|
1364
|
+
Run a "bit flipper" a.k.a. local search (based on CaDiCaL's
|
|
1365
|
+
ProbSAT-like walker) aiming at a model of the formula that
|
|
1366
|
+
minimizes its *cost* with respect to a set of weighted literal
|
|
1367
|
+
preferences, i.e. the sum of the weights of the preferred literals
|
|
1368
|
+
falsified by the model. The method returns a pair of a model and
|
|
1369
|
+
its cost, or ``(None, None)`` if no model is found.
|
|
1370
|
+
|
|
1371
|
+
Preferences are given as a dictionary mapping literals to their
|
|
1372
|
+
non-negative integer weights (both polarities of a variable can
|
|
1373
|
+
be preferred). The preferences are kept between the calls unless
|
|
1374
|
+
new ones are provided. The search is limited by a ``budget``
|
|
1375
|
+
given in CaDiCaL's local search *ticks* (a measure of memory
|
|
1376
|
+
accesses).
|
|
1377
|
+
|
|
1378
|
+
**Note** that all the clauses removed by preprocessing (see
|
|
1379
|
+
:meth:`Cadical300.process`) are restored by the method.
|
|
1380
|
+
|
|
1381
|
+
**Note** that only :class:`Cadical300` supports this
|
|
1382
|
+
functionality, without external propagators (and so without
|
|
1383
|
+
native cardinality constraints).
|
|
1384
|
+
|
|
1385
|
+
.. warning::
|
|
1386
|
+
|
|
1387
|
+
This prototype implementation has been written by an LLM. So
|
|
1388
|
+
use at your own risk!
|
|
1389
|
+
|
|
1390
|
+
:param assumptions: a list of assumption literals.
|
|
1391
|
+
:param preferences: weighted preferred literals.
|
|
1392
|
+
:param budget: limit on the number of ticks.
|
|
1393
|
+
|
|
1394
|
+
:type assumptions: iterable(int)
|
|
1395
|
+
:type preferences: dict(int, int)
|
|
1396
|
+
:type budget: int
|
|
1397
|
+
|
|
1398
|
+
:rtype: tuple(list(int), int) or tuple(None, None).
|
|
1399
|
+
|
|
1400
|
+
Usage example:
|
|
1401
|
+
|
|
1402
|
+
.. code-block:: python
|
|
1403
|
+
|
|
1404
|
+
>>> from pysat.solvers import Solver
|
|
1405
|
+
>>>
|
|
1406
|
+
>>> with Solver(name='cd30', bootstrap_with=[[1, 2], [-1, -2]]) as s:
|
|
1407
|
+
... print(s.solve())
|
|
1408
|
+
... print(s.flip_bits(preferences={1: 5, 2: 3}))
|
|
1409
|
+
...
|
|
1410
|
+
True
|
|
1411
|
+
([1, -2], 3)
|
|
1412
|
+
"""
|
|
1413
|
+
|
|
1414
|
+
if self.solver:
|
|
1415
|
+
if isinstance(self.solver, Cadical300):
|
|
1416
|
+
return self.solver.flip_bits(assumptions, preferences, budget)
|
|
1417
|
+
else:
|
|
1418
|
+
raise NotImplementedError('Local search is supported only by CaDiCaL 3.0.0')
|
|
1419
|
+
|
|
1362
1420
|
def apply_jw(self):
|
|
1363
1421
|
"""
|
|
1364
1422
|
Recompute and apply JW scores to the current formula.
|
|
@@ -1416,9 +1474,7 @@ class Solver(object):
|
|
|
1416
1474
|
"""
|
|
1417
1475
|
|
|
1418
1476
|
if self.solver:
|
|
1419
|
-
if hard:
|
|
1420
|
-
if not isinstance(self.solver, Ergo):
|
|
1421
|
-
raise NotImplementedError('Setting persistent phases is unsupported by this solver')
|
|
1477
|
+
if hard and isinstance(self.solver, Ergo):
|
|
1422
1478
|
return self.solver.set_phases(literals, hard=True)
|
|
1423
1479
|
|
|
1424
1480
|
return self.solver.set_phases(literals)
|
|
@@ -2365,9 +2421,10 @@ class Cadical153(object):
|
|
|
2365
2421
|
if self.cadical:
|
|
2366
2422
|
pysolvers.cadical153_dbudget(self.cadical, budget)
|
|
2367
2423
|
|
|
2368
|
-
def process(self, rounds=1, block=False,
|
|
2424
|
+
def process(self, rounds=1, block=False, condition=False, cover=False,
|
|
2369
2425
|
decompose=True, elim=True, probe=True, probehbr=True,
|
|
2370
|
-
subsume=True,
|
|
2426
|
+
subsume=True, ternary=True, transred=True, vivify=True,
|
|
2427
|
+
freeze=[]):
|
|
2371
2428
|
"""
|
|
2372
2429
|
Apply the preprocessor for the internal formula. See the
|
|
2373
2430
|
documentation for the ``process`` module for details.
|
|
@@ -2379,7 +2436,8 @@ class Cadical153(object):
|
|
|
2379
2436
|
int(condition),
|
|
2380
2437
|
int(decompose), int(elim),
|
|
2381
2438
|
int(probe), int(probehbr),
|
|
2382
|
-
int(subsume), int(
|
|
2439
|
+
int(subsume), int(ternary),
|
|
2440
|
+
int(transred), int(vivify),
|
|
2383
2441
|
freeze,
|
|
2384
2442
|
int(MainThread.check()))
|
|
2385
2443
|
|
|
@@ -2799,9 +2857,10 @@ class Cadical195(object):
|
|
|
2799
2857
|
if self.cadical:
|
|
2800
2858
|
pysolvers.cadical195_dbudget(self.cadical, budget)
|
|
2801
2859
|
|
|
2802
|
-
def process(self, rounds=1, block=False,
|
|
2860
|
+
def process(self, rounds=1, block=False, condition=False, cover=False,
|
|
2803
2861
|
decompose=True, elim=True, probe=True, probehbr=True,
|
|
2804
|
-
subsume=True,
|
|
2862
|
+
subsume=True, ternary=True, transred=True, vivify=True,
|
|
2863
|
+
freeze=[]):
|
|
2805
2864
|
"""
|
|
2806
2865
|
Apply the preprocessor for the internal formula. See the
|
|
2807
2866
|
documentation for the ``process`` module for details.
|
|
@@ -2813,7 +2872,8 @@ class Cadical195(object):
|
|
|
2813
2872
|
int(condition),
|
|
2814
2873
|
int(decompose), int(elim),
|
|
2815
2874
|
int(probe), int(probehbr),
|
|
2816
|
-
int(subsume), int(
|
|
2875
|
+
int(subsume), int(ternary),
|
|
2876
|
+
int(transred), int(vivify),
|
|
2817
2877
|
freeze,
|
|
2818
2878
|
int(MainThread.check()))
|
|
2819
2879
|
|
|
@@ -3373,6 +3433,31 @@ class Cadical300(object):
|
|
|
3373
3433
|
|
|
3374
3434
|
return self.status
|
|
3375
3435
|
|
|
3436
|
+
def flip_bits(self, assumptions=[], preferences=None, budget=100000):
|
|
3437
|
+
"""
|
|
3438
|
+
Run local search guided by weighted literal preferences.
|
|
3439
|
+
"""
|
|
3440
|
+
|
|
3441
|
+
if self.cadical:
|
|
3442
|
+
self.sync_vars()
|
|
3443
|
+
|
|
3444
|
+
if self.use_timer:
|
|
3445
|
+
start_time = process_time()
|
|
3446
|
+
|
|
3447
|
+
res = pysolvers.cadical300_flipbits(self.cadical, assumptions,
|
|
3448
|
+
preferences, budget, int(MainThread.check()))
|
|
3449
|
+
|
|
3450
|
+
if self.use_timer:
|
|
3451
|
+
self.call_time = process_time() - start_time
|
|
3452
|
+
self.accu_time += self.call_time
|
|
3453
|
+
|
|
3454
|
+
# the solver is in the inconclusive state now
|
|
3455
|
+
self.status = None
|
|
3456
|
+
self.prev_assumps = assumptions
|
|
3457
|
+
self.sync_vpool()
|
|
3458
|
+
|
|
3459
|
+
return res
|
|
3460
|
+
|
|
3376
3461
|
def conf_budget(self, budget):
|
|
3377
3462
|
"""
|
|
3378
3463
|
Set limit on the number of conflicts.
|
|
@@ -3389,9 +3474,10 @@ class Cadical300(object):
|
|
|
3389
3474
|
if self.cadical:
|
|
3390
3475
|
pysolvers.cadical300_dbudget(self.cadical, budget)
|
|
3391
3476
|
|
|
3392
|
-
def process(self, rounds=1,
|
|
3393
|
-
|
|
3394
|
-
|
|
3477
|
+
def process(self, rounds=1, backbone=True, block=False, condition=False,
|
|
3478
|
+
congruence=True, cover=False, decompose=True, elim=True,
|
|
3479
|
+
probe=True, probehbr=True, subsume=True, sweep=True,
|
|
3480
|
+
ternary=True, transred=True, vivify=True, freeze=[]):
|
|
3395
3481
|
"""
|
|
3396
3482
|
Apply the preprocessor for the internal formula. See the
|
|
3397
3483
|
documentation for the ``process`` module for details.
|
|
@@ -3401,12 +3487,14 @@ class Cadical300(object):
|
|
|
3401
3487
|
self.sync_vars()
|
|
3402
3488
|
|
|
3403
3489
|
result = pysolvers.cadical300_process(self.cadical, rounds,
|
|
3404
|
-
int(
|
|
3405
|
-
int(condition),
|
|
3490
|
+
int(backbone), int(block),
|
|
3491
|
+
int(cover), int(condition),
|
|
3492
|
+
int(congruence),
|
|
3406
3493
|
int(decompose), int(elim),
|
|
3407
3494
|
int(probe), int(probehbr),
|
|
3408
|
-
int(subsume), int(
|
|
3409
|
-
|
|
3495
|
+
int(subsume), int(sweep),
|
|
3496
|
+
int(ternary), int(transred),
|
|
3497
|
+
int(vivify), freeze,
|
|
3410
3498
|
int(MainThread.check()))
|
|
3411
3499
|
|
|
3412
3500
|
self.sync_vpool()
|
|
@@ -1873,20 +1873,20 @@ diff -Naur solvers/cadical153/solver.cpp solvers/cdc153/solver.cpp
|
|
|
1873
1873
|
+
|
|
1874
1874
|
+vector<bool> Solver::extend(vector<int>& solution)
|
|
1875
1875
|
+{
|
|
1876
|
-
+
|
|
1877
|
-
+
|
|
1878
|
-
+ int
|
|
1879
|
-
+ if (
|
|
1880
|
-
+
|
|
1881
|
-
+
|
|
1882
|
-
+
|
|
1883
|
-
+
|
|
1884
|
-
+
|
|
1885
|
-
+ internal->vals[-i] = 1;
|
|
1886
|
-
+ }
|
|
1876
|
+
+ vector<int> assigned; // values set here, to be undone after extension
|
|
1877
|
+
+ for (int lit : solution) {
|
|
1878
|
+
+ const int idx = abs(lit);
|
|
1879
|
+
+ if (idx > external->max_var) continue; // unknown variable
|
|
1880
|
+
+ const int ilit = external->e2i[idx];
|
|
1881
|
+
+ if (!ilit || internal->vals[ilit]) continue; // unmapped or fixed
|
|
1882
|
+
+ internal->vals[ilit] = lit > 0 ? 1 : -1;
|
|
1883
|
+
+ internal->vals[-ilit] = -internal->vals[ilit];
|
|
1884
|
+
+ assigned.push_back(ilit);
|
|
1887
1885
|
+ }
|
|
1888
1886
|
+ external->extend();
|
|
1889
1887
|
+
|
|
1888
|
+
+ for (int ilit : assigned)
|
|
1889
|
+
+ internal->vals[ilit] = internal->vals[-ilit] = 0;
|
|
1890
1890
|
+ return external->vals;
|
|
1891
1891
|
+}
|
|
1892
1892
|
+
|
|
@@ -2855,20 +2855,20 @@ diff -Naur solvers/cadical195/solver.cpp solvers/cdc195/solver.cpp
|
|
|
2855
2855
|
+
|
|
2856
2856
|
+vector<bool> Solver::extend(vector<int>& solution)
|
|
2857
2857
|
+{
|
|
2858
|
-
+
|
|
2859
|
-
+
|
|
2860
|
-
+ int
|
|
2861
|
-
+ if (
|
|
2862
|
-
+
|
|
2863
|
-
+
|
|
2864
|
-
+
|
|
2865
|
-
+
|
|
2866
|
-
+
|
|
2867
|
-
+ internal->vals[-i] = 1;
|
|
2868
|
-
+ }
|
|
2858
|
+
+ vector<int> assigned; // values set here, to be undone after extension
|
|
2859
|
+
+ for (int lit : solution) {
|
|
2860
|
+
+ const int idx = abs(lit);
|
|
2861
|
+
+ if (idx > external->max_var) continue; // unknown variable
|
|
2862
|
+
+ const int ilit = external->e2i[idx];
|
|
2863
|
+
+ if (!ilit || internal->vals[ilit]) continue; // unmapped or fixed
|
|
2864
|
+
+ internal->vals[ilit] = lit > 0 ? 1 : -1;
|
|
2865
|
+
+ internal->vals[-ilit] = -internal->vals[ilit];
|
|
2866
|
+
+ assigned.push_back(ilit);
|
|
2869
2867
|
+ }
|
|
2870
2868
|
+ external->extend();
|
|
2871
2869
|
+
|
|
2870
|
+
+ for (int ilit : assigned)
|
|
2871
|
+
+ internal->vals[ilit] = internal->vals[-ilit] = 0;
|
|
2872
2872
|
+ return external->vals;
|
|
2873
2873
|
+}
|
|
2874
2874
|
+
|