python-sat 1.8.dev13__tar.gz → 1.8.dev14__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.
Potentially problematic release.
This version of python-sat might be problematic. Click here for more details.
- {python-sat-1.8.dev13/python_sat.egg-info → python_sat-1.8.dev14}/PKG-INFO +1 -1
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/allies/approxmc.py +16 -16
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/allies/unigen.py +13 -12
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/examples/fm.py +3 -3
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/examples/genhard.py +24 -23
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/examples/hitman.py +5 -5
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/examples/musx.py +1 -1
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/examples/rc2.py +7 -7
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/pysat/__init__.py +1 -1
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/pysat/card.py +13 -12
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/pysat/engines.py +3 -3
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/pysat/formula.py +59 -47
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/pysat/pb.py +9 -8
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/pysat/solvers.py +10 -10
- {python-sat-1.8.dev13 → python_sat-1.8.dev14/python_sat.egg-info}/PKG-INFO +1 -1
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/python_sat.egg-info/SOURCES.txt +2 -1
- python-sat-1.8.dev13/tests/test_cnfplus.py → python_sat-1.8.dev14/tests/test_cnf.py +12 -1
- python_sat-1.8.dev14/tests/test_formula_unique.py +38 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/LICENSE.txt +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/MANIFEST.in +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/README.rst +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/allies/__init__.py +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/cardenc/bitwise.hh +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/cardenc/card.hh +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/cardenc/clset.hh +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/cardenc/common.hh +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/cardenc/itot.hh +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/cardenc/ladder.hh +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/cardenc/mto.hh +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/cardenc/pairwise.hh +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/cardenc/ptypes.hh +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/cardenc/pycard.cc +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/cardenc/seqcounter.hh +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/cardenc/sortcard.hh +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/cardenc/utils.hh +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/examples/__init__.py +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/examples/lbx.py +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/examples/lsu.py +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/examples/mcsls.py +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/examples/models.py +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/examples/optux.py +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/examples/usage.py +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/pysat/_fileio.py +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/pysat/_utils.py +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/pysat/process.py +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/python_sat.egg-info/dependency_links.txt +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/python_sat.egg-info/requires.txt +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/python_sat.egg-info/top_level.txt +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/requirements.txt +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/setup.cfg +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/setup.py +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/cadical103.tar.gz +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/cadical153.tar.gz +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/cadical170.tar.gz +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/cadical195.tar.gz +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/glucose30.tar.gz +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/glucose41.tar.gz +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/glucose421.tar.gz +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/lingeling.tar.gz +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/maplechrono.zip +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/maplecm.zip +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/maplesat.zip +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/mergesat3.tar.gz +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/minicard.tar.gz +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/minisat22.tar.gz +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/minisatgh.zip +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/patches/cadical103.patch +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/patches/cadical153.patch +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/patches/cadical195.patch +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/patches/glucose30.patch +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/patches/glucose41.patch +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/patches/glucose421.patch +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/patches/gluecard30.patch +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/patches/gluecard41.patch +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/patches/lingeling.patch +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/patches/maplechrono.patch +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/patches/maplecm.patch +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/patches/maplesat.patch +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/patches/mergesat3.patch +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/patches/minicard.patch +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/patches/minisat22.patch +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/patches/minisatgh.patch +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/prepare.py +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/solvers/pysolvers.cc +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/tests/test_accum_stats.py +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/tests/test_atmost.py +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/tests/test_atmost1.py +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/tests/test_atmostk.py +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/tests/test_boolengine.py +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/tests/test_clausification.py +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/tests/test_equals1.py +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/tests/test_process.py +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/tests/test_propagate.py +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/tests/test_unique_model.py +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/tests/test_unique_mus.py +0 -0
- {python-sat-1.8.dev13 → python_sat-1.8.dev14}/tests/test_warmstart.py +0 -0
|
@@ -47,17 +47,17 @@
|
|
|
47
47
|
The interface gives access to :class:`Counter`, which expects a formula in
|
|
48
48
|
:class:`.CNF` as input. Given a few additional (optional) arguments,
|
|
49
49
|
including a random seed, *tolerance factor* :math:`\\varepsilon`, and
|
|
50
|
-
*confidence* :math
|
|
50
|
+
*confidence* :math:`\\delta`, the class can be used to get an approximate
|
|
51
51
|
number of models of the formula, subject to the given tolerance factor and
|
|
52
52
|
confidence parameter.
|
|
53
53
|
|
|
54
|
-
Namely, given a CNF formula :math
|
|
55
|
-
as the exact number of models, and parameters
|
|
56
|
-
and :math
|
|
57
|
-
:math:`C`, which is an approximate number of
|
|
58
|
-
:math
|
|
59
|
-
:math:`\\textrm{Pr}
|
|
60
|
-
(1+\\varepsilon)
|
|
54
|
+
Namely, given a CNF formula :math:`\\mathcal{F}` with
|
|
55
|
+
:math:`\\#\\mathcal{F}` as the exact number of models, and parameters
|
|
56
|
+
:math:`\\varepsilon\\in(0,1]` and :math:`\\delta\\in[0,1)`, the counter
|
|
57
|
+
computes and reports a value :math:`C`, which is an approximate number of
|
|
58
|
+
models of :math:`\\mathcal{F}`, such that
|
|
59
|
+
:math:`\\textrm{Pr}\\left[\\frac{1}{1+\\varepsilon}\\#\\mathcal{F}\\leq
|
|
60
|
+
C\\leq (1+\\varepsilon)\\#\\mathcal{F}\\right]\\geq 1-\\delta`.
|
|
61
61
|
|
|
62
62
|
The implementation can be used as an executable (the list of available
|
|
63
63
|
command-line options can be shown using ``approxmc.py -h``) in the
|
|
@@ -131,13 +131,13 @@ class Counter(object):
|
|
|
131
131
|
models of the formula, subject to *tolerance factor* ``epsilon`` and
|
|
132
132
|
*confidence parameter* ``delta``.
|
|
133
133
|
|
|
134
|
-
Namely, given a CNF formula :math
|
|
135
|
-
:math:`\\varepsilon
|
|
136
|
-
computes and reports a value :math:`C` such that
|
|
137
|
-
:math:`\\textrm{Pr}
|
|
138
|
-
C
|
|
139
|
-
:math
|
|
140
|
-
:math
|
|
134
|
+
Namely, given a CNF formula :math:`\\mathcal{F}` and parameters
|
|
135
|
+
:math:`\\varepsilon\\in(0,1]` and :math:`\\delta\\in[0,1)`, the
|
|
136
|
+
counter computes and reports a value :math:`C` such that
|
|
137
|
+
:math:`\\textrm{Pr}\\left[\\frac{1}{1+\\varepsilon}\\#\\mathcal{F}\\leq
|
|
138
|
+
C\\leq (1+\\varepsilon)\\#\\mathcal{F}\\right]\\geq 1-\\delta`. Here,
|
|
139
|
+
:math:`\\#\\mathcal{F}` denotes the exact model count for formula
|
|
140
|
+
:math:`\\mathcal{F}`.
|
|
141
141
|
|
|
142
142
|
The ``formula`` argument can be left unspecified at this stage. In
|
|
143
143
|
this case, a user is expected to add all the relevant clauses using
|
|
@@ -241,7 +241,7 @@ class Counter(object):
|
|
|
241
241
|
of :class:`Counter` or through a series of calls to
|
|
242
242
|
:meth:`add_clause`, this method runs the ApproxMC counter with the
|
|
243
243
|
specified values of tolerance :math:`\\varepsilon` and confidence
|
|
244
|
-
:math
|
|
244
|
+
:math:`\\delta` parameters, as well as the random ``seed`` value,
|
|
245
245
|
and returns the number of models estimated.
|
|
246
246
|
|
|
247
247
|
A user may specify an argument ``projection``, which is a list of
|
|
@@ -50,20 +50,21 @@
|
|
|
50
50
|
The interface gives access to :class:`Sampler`, which expects a formula in
|
|
51
51
|
:class:`.CNF` as input. Given a few additional (optional) arguments,
|
|
52
52
|
including a random seed, *tolerance factor* :math:`\\varepsilon`,
|
|
53
|
-
*confidence* :math
|
|
54
|
-
parameter* :math
|
|
53
|
+
*confidence* :math:`\\delta` (to be used by ApproxMC), and *uniformity
|
|
54
|
+
parameter* :math:`\\kappa`, the class can be used to get apply
|
|
55
55
|
almost-uniform sampling and to obtain a requested number of samples as a
|
|
56
56
|
result, subject to the given tolerance factor and confidence parameter.
|
|
57
57
|
|
|
58
|
-
Namely, given a CNF formula :math
|
|
59
|
-
assignments (or models) denoted by :math:`sol(
|
|
60
|
-
:math:`\\varepsilon
|
|
61
|
-
:math:`y
|
|
62
|
-
\\textrm{ is
|
|
63
|
-
Almost-uniform sampling
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
\\
|
|
58
|
+
Namely, given a CNF formula :math:`\\mathcal{F}` with the set of
|
|
59
|
+
satisfying assignments (or models) denoted by :math:`sol(\\mathcal{F})`
|
|
60
|
+
and parameter :math:`\\varepsilon\\in(0,1]`, a uniform sampler outputs a
|
|
61
|
+
model :math:`y\\in sol(\\mathcal{F})` such that
|
|
62
|
+
:math:`\\textrm{Pr}\\left[y \\textrm{ is
|
|
63
|
+
output}\\right]=\\frac{1}{|sol(\\mathcal{F})|}`. Almost-uniform sampling
|
|
64
|
+
relaxes the uniformity guarantee and ensures that
|
|
65
|
+
:math:`\\frac{1}{(1+\\varepsilon)|sol(\\mathcal{F})|} \\leq
|
|
66
|
+
\\textrm{Pr}\\left[y \\textrm{ is output}\\right] \\leq
|
|
67
|
+
\\frac{1+\\varepsilon}{|sol(\\mathcal{F})|}`.
|
|
67
68
|
|
|
68
69
|
The implementation can be used as an executable (the list of available
|
|
69
70
|
command-line options can be shown using ``unigen.py -h``) in the
|
|
@@ -240,7 +241,7 @@ class Sampler(object):
|
|
|
240
241
|
of :class:`Sampler` or through a series of calls to
|
|
241
242
|
:meth:`add_clause`, this method runs the UniGen3 sampler with the
|
|
242
243
|
specified values of tolerance :math:`\\varepsilon`, confidence
|
|
243
|
-
:math
|
|
244
|
+
:math:`\\delta` parameters, and uniformity parameter :math:`kappa`
|
|
244
245
|
as well as the random ``seed`` value, and outputs a requested
|
|
245
246
|
number of samples.
|
|
246
247
|
|
|
@@ -386,12 +386,12 @@ class FM(object):
|
|
|
386
386
|
|
|
387
387
|
Otherwise (if the core contains more than one clause), every clause
|
|
388
388
|
:math:`c` of the core is *relaxed*. This means a new *relaxation
|
|
389
|
-
literal* is added to the clause, i.e. :math:`c
|
|
389
|
+
literal* is added to the clause, i.e. :math:`c\\gets c\\vee r`,
|
|
390
390
|
where :math:`r` is a fresh (unused) relaxation variable. After the
|
|
391
391
|
clauses get relaxed, a new cardinality encoding is added to the
|
|
392
392
|
formula enforcing the sum of the new relaxation variables to be not
|
|
393
|
-
greater than 1, :math
|
|
394
|
-
:math
|
|
393
|
+
greater than 1, :math:`\\sum_{c\\in\\phi}{r\\leq 1}`, where
|
|
394
|
+
:math:`\\phi` denotes the unsatisfiable core.
|
|
395
395
|
"""
|
|
396
396
|
|
|
397
397
|
if len(self.core) > 1:
|
|
@@ -129,7 +129,7 @@ class PHP(CNF, object):
|
|
|
129
129
|
"""
|
|
130
130
|
Generator of :math:`k` pigeonhole principle (:math:`k`-PHP) formulas.
|
|
131
131
|
Given integer parameters :math:`m` and :math:`k`, the :math:`k`
|
|
132
|
-
pigeonhole principle states that if :math:`k
|
|
132
|
+
pigeonhole principle states that if :math:`k\\cdot m+1` pigeons are
|
|
133
133
|
distributes by :math:`m` holes, then at least one hole contains more
|
|
134
134
|
than :math:`k` pigeons.
|
|
135
135
|
|
|
@@ -139,9 +139,9 @@ class PHP(CNF, object):
|
|
|
139
139
|
|
|
140
140
|
Assume that a Boolean variable :math:`x_{ij}` encodes that pigeon
|
|
141
141
|
:math:`i` resides in hole :math:`j`. Then a PHP formula can be seen as
|
|
142
|
-
a conjunction: :math:`\\bigwedge_{i=1}^{k
|
|
143
|
-
m+1}{\\textsf{AtLeast1}(x_{i1}
|
|
144
|
-
\\bigwedge_{j=1}^{m}{\\textsf{AtMost}k(x_{1j}
|
|
142
|
+
a conjunction: :math:`\\bigwedge_{i=1}^{k\\cdot
|
|
143
|
+
m+1}{\\textsf{AtLeast1}(x_{i1},\\ldots,x_{im})}\\wedge
|
|
144
|
+
\\bigwedge_{j=1}^{m}{\\textsf{AtMost}k(x_{1j},\\ldots,x_{k\\cdot
|
|
145
145
|
m+1,j})}`. Here each :math:`\\textsf{AtLeast1}` constraint forces every
|
|
146
146
|
pigeon to be placed into at least one hole while each
|
|
147
147
|
:math:`\\textsf{AtMost}k` constraint allows the corresponding hole to
|
|
@@ -204,16 +204,17 @@ class GT(CNF, object):
|
|
|
204
204
|
"""
|
|
205
205
|
Generator of ordering (or *greater than*, GT) principle formulas. Given
|
|
206
206
|
an integer parameter :math:`n`, the principle states that any partial
|
|
207
|
-
order on the set :math
|
|
208
|
-
|
|
209
|
-
Assume variable :math:`x_{ij}`, for :math:`i,j
|
|
210
|
-
the fact that :math:`i
|
|
211
|
-
\\neg{x_{ji}})` and :math:`(\\neg{x_{ij}}
|
|
212
|
-
x_{ik})` ensure that the relation
|
|
213
|
-
|
|
214
|
-
:math
|
|
215
|
-
|
|
216
|
-
:math:`
|
|
207
|
+
order on the set :math:`\\{1,2,\\ldots,n\\}` must have a maximal element.
|
|
208
|
+
|
|
209
|
+
Assume variable :math:`x_{ij}`, for :math:`i,j\\in[n],i\\neq j`,
|
|
210
|
+
denotes the fact that :math:`i \\succ j`. Clauses
|
|
211
|
+
:math:`(\\neg{x_{ij}} \\vee \\neg{x_{ji}})` and :math:`(\\neg{x_{ij}}
|
|
212
|
+
\\vee \\neg{x_{jk}} \\vee x_{ik})` ensure that the relation
|
|
213
|
+
:math:`\\succ` is anti-symmetric and transitive. As a result,
|
|
214
|
+
:math:`\\succ` is a partial order on :math:`[n]`. The additional
|
|
215
|
+
requirement that each element :math:`i` has a successor in
|
|
216
|
+
:math:`[n]\\setminus\\{i\\}` represented a clause :math:`(\\vee_{j
|
|
217
|
+
\\neq i}{x_{ji}})` makes the formula unsatisfiable.
|
|
217
218
|
|
|
218
219
|
GT formulas were originally conjectured [2]_ to be hard for resolution.
|
|
219
220
|
However, [5]_ proved the existence of a polynomial size resolution
|
|
@@ -276,18 +277,18 @@ class CB(CNF, object):
|
|
|
276
277
|
"""
|
|
277
278
|
Mutilated chessboard principle (CB). Given an integer :math:`n`, the
|
|
278
279
|
principle states that it is impossible to cover a chessboard of size
|
|
279
|
-
:math:`2n
|
|
280
|
+
:math:`2n\\cdot 2n` by domino tiles if two diagonally opposite corners
|
|
280
281
|
of the chessboard are removed.
|
|
281
282
|
|
|
282
283
|
Note that the chessboard has :math:`4n^2-2` cells. Introduce a Boolean
|
|
283
|
-
variable :math:`x_{ij}` for :math:`i,j
|
|
284
|
-
and :math:`j` are adjacent (no variables are introduced for
|
|
285
|
-
non-adjacent cells). CB formulas comprise clauses (1)
|
|
284
|
+
variable :math:`x_{ij}` for :math:`i,j\\in[4n^2-2]` s.t. cells
|
|
285
|
+
:math:`i` and :math:`j` are adjacent (no variables are introduced for
|
|
286
|
+
pairs of non-adjacent cells). CB formulas comprise clauses (1)
|
|
286
287
|
:math:`(\\neg{x_{ji} \\vee \\neg{x_{ki}}})` for every :math:`i,j \\neq
|
|
287
288
|
k` meaning that no more than one adjacent cell can be paired with the
|
|
288
|
-
current one; and (2) :math:`(\\vee_{j
|
|
289
|
-
\\forall i` enforcing that every cell :math:`i` should
|
|
290
|
-
at least one adjacent cell.
|
|
289
|
+
current one; and (2) :math:`(\\vee_{j \\in \\text{Adj}(i)}
|
|
290
|
+
{x_{ij}})\\,\\, \\forall i` enforcing that every cell :math:`i` should
|
|
291
|
+
be paired with at least one adjacent cell.
|
|
291
292
|
|
|
292
293
|
Clearly, since the two diagonal corners are removed, the formula is
|
|
293
294
|
unsatisfiable. Also note the following. Assuming that the number of
|
|
@@ -389,8 +390,8 @@ class PAR(CNF, object):
|
|
|
389
390
|
variables :math:`x_{ij},i \\neq j`. If variable :math:`x_{ij}` is
|
|
390
391
|
*true*, then there is an edge between nodes :math:`i` and :math:`j`.
|
|
391
392
|
The formula consists of the following clauses: :math:`(\\vee_{j \\neq
|
|
392
|
-
i}{x_{ij}})` for every :math:`i
|
|
393
|
-
\\vee \\neg{x_{kj}})` for all distinct :math:`i,j,k
|
|
393
|
+
i}{x_{ij}})` for every :math:`i\\in[2n+1]`, and :math:`(\\neg{x_{ij}}
|
|
394
|
+
\\vee \\neg{x_{kj}})` for all distinct :math:`i,j,k \\in [2n+1]`.
|
|
394
395
|
|
|
395
396
|
The parity principle is known to be hard for resolution [4]_.
|
|
396
397
|
|
|
@@ -35,14 +35,14 @@
|
|
|
35
35
|
by size) subset-minimal hitting enumeration.
|
|
36
36
|
|
|
37
37
|
The minimal hitting set problem is trivially formulated as a MaxSAT formula
|
|
38
|
-
in WCNF, as follows. Assume :math:`E
|
|
38
|
+
in WCNF, as follows. Assume :math:`E=\\{e_1,\\ldots,e_n\\}` to be a universe
|
|
39
39
|
of elements. Also assume there are :math:`k` sets to hit:
|
|
40
|
-
:math:`s_i
|
|
41
|
-
set :math:`s_i
|
|
42
|
-
clause :math:`(e_{i,1} \\vee
|
|
40
|
+
:math:`s_i=\\{e_{i,1},\\ldots,e_{i,j_i}\\}` s.t. :math:`e_{i,l}\\in E`. Every
|
|
41
|
+
set :math:`s_i=\\{e_{i,1},\\ldots,e_{i,j_i}\\}` is translated into a hard
|
|
42
|
+
clause :math:`(e_{i,1} \\vee \\ldots \\vee e_{i,j_i})`. This results in the
|
|
43
43
|
set of hard clauses having size :math:`k`. The set of soft clauses
|
|
44
44
|
comprises unit clauses of the form :math:`(\\neg{e_{j}})` s.t.
|
|
45
|
-
:math:`e_{j}
|
|
45
|
+
:math:`e_{j}\\in E`, each having weight 1.
|
|
46
46
|
|
|
47
47
|
Taking into account this problem formulation as MaxSAT, ordered hitting
|
|
48
48
|
enumeration is done with the use of the state-of-the-art MaxSAT solver
|
|
@@ -227,7 +227,7 @@ class MUSX(object):
|
|
|
227
227
|
|
|
228
228
|
Soft clauses are (de)activated using the standard MiniSat-like
|
|
229
229
|
assumptions interface [2]_. Each soft clause :math:`c` is augmented
|
|
230
|
-
with a selector literal :math:`s`, e.g. :math:`(c)
|
|
230
|
+
with a selector literal :math:`s`, e.g. :math:`(c) \\gets (c \\vee
|
|
231
231
|
\\neg{s})`. As a result, clause :math:`c` can be activated by
|
|
232
232
|
assuming literal :math:`s`. The over-approximation provided as an
|
|
233
233
|
input is specified as a list of selector literals for clauses in
|
|
@@ -695,8 +695,8 @@ class RC2(object):
|
|
|
695
695
|
"""
|
|
696
696
|
Detect and adapt intrinsic AtMost1 constraints. Assume
|
|
697
697
|
there is a subset of soft clauses
|
|
698
|
-
:math:`\\mathcal{S}'
|
|
699
|
-
:math
|
|
698
|
+
:math:`\\mathcal{S}'\\subseteq \\mathcal{S}` s.t.
|
|
699
|
+
:math:`\\sum_{c\\in\\mathcal{S}'}{c\\leq 1}`, i.e. at most
|
|
700
700
|
one of the clauses of :math:`\\mathcal{S}'` can be
|
|
701
701
|
satisfied.
|
|
702
702
|
|
|
@@ -709,7 +709,7 @@ class RC2(object):
|
|
|
709
709
|
unit-propagated to be false. Note that this method for
|
|
710
710
|
detection of AtMost1 constraints is *incomplete*, because
|
|
711
711
|
in general unit propagation does not suffice to test
|
|
712
|
-
whether or not :math:`\\mathcal{F}
|
|
712
|
+
whether or not :math:`\\mathcal{F}\\wedge l_i\\models
|
|
713
713
|
\\neg{l_j}`.
|
|
714
714
|
|
|
715
715
|
Each intrinsic AtMost1 constraint detected this way is
|
|
@@ -796,7 +796,7 @@ class RC2(object):
|
|
|
796
796
|
has cost at least :math:`|\\mathcal{S}'|-1` (assuming
|
|
797
797
|
*unweighted* MaxSAT). Furthermore, it is safe to replace
|
|
798
798
|
all clauses of :math:`\\mathcal{S}'` with a single soft
|
|
799
|
-
clause :math
|
|
799
|
+
clause :math:`\\sum_{c\\in\\mathcal{S}'}{c}`.
|
|
800
800
|
|
|
801
801
|
Here, input parameter ``am1`` plays the role of subset
|
|
802
802
|
:math:`\\mathcal{S}'` mentioned above. The procedure bumps
|
|
@@ -907,13 +907,13 @@ class RC2(object):
|
|
|
907
907
|
optimization* in [6]_.
|
|
908
908
|
|
|
909
909
|
Given a totalizer object ``tobj`` representing a sum of
|
|
910
|
-
some *relaxation* variables :math:`r
|
|
910
|
+
some *relaxation* variables :math:`r\\in R` that augment
|
|
911
911
|
soft clauses :math:`\\mathcal{C}_r`, the idea is to
|
|
912
912
|
increase the right-hand side of the sum (which is equal to
|
|
913
913
|
1 by default) as much as possible, reaching a value
|
|
914
914
|
:math:`k` s.t. formula
|
|
915
|
-
:math:`\\mathcal{H}
|
|
916
|
-
R}{r
|
|
915
|
+
:math:`\\mathcal{H}\\wedge\\mathcal{C}_r\\wedge(\\sum_{r\\in
|
|
916
|
+
R}{r\\leq k})` is still unsatisfiable while increasing it
|
|
917
917
|
further makes the formula satisfiable (here
|
|
918
918
|
:math:`\\mathcal{H}` denotes the hard part of the
|
|
919
919
|
formula).
|
|
@@ -68,10 +68,10 @@
|
|
|
68
68
|
pp. 129-134
|
|
69
69
|
|
|
70
70
|
A cardinality constraint is a constraint of the form:
|
|
71
|
-
:math
|
|
72
|
-
practical problem formulations. Note that the implementation of the
|
|
71
|
+
:math:`\\sum_{i=1}^n{x_i}\\leq k`. Cardinality constraints are ubiquitous
|
|
72
|
+
in practical problem formulations. Note that the implementation of the
|
|
73
73
|
pairwise, bitwise, and ladder encodings can only deal with AtMost1
|
|
74
|
-
constraints, e.g. :math
|
|
74
|
+
constraints, e.g. :math:`\\sum_{i=1}^n{x_i}\\leq 1`.
|
|
75
75
|
|
|
76
76
|
Access to all cardinality encodings can be made through the main class of
|
|
77
77
|
this module, which is :class:`.CardEnc`.
|
|
@@ -150,9 +150,9 @@ class EncType(object):
|
|
|
150
150
|
Note that while most of the encodings are produced as a list of
|
|
151
151
|
clauses, the "native" encoding of `MiniCard
|
|
152
152
|
<https://github.com/liffiton/minicard>`__ is managed as one clause.
|
|
153
|
-
Given an AtMostK constraint :math
|
|
154
|
-
encoding represents it as a pair ``[lits, k]``, where ``lits``
|
|
155
|
-
list of size ``n`` containing literals in the sum.
|
|
153
|
+
Given an AtMostK constraint :math:`\\sum_{i=1}^n{x_i\\leq k}`, the
|
|
154
|
+
native encoding represents it as a pair ``[lits, k]``, where ``lits``
|
|
155
|
+
is a list of size ``n`` containing literals in the sum.
|
|
156
156
|
"""
|
|
157
157
|
|
|
158
158
|
pairwise = 0
|
|
@@ -248,8 +248,8 @@ class CardEnc(object):
|
|
|
248
248
|
encoding=EncType.seqcounter):
|
|
249
249
|
"""
|
|
250
250
|
This method can be used for creating a CNF encoding of an AtMostK
|
|
251
|
-
constraint, i.e. of :math
|
|
252
|
-
shares the arguments and the return type with method
|
|
251
|
+
constraint, i.e. of :math:`\\sum_{i=1}^{n}{x_i}\\leq k`. The
|
|
252
|
+
method shares the arguments and the return type with method
|
|
253
253
|
:meth:`CardEnc.atleast`. Please, see it for details.
|
|
254
254
|
"""
|
|
255
255
|
|
|
@@ -310,9 +310,10 @@ class CardEnc(object):
|
|
|
310
310
|
encoding=EncType.seqcounter):
|
|
311
311
|
"""
|
|
312
312
|
This method can be used for creating a CNF encoding of an AtLeastK
|
|
313
|
-
constraint, i.e. of :math
|
|
314
|
-
takes 1 mandatory argument ``lits`` and 3 default arguments
|
|
315
|
-
specified: ``bound``, ``top_id``, ``vpool``, and
|
|
313
|
+
constraint, i.e. of :math:`\\sum_{i=1}^{n}{x_i}\\geq k`. The
|
|
314
|
+
method takes 1 mandatory argument ``lits`` and 3 default arguments
|
|
315
|
+
can be specified: ``bound``, ``top_id``, ``vpool``, and
|
|
316
|
+
``encoding``.
|
|
316
317
|
|
|
317
318
|
:param lits: a list of literals in the sum.
|
|
318
319
|
:param bound: the value of bound :math:`k`.
|
|
@@ -410,7 +411,7 @@ class CardEnc(object):
|
|
|
410
411
|
encoding=EncType.seqcounter):
|
|
411
412
|
"""
|
|
412
413
|
This method can be used for creating a CNF encoding of an EqualsK
|
|
413
|
-
constraint, i.e. of :math
|
|
414
|
+
constraint, i.e. of :math:`\\sum_{i=1}^{n}{x_i}= k`. The method
|
|
414
415
|
makes consecutive calls of both :meth:`CardEnc.atleast` and
|
|
415
416
|
:meth:`CardEnc.atmost`. It shares the arguments and the return type
|
|
416
417
|
with method :meth:`CardEnc.atleast`. Please, see it for details.
|
|
@@ -342,9 +342,9 @@ class LinearConstraint:
|
|
|
342
342
|
class ParityConstraint:
|
|
343
343
|
"""
|
|
344
344
|
A possible implementation of parity constraints. These are constraints
|
|
345
|
-
of the form :math:`l_1
|
|
346
|
-
each :math:`l_i` is a Boolean literal while :math:`b` is a
|
|
347
|
-
constant. The class is designed to exemplify the work with
|
|
345
|
+
of the form :math:`l_1 \\oplus l_2 \\oplus \\ldots \\oplus l_n = b`
|
|
346
|
+
where each :math:`l_i` is a Boolean literal while :math:`b` is a
|
|
347
|
+
Boolean constant. The class is designed to exemplify the work with
|
|
348
348
|
:class:`BooleanEngine`.
|
|
349
349
|
|
|
350
350
|
The implementation is pretty naive. It propagates a last unassigned
|
|
@@ -125,19 +125,19 @@
|
|
|
125
125
|
additional class for dealing with *partial* and *weighted partial* CNF
|
|
126
126
|
formulas, i.e. WCNF formulas. A WCNF formula is a conjunction of two sets
|
|
127
127
|
of clauses: *hard* clauses and *soft* clauses, i.e.
|
|
128
|
-
:math
|
|
128
|
+
:math:`\\mathcal{F}=\\mathcal{H}\\wedge\\mathcal{S}`. Soft clauses of a WCNF
|
|
129
129
|
are labeled with integer *weights*, i.e. a soft clause of
|
|
130
|
-
:math
|
|
130
|
+
:math:`\\mathcal{S}` is a pair :math:`(c_i, w_i)`. In partial (unweighted)
|
|
131
131
|
formulas, all soft clauses have weight 1.
|
|
132
132
|
|
|
133
133
|
WCNF can be of help when solving optimization problems using the SAT
|
|
134
134
|
technology. A typical example of where a WCNF formula can be used is
|
|
135
135
|
`maximum satisfiability (MaxSAT)
|
|
136
136
|
<https://en.wikipedia.org/wiki/Maximum_satisfiability_problem>`__, which
|
|
137
|
-
given a WCNF formula :math
|
|
138
|
-
targets satisfying all its hard clauses :math
|
|
137
|
+
given a WCNF formula :math:`\\mathcal{F}=\\mathcal{H}\\wedge\\mathcal{S}`
|
|
138
|
+
targets satisfying all its hard clauses :math:`\\mathcal{H}` and maximizing
|
|
139
139
|
the sum of weights of satisfied soft clauses, i.e. maximizing the value of
|
|
140
|
-
:math
|
|
140
|
+
:math:`\\sum_{c_i\\in\\mathcal{S}}{w_i\\cdot c_i}`.
|
|
141
141
|
|
|
142
142
|
An object of class :class:`WCNF` has two variables to access the hard and
|
|
143
143
|
soft clauses of the corresponding formula: ``hard`` and ``soft``. The
|
|
@@ -160,7 +160,7 @@
|
|
|
160
160
|
[1, 3]
|
|
161
161
|
|
|
162
162
|
A properly constructed WCNF formula must have a *top weight*, which should
|
|
163
|
-
be equal to :math:`1
|
|
163
|
+
be equal to :math:`1+\\sum_{c_i\\in\\mathcal{S}}{w_i}`. Top weight of a
|
|
164
164
|
formula can be accessed through variable ``topw``.
|
|
165
165
|
|
|
166
166
|
.. code-block:: python
|
|
@@ -882,10 +882,15 @@ class Formula(object):
|
|
|
882
882
|
|
|
883
883
|
if len(collection) > 1:
|
|
884
884
|
if _hashable(collection):
|
|
885
|
-
|
|
885
|
+
# it is a hashable iterable; it is better to sort it
|
|
886
|
+
items.append((prefix, repr(sorted(collection, key=lambda x: hash(x)))))
|
|
886
887
|
else:
|
|
887
888
|
for i, item in enumerate(collection):
|
|
888
889
|
if _hashable(item):
|
|
890
|
+
# it is a hashable iterable; it is better to sort it
|
|
891
|
+
if isinstance(item, Iterable):
|
|
892
|
+
item = sorted(item, key=lambda x: hash(x))
|
|
893
|
+
|
|
889
894
|
items.append((prefix, repr(item)))
|
|
890
895
|
elif isinstance(item, Iterable):
|
|
891
896
|
items.extend(_flatten(item, prefix=prefix))
|
|
@@ -900,6 +905,10 @@ class Formula(object):
|
|
|
900
905
|
value = collection[key]
|
|
901
906
|
new_key = prefix + sep + key if prefix else key
|
|
902
907
|
if value and _hashable(value):
|
|
908
|
+
# it is a hashable iterable; it is better to sort it
|
|
909
|
+
if isinstance(value, Iterable):
|
|
910
|
+
value = sorted(value, key=lambda x: hash(x))
|
|
911
|
+
|
|
903
912
|
items.append((new_key, repr(value)))
|
|
904
913
|
elif isinstance(value, Iterable):
|
|
905
914
|
if value:
|
|
@@ -1450,9 +1459,9 @@ Formula.set_context('default')
|
|
|
1450
1459
|
class And(Formula):
|
|
1451
1460
|
"""
|
|
1452
1461
|
Conjunction. Given a list of operands (subformulas) :math:`f_i`,
|
|
1453
|
-
:math:`i
|
|
1454
|
-
:math:`\\bigwedge_{i=1}^{n}{f_i}`. The list of operands *of
|
|
1455
|
-
least 1* should be passed as arguments to the constructor.
|
|
1462
|
+
:math:`i \\in \\{1,\\ldots,n\\}, n \\in \\mathbb{N}`, it creates a
|
|
1463
|
+
formula :math:`\\bigwedge_{i=1}^{n}{f_i}`. The list of operands *of
|
|
1464
|
+
size at least 1* should be passed as arguments to the constructor.
|
|
1456
1465
|
|
|
1457
1466
|
Example:
|
|
1458
1467
|
|
|
@@ -1613,7 +1622,7 @@ class And(Formula):
|
|
|
1613
1622
|
subformula, thus representing their conjunction.
|
|
1614
1623
|
|
|
1615
1624
|
If ``name_required`` is set to ``True``, the method encodes the
|
|
1616
|
-
conjunction using the standard logic: :math:`x
|
|
1625
|
+
conjunction using the standard logic: :math:`x \\equiv
|
|
1617
1626
|
\\bigwedge{y_i}`, if :math:`x` is the new auxiliary variable
|
|
1618
1627
|
encoding ``self`` and :math:`y_i` is the auxiliary variable
|
|
1619
1628
|
representing :math:`i`'s subformula.
|
|
@@ -1672,9 +1681,9 @@ class And(Formula):
|
|
|
1672
1681
|
class Or(Formula):
|
|
1673
1682
|
"""
|
|
1674
1683
|
Disjunction. Given a list of operands (subformulas) :math:`f_i`,
|
|
1675
|
-
:math:`i
|
|
1676
|
-
:math:`\\bigvee_{i=1}^{n}{f_i}`. The list of operands *of size
|
|
1677
|
-
least 1* should be passed as arguments to the constructor.
|
|
1684
|
+
:math:`i \\in \\{1,\\ldots,n\\}, n \\in \\mathbb{N}`, it creates a
|
|
1685
|
+
formula :math:`\\bigvee_{i=1}^{n}{f_i}`. The list of operands *of size
|
|
1686
|
+
at least 1* should be passed as arguments to the constructor.
|
|
1678
1687
|
|
|
1679
1688
|
Example:
|
|
1680
1689
|
|
|
@@ -1835,7 +1844,7 @@ class Or(Formula):
|
|
|
1835
1844
|
subformula, thus representing their conjunction.
|
|
1836
1845
|
|
|
1837
1846
|
If ``name_required`` is set to ``True``, the method encodes the
|
|
1838
|
-
conjunction using the standard logic: :math:`x
|
|
1847
|
+
conjunction using the standard logic: :math:`x \\equiv
|
|
1839
1848
|
\\bigvee{y_i}`, if :math:`x` is the new auxiliary variable
|
|
1840
1849
|
encoding ``self`` and :math:`y_i` is the auxiliary variable
|
|
1841
1850
|
representing :math:`i`'s subformula.
|
|
@@ -2164,11 +2173,11 @@ class Implies(Formula):
|
|
|
2164
2173
|
If ``name_required`` is ``False``, the method recursively encodes
|
|
2165
2174
|
the left and right subformulas giving them names, say, :math:`x`
|
|
2166
2175
|
and :math:`y` respectively and the populates self's clauses with a
|
|
2167
|
-
single binary clause :math:`(\\neg{x}
|
|
2176
|
+
single binary clause :math:`(\\neg{x}\\lor y)`.
|
|
2168
2177
|
|
|
2169
2178
|
If ``name_required`` is set to ``True``, the method removes this
|
|
2170
2179
|
single clause and instead gives a name to the implication by
|
|
2171
|
-
Tseitin-encoding it, i.e. :math:`n
|
|
2180
|
+
Tseitin-encoding it, i.e. :math:`n \\equiv (\\neg{x}\\lor y)`.
|
|
2172
2181
|
|
|
2173
2182
|
:param name_required: whether or not a Tseitin variable is needed
|
|
2174
2183
|
:param name_required: bool
|
|
@@ -2222,10 +2231,10 @@ class Implies(Formula):
|
|
|
2222
2231
|
class Equals(Formula):
|
|
2223
2232
|
"""
|
|
2224
2233
|
Equivalence. Given a list of operands (subformulas) :math:`f_i`,
|
|
2225
|
-
:math:`i
|
|
2226
|
-
:math:`f_1
|
|
2227
|
-
f_n`. The list of operands *of
|
|
2228
|
-
arguments to the constructor.
|
|
2234
|
+
:math:`i \\in \\{1,\\ldots,n\\}, n \\in \\mathbb{N}`, it creates a
|
|
2235
|
+
formula :math:`f_1 \\leftrightarrow f_2
|
|
2236
|
+
\\leftrightarrow\\ldots\\leftrightarrow f_n`. The list of operands *of
|
|
2237
|
+
size at least 2* should be passed as arguments to the constructor.
|
|
2229
2238
|
|
|
2230
2239
|
Example:
|
|
2231
2240
|
|
|
@@ -2405,8 +2414,8 @@ class Equals(Formula):
|
|
|
2405
2414
|
If ``name_required`` is ``False``, the method recursively encodes
|
|
2406
2415
|
the subformulas and populates self's clauses with binary clauses
|
|
2407
2416
|
connecting two consecutive subformulas :math:`f_i` and
|
|
2408
|
-
:math:`f_{i+1}` by introducing two clauses :math:`(\\neg{f_i}
|
|
2409
|
-
f_{i+1})` and :math:`(f_i
|
|
2417
|
+
:math:`f_{i+1}` by introducing two clauses :math:`(\\neg{f_i}\\lor
|
|
2418
|
+
f_{i+1})` and :math:`(f_i\\lor\\neg{f_i+1})`.
|
|
2410
2419
|
|
|
2411
2420
|
If ``name_required`` is set to ``True``, the method introduces an
|
|
2412
2421
|
new auxiliary name for the equivalence term and clausifies it by
|
|
@@ -2468,10 +2477,10 @@ class Equals(Formula):
|
|
|
2468
2477
|
class XOr(Formula):
|
|
2469
2478
|
"""
|
|
2470
2479
|
Exclusive disjunction. Given a list of operands (subformulas)
|
|
2471
|
-
:math:`f_i`, :math:`i
|
|
2472
|
-
creates a formula :math:`f_1
|
|
2473
|
-
list of operands *of size at least 2* should be passed as
|
|
2474
|
-
the constructor.
|
|
2480
|
+
:math:`f_i`, :math:`i \\in \\{1,\\ldots,n\\}, n \\in \\mathbb{N}`, it
|
|
2481
|
+
creates a formula :math:`f_1 \\oplus f_2 \\oplus\\ldots\\oplus f_n`.
|
|
2482
|
+
The list of operands *of size at least 2* should be passed as
|
|
2483
|
+
arguments to the constructor.
|
|
2475
2484
|
|
|
2476
2485
|
Example:
|
|
2477
2486
|
|
|
@@ -2747,7 +2756,7 @@ class ITE(Formula):
|
|
|
2747
2756
|
"""
|
|
2748
2757
|
If-then-else operator. Given three operands (subformulas) :math:`x`,
|
|
2749
2758
|
:math:`y`, and :math:`z`, it creates a formula :math:`(x \\rightarrow
|
|
2750
|
-
y)
|
|
2759
|
+
y) \\land (\\neg{x} \\rightarrow z)`. The operands should be passed as
|
|
2751
2760
|
arguments to the constructor.
|
|
2752
2761
|
|
|
2753
2762
|
Example:
|
|
@@ -2886,12 +2895,12 @@ class ITE(Formula):
|
|
|
2886
2895
|
the ``cond``, ``cons1``, and ``cons2`` subformulas giving them
|
|
2887
2896
|
names, say, :math:`x`, :math:`y`, and :math:`z`, respectivela, and
|
|
2888
2897
|
the populates self's clauses with two binary clauses
|
|
2889
|
-
:math:`(\\neg{x}
|
|
2898
|
+
:math:`(\\neg{x}\\lor y)` and :math:`(x \\lor y)`.
|
|
2890
2899
|
|
|
2891
2900
|
If ``name_required`` is set to ``True``, the method removes these
|
|
2892
2901
|
clauses and instead gives a name to the ITE by Tseitin-encoding
|
|
2893
|
-
it, i.e. encoding :math:`n
|
|
2894
|
-
y)
|
|
2902
|
+
it, i.e. encoding :math:`n \\equiv \\left[(\\neg{x}\\lor
|
|
2903
|
+
y)\\land(x\\lor y)\\right]`.
|
|
2895
2904
|
|
|
2896
2905
|
:param name_required: whether or not a Tseitin variable is needed
|
|
2897
2906
|
:param name_required: bool
|
|
@@ -2984,6 +2993,7 @@ class CNF(Formula, object):
|
|
|
2984
2993
|
|
|
2985
2994
|
self.nv = 0
|
|
2986
2995
|
self.clauses = []
|
|
2996
|
+
self.encoded = []
|
|
2987
2997
|
self.comments = []
|
|
2988
2998
|
|
|
2989
2999
|
# this variable is required for integration with Formula
|
|
@@ -3574,13 +3584,14 @@ class CNF(Formula, object):
|
|
|
3574
3584
|
|
|
3575
3585
|
def negate(self, topv=None):
|
|
3576
3586
|
"""
|
|
3577
|
-
Given a CNF formula :math
|
|
3578
|
-
formula :math:`\\neg{
|
|
3579
|
-
encoded to CNF with the use of *auxiliary* Tseitin
|
|
3580
|
-
A new CNF formula is returned keeping all the
|
|
3581
|
-
variables that can be accessed through the
|
|
3582
|
-
All the literals used to encode the negation
|
|
3583
|
-
clauses can be accessed through the ``enclits``
|
|
3587
|
+
Given a CNF formula :math:`\\mathcal{F}`, this method creates a
|
|
3588
|
+
CNF formula :math:`\\neg{\\mathcal{F}}`. The negation of the
|
|
3589
|
+
formula is encoded to CNF with the use of *auxiliary* Tseitin
|
|
3590
|
+
variables [1]_. A new CNF formula is returned keeping all the
|
|
3591
|
+
newly introduced variables that can be accessed through the
|
|
3592
|
+
``auxvars`` variable. All the literals used to encode the negation
|
|
3593
|
+
of the original clauses can be accessed through the ``enclits``
|
|
3594
|
+
variable.
|
|
3584
3595
|
|
|
3585
3596
|
**Note** that the negation of each clause is encoded with one
|
|
3586
3597
|
auxiliary variable if it is not unit size. Otherwise, no auxiliary
|
|
@@ -4360,11 +4371,11 @@ class CNFPlus(CNF, object):
|
|
|
4360
4371
|
3 5 7 0
|
|
4361
4372
|
|
|
4362
4373
|
Each AtLeastK constraint is translated into an AtMostK constraint in
|
|
4363
|
-
the standard way: :math
|
|
4364
|
-
|
|
4365
|
-
are stored in variable ``atmosts``, each being a pair
|
|
4366
|
-
where ``lits`` is a list of literals in the sum and
|
|
4367
|
-
bound.
|
|
4374
|
+
the standard way: :math:`\\sum_{i=1}^{n}{x_i}\\geq k \\leftrightarrow
|
|
4375
|
+
\\sum_{i=1}^{n}{\\neg{x_i}}\\leq (n-k)`. Internally, AtMostK
|
|
4376
|
+
constraints are stored in variable ``atmosts``, each being a pair
|
|
4377
|
+
``(lits, k)``, where ``lits`` is a list of literals in the sum and
|
|
4378
|
+
``k`` is the upper bound.
|
|
4368
4379
|
|
|
4369
4380
|
Example:
|
|
4370
4381
|
|
|
@@ -4885,10 +4896,11 @@ class WCNFPlus(WCNF, object):
|
|
|
4885
4896
|
i.e. soft cardinality constraints are currently *not supported*.
|
|
4886
4897
|
|
|
4887
4898
|
Each AtLeastK constraint is translated into an AtMostK constraint in
|
|
4888
|
-
the standard way: :math
|
|
4889
|
-
|
|
4890
|
-
are stored in variable ``atms``, each being a pair
|
|
4891
|
-
``lits`` is a list of literals in the sum and
|
|
4899
|
+
the standard way: :math:`\\sum_{i=1}^{n}{x_i}\\geq k \\leftrightarrow
|
|
4900
|
+
\\sum_{i=1}^{n}{\\neg{x_i}}\\leq (n-k)`. Internally, AtMostK
|
|
4901
|
+
constraints are stored in variable ``atms``, each being a pair
|
|
4902
|
+
``(lits, k)``, where ``lits`` is a list of literals in the sum and
|
|
4903
|
+
``k`` is the upper bound.
|
|
4892
4904
|
|
|
4893
4905
|
Example:
|
|
4894
4906
|
|
|
@@ -49,9 +49,9 @@
|
|
|
49
49
|
Pseudo-Boolean Constraints into CNF*. SAT 2015. pp. 9-16
|
|
50
50
|
|
|
51
51
|
A *pseudo-Boolean constraint* is a constraint of the form:
|
|
52
|
-
:math
|
|
53
|
-
:math:`a_i
|
|
54
|
-
:math:`y_i
|
|
52
|
+
:math:`\\left(\\sum_{i=1}^n{a_i\\cdot x_i}\\right)\\circ k`, where
|
|
53
|
+
:math:`a_i\\in\\mathbb{N}`, :math:`x_i\\in\{y_i,\\neg{y_i}\\}`,
|
|
54
|
+
:math:`y_i\\in\\mathbb{B}`, and :math:`\\circ\\in\\{\\leq,=,\\geq\\}`.
|
|
55
55
|
Pseudo-Boolean constraints arise in a number of important practical
|
|
56
56
|
applications. Thus, several *encodings* of pseudo-Boolean constraints into
|
|
57
57
|
CNF formulas are known [2]_. The list of pseudo-Boolean encodings
|
|
@@ -362,8 +362,9 @@ class PBEnc(object):
|
|
|
362
362
|
"""
|
|
363
363
|
This method can be used for creating a CNF encoding of a LEQ
|
|
364
364
|
(weighted AtMostK) constraint, i.e. of
|
|
365
|
-
:math
|
|
366
|
-
clauses is returned as an object of class
|
|
365
|
+
:math:`\\sum_{i=1}^{n}{a_i\\cdot x_i}\\leq k`. The resulting set
|
|
366
|
+
of clauses is returned as an object of class
|
|
367
|
+
:class:`.formula.CNF`.
|
|
367
368
|
|
|
368
369
|
The input list of literals can contain either integers or pairs
|
|
369
370
|
``(l, w)``, where ``l`` is an integer literal and ``w`` is an
|
|
@@ -409,8 +410,8 @@ class PBEnc(object):
|
|
|
409
410
|
"""
|
|
410
411
|
This method can be used for creating a CNF encoding of a GEQ
|
|
411
412
|
(weighted AtLeastK) constraint, i.e. of
|
|
412
|
-
:math
|
|
413
|
-
arguments and the return type with method :meth:`PBEnc.leq`.
|
|
413
|
+
:math:`\\sum_{i=1}^{n}{a_i\\cdot x_i}\\geq k`. The method shares
|
|
414
|
+
the arguments and the return type with method :meth:`PBEnc.leq`.
|
|
414
415
|
Please, see it for details.
|
|
415
416
|
"""
|
|
416
417
|
|
|
@@ -432,7 +433,7 @@ class PBEnc(object):
|
|
|
432
433
|
encoding=EncType.best):
|
|
433
434
|
"""
|
|
434
435
|
This method can be used for creating a CNF encoding of a weighted
|
|
435
|
-
EqualsK constraint, i.e. of :math
|
|
436
|
+
EqualsK constraint, i.e. of :math:`\\sum_{i=1}^{n}{a_i\\cdot x_i}=
|
|
436
437
|
k`. The method shares the arguments and the return type with
|
|
437
438
|
method :meth:`PBEnc.leq`. Please, see it for details.
|
|
438
439
|
"""
|
|
@@ -119,12 +119,12 @@
|
|
|
119
119
|
|
|
120
120
|
PySAT supports both non-incremental and incremental SAT solving.
|
|
121
121
|
Incrementality can be achieved with the use of the MiniSat-like
|
|
122
|
-
*assumption-based* interface [2]_. It can be helpful if multiple calls to
|
|
123
|
-
SAT solver are needed for the same formula using different sets of
|
|
122
|
+
*assumption-based* interface [2]_. It can be helpful if multiple calls to
|
|
123
|
+
a SAT solver are needed for the same formula using different sets of
|
|
124
124
|
"assumptions", e.g. when doing consecutive SAT calls for formula
|
|
125
|
-
:math
|
|
126
|
-
:math
|
|
127
|
-
:math:`a_{l_k}` is an assumption literal.
|
|
125
|
+
:math:`\\mathcal{F}\\land (a_{i_1}\\land\\ldots\\land a_{i_1+j_1})` and
|
|
126
|
+
:math:`\\mathcal{F}\\land (a_{i_2}\\land\\ldots\\land a_{i_2+j_2})`, where
|
|
127
|
+
every :math:`a_{l_k}` is an assumption literal.
|
|
128
128
|
|
|
129
129
|
There are several advantages of using assumptions: (1) it enables one to
|
|
130
130
|
*keep and reuse* the clauses learnt during previous SAT calls at a later
|
|
@@ -404,7 +404,7 @@ class Solver(object):
|
|
|
404
404
|
"""
|
|
405
405
|
|
|
406
406
|
# checking keyword arguments
|
|
407
|
-
kwallowed = set(['incr', 'with_proof', 'warm_start'])
|
|
407
|
+
kwallowed = set(['incr', 'with_proof', 'warm_start', 'native_card'])
|
|
408
408
|
for a in kwargs:
|
|
409
409
|
if a not in kwallowed:
|
|
410
410
|
raise TypeError('Unexpected keyword argument \'{0}\''.format(a))
|
|
@@ -735,7 +735,7 @@ class Solver(object):
|
|
|
735
735
|
.. code-block:: python
|
|
736
736
|
|
|
737
737
|
>>> from pysat.solvers import Solver
|
|
738
|
-
>>> s = Solver(bootstrap_with=[[-1, 2], [-2, 3])
|
|
738
|
+
>>> s = Solver(bootstrap_with=[[-1, 2], [-2, 3]])
|
|
739
739
|
>>> s.solve()
|
|
740
740
|
True
|
|
741
741
|
>>> s.solve(assumptions=[1, -3])
|
|
@@ -1349,14 +1349,14 @@ class Solver(object):
|
|
|
1349
1349
|
**Note that most of the solvers do not support native AtMostK
|
|
1350
1350
|
constraints**.
|
|
1351
1351
|
|
|
1352
|
-
An AtMostK constraint is :math
|
|
1352
|
+
An AtMostK constraint is :math:`\\sum_{i=1}^{n}{x_i}\\leq k`. A
|
|
1353
1353
|
native AtMostK constraint should be given as a pair ``lits`` and
|
|
1354
1354
|
``k``, where ``lits`` is a list of literals in the sum.
|
|
1355
1355
|
|
|
1356
1356
|
Also, besides *unweighted* AtMostK constraints, some solvers (see
|
|
1357
1357
|
:class:`Cadical195`) support their weighted counterparts, i.e.
|
|
1358
|
-
pseudo-Boolean constraints of the form :math
|
|
1359
|
-
|
|
1358
|
+
pseudo-Boolean constraints of the form :math:`\\sum_{i=1}^{n}{w_i
|
|
1359
|
+
\\cdot x_i}\\leq k`. The weights of the literals can be specified
|
|
1360
1360
|
using the argument ``weights``.
|
|
1361
1361
|
|
|
1362
1362
|
:param lits: a list of literals
|
|
@@ -85,8 +85,9 @@ tests/test_atmost1.py
|
|
|
85
85
|
tests/test_atmostk.py
|
|
86
86
|
tests/test_boolengine.py
|
|
87
87
|
tests/test_clausification.py
|
|
88
|
-
tests/
|
|
88
|
+
tests/test_cnf.py
|
|
89
89
|
tests/test_equals1.py
|
|
90
|
+
tests/test_formula_unique.py
|
|
90
91
|
tests/test_process.py
|
|
91
92
|
tests/test_propagate.py
|
|
92
93
|
tests/test_unique_model.py
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import pytest
|
|
1
2
|
from pysat.card import *
|
|
2
3
|
from pysat.formula import CNFPlus
|
|
3
4
|
from pysat.solvers import Solver, SolverNames
|
|
@@ -27,7 +28,17 @@ cnf1.append(range(1, 6)) # at least 1
|
|
|
27
28
|
cnf2 = CardEnc.atmost(lits=range(1, 6), bound=1, encoding=EncType.seqcounter)
|
|
28
29
|
cnf2.append(range(1, 6)) # at least 1
|
|
29
30
|
|
|
31
|
+
def test_cnf():
|
|
32
|
+
cnf = CNF()
|
|
33
|
+
cnf_copy = cnf.copy()
|
|
34
|
+
# TODO: check actual values of the copy for sanity.
|
|
35
|
+
|
|
30
36
|
def test_cnfplus():
|
|
37
|
+
cnfplus = CNFPlus()
|
|
38
|
+
cnfplus_copy = cnfplus.copy()
|
|
39
|
+
# TODO: check actual values of the copy for sanity.
|
|
40
|
+
|
|
41
|
+
def test_cnfplus_solvers():
|
|
31
42
|
# testing cnf1:
|
|
32
43
|
for name in solvers:
|
|
33
44
|
if name not in ('minicard', 'gluecard30', 'gluecard41'):
|
|
@@ -59,7 +70,7 @@ def test_cnfplus():
|
|
|
59
70
|
pass
|
|
60
71
|
assert i == 5, 'there should be 5 models'
|
|
61
72
|
|
|
62
|
-
def
|
|
73
|
+
def test_cnf_solvers():
|
|
63
74
|
# testing cnf2
|
|
64
75
|
for name in solvers:
|
|
65
76
|
with Solver(name=name, bootstrap_with=cnf2) as s:
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from pysat.formula import *
|
|
2
|
+
from itertools import permutations
|
|
3
|
+
|
|
4
|
+
def test_atom_uniqueness():
|
|
5
|
+
x1, x2 = Atom('x'), Atom('x') # same atom
|
|
6
|
+
z = Atom('z') # a different atom
|
|
7
|
+
|
|
8
|
+
assert x1 is x2, 'Atoms should be the same object'
|
|
9
|
+
assert x1 is not z, 'Atoms should be different objects'
|
|
10
|
+
|
|
11
|
+
def test_2and_uniqueness():
|
|
12
|
+
x1, x2 = Atom('x'), Atom('x') # same atom
|
|
13
|
+
y = Atom('y') # a different atom
|
|
14
|
+
|
|
15
|
+
a = And(x1, y)
|
|
16
|
+
b = And(y, x1)
|
|
17
|
+
c = And(x2, y)
|
|
18
|
+
d = And(y, x2)
|
|
19
|
+
|
|
20
|
+
assert id(a) == id(b) == id(c) == id(d), 'All 2-and\'s should be the same object'
|
|
21
|
+
|
|
22
|
+
def test_3and_uniqueness():
|
|
23
|
+
x, y, z = Atom('x'), Atom('y'), Atom('z')
|
|
24
|
+
|
|
25
|
+
a = And(x, y, z)
|
|
26
|
+
|
|
27
|
+
for comb in permutations([x, y, z]):
|
|
28
|
+
assert And(*comb) is a, 'All 3-and\'s should be the same object'
|
|
29
|
+
assert And(comb) is a, 'All 3-and\'s should be the same object'
|
|
30
|
+
|
|
31
|
+
def test_3or_uniqueness():
|
|
32
|
+
x, y, z = Atom('x'), Atom('y'), Atom('z')
|
|
33
|
+
|
|
34
|
+
a = Or(x, y, z)
|
|
35
|
+
|
|
36
|
+
for comb in permutations([x, y, z]):
|
|
37
|
+
assert Or(*comb) is a, 'All 3-and\'s should be the same object'
|
|
38
|
+
assert Or(comb) is a, 'All 3-and\'s should be the same object'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|