python-sat 1.8.dev25__cp310-cp310-musllinux_1_2_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pycard.cpython-310-x86_64-linux-gnu.so +0 -0
- pysat/__init__.py +24 -0
- pysat/_fileio.py +209 -0
- pysat/_utils.py +58 -0
- pysat/allies/__init__.py +0 -0
- pysat/allies/approxmc.py +385 -0
- pysat/allies/unigen.py +435 -0
- pysat/card.py +802 -0
- pysat/engines.py +1302 -0
- pysat/examples/__init__.py +0 -0
- pysat/examples/bbscan.py +663 -0
- pysat/examples/bica.py +691 -0
- pysat/examples/fm.py +527 -0
- pysat/examples/genhard.py +516 -0
- pysat/examples/hitman.py +653 -0
- pysat/examples/lbx.py +638 -0
- pysat/examples/lsu.py +496 -0
- pysat/examples/mcsls.py +610 -0
- pysat/examples/models.py +189 -0
- pysat/examples/musx.py +344 -0
- pysat/examples/optux.py +710 -0
- pysat/examples/primer.py +620 -0
- pysat/examples/rc2.py +1858 -0
- pysat/examples/usage.py +63 -0
- pysat/formula.py +5619 -0
- pysat/pb.py +463 -0
- pysat/process.py +363 -0
- pysat/solvers.py +7591 -0
- pysolvers.cpython-310-x86_64-linux-gnu.so +0 -0
- python_sat-1.8.dev25.data/scripts/approxmc.py +385 -0
- python_sat-1.8.dev25.data/scripts/bbscan.py +663 -0
- python_sat-1.8.dev25.data/scripts/bica.py +691 -0
- python_sat-1.8.dev25.data/scripts/fm.py +527 -0
- python_sat-1.8.dev25.data/scripts/genhard.py +516 -0
- python_sat-1.8.dev25.data/scripts/lbx.py +638 -0
- python_sat-1.8.dev25.data/scripts/lsu.py +496 -0
- python_sat-1.8.dev25.data/scripts/mcsls.py +610 -0
- python_sat-1.8.dev25.data/scripts/models.py +189 -0
- python_sat-1.8.dev25.data/scripts/musx.py +344 -0
- python_sat-1.8.dev25.data/scripts/optux.py +710 -0
- python_sat-1.8.dev25.data/scripts/primer.py +620 -0
- python_sat-1.8.dev25.data/scripts/rc2.py +1858 -0
- python_sat-1.8.dev25.data/scripts/unigen.py +435 -0
- python_sat-1.8.dev25.dist-info/METADATA +45 -0
- python_sat-1.8.dev25.dist-info/RECORD +50 -0
- python_sat-1.8.dev25.dist-info/WHEEL +5 -0
- python_sat-1.8.dev25.dist-info/licenses/LICENSE.txt +21 -0
- python_sat-1.8.dev25.dist-info/top_level.txt +3 -0
- python_sat.libs/libgcc_s-0cd532bd.so.1 +0 -0
- python_sat.libs/libstdc++-5d72f927.so.6.0.33 +0 -0
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
#!python
|
|
2
|
+
#-*- coding:utf-8 -*-
|
|
3
|
+
##
|
|
4
|
+
## genhard.py
|
|
5
|
+
##
|
|
6
|
+
## Created on: Mar 6, 2018
|
|
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
|
+
CB
|
|
20
|
+
GT
|
|
21
|
+
PAR
|
|
22
|
+
PHP
|
|
23
|
+
|
|
24
|
+
==================
|
|
25
|
+
Module description
|
|
26
|
+
==================
|
|
27
|
+
|
|
28
|
+
This module is designed to provide a few examples illustrating how PySAT
|
|
29
|
+
can be used for encoding practical problems into CNF formulas. These
|
|
30
|
+
include combinatorial principles that are widely studied from the
|
|
31
|
+
propositional proof complexity perspective. Namely, encodings for the
|
|
32
|
+
following principles are implemented: *pigeonhole principle* (:class:`PHP`)
|
|
33
|
+
[1]_, *ordering (greater-than) principle* (:class:`GT`) [2]_, *mutilated
|
|
34
|
+
chessboard principle* (:class:`CB`) [3]_, and *parity principle*
|
|
35
|
+
(:class:`PAR`) [4]_.
|
|
36
|
+
|
|
37
|
+
.. [1] Stephen A. Cook, Robert A. Reckhow. *The Relative Efficiency of
|
|
38
|
+
Propositional Proof Systems*. J. Symb. Log. 44(1). 1979. pp. 36-50
|
|
39
|
+
|
|
40
|
+
.. [2] Balakrishnan Krishnamurthy. *Short Proofs for Tricky Formulas*. Acta
|
|
41
|
+
Informatica 22(3). 1985. pp. 253-275
|
|
42
|
+
|
|
43
|
+
.. [3] Michael Alekhnovich. *Mutilated Chessboard Problem Is Exponentially
|
|
44
|
+
Hard For Resolution*. Theor. Comput. Sci. 310(1-3). 2004. pp. 513-525
|
|
45
|
+
|
|
46
|
+
.. [4] Miklós Ajtai. *Parity And The Pigeonhole Principle*. Feasible
|
|
47
|
+
Mathematics. 1990. pp. 1–24
|
|
48
|
+
|
|
49
|
+
The module can be used as an executable (the list of available command-line
|
|
50
|
+
options can be shown using ``genhard.py -h``) in the following way
|
|
51
|
+
|
|
52
|
+
::
|
|
53
|
+
|
|
54
|
+
$ genhard.py -t php -n 3 -v
|
|
55
|
+
c PHP formula for 4 pigeons and 3 holes
|
|
56
|
+
c (pigeon, hole) pair: (1, 1); bool var: 1
|
|
57
|
+
c (pigeon, hole) pair: (1, 2); bool var: 2
|
|
58
|
+
c (pigeon, hole) pair: (1, 3); bool var: 3
|
|
59
|
+
c (pigeon, hole) pair: (2, 1); bool var: 4
|
|
60
|
+
c (pigeon, hole) pair: (2, 2); bool var: 5
|
|
61
|
+
c (pigeon, hole) pair: (2, 3); bool var: 6
|
|
62
|
+
c (pigeon, hole) pair: (3, 1); bool var: 7
|
|
63
|
+
c (pigeon, hole) pair: (3, 2); bool var: 8
|
|
64
|
+
c (pigeon, hole) pair: (3, 3); bool var: 9
|
|
65
|
+
c (pigeon, hole) pair: (4, 1); bool var: 10
|
|
66
|
+
c (pigeon, hole) pair: (4, 2); bool var: 11
|
|
67
|
+
c (pigeon, hole) pair: (4, 3); bool var: 12
|
|
68
|
+
p cnf 12 22
|
|
69
|
+
1 2 3 0
|
|
70
|
+
4 5 6 0
|
|
71
|
+
7 8 9 0
|
|
72
|
+
10 11 12 0
|
|
73
|
+
-1 -4 0
|
|
74
|
+
-1 -7 0
|
|
75
|
+
-1 -10 0
|
|
76
|
+
-4 -7 0
|
|
77
|
+
-4 -10 0
|
|
78
|
+
-7 -10 0
|
|
79
|
+
-2 -5 0
|
|
80
|
+
-2 -8 0
|
|
81
|
+
-2 -11 0
|
|
82
|
+
-5 -8 0
|
|
83
|
+
-5 -11 0
|
|
84
|
+
-8 -11 0
|
|
85
|
+
-3 -6 0
|
|
86
|
+
-3 -9 0
|
|
87
|
+
-3 -12 0
|
|
88
|
+
-6 -9 0
|
|
89
|
+
-6 -12 0
|
|
90
|
+
-9 -12 0
|
|
91
|
+
|
|
92
|
+
Alternatively, each of the considered problem encoders can be accessed with
|
|
93
|
+
the use of the standard ``import`` interface of Python, e.g.
|
|
94
|
+
|
|
95
|
+
.. code-block:: python
|
|
96
|
+
|
|
97
|
+
>>> from pysat.examples.genhard import PHP
|
|
98
|
+
>>>
|
|
99
|
+
>>> cnf = PHP(3)
|
|
100
|
+
>>> print(cnf.nv, len(cnf.clauses))
|
|
101
|
+
12 22
|
|
102
|
+
|
|
103
|
+
Given this example, observe that classes :class:`PHP`, :class:`GT`,
|
|
104
|
+
:class:`CB`, and :class:`PAR` inherit from class
|
|
105
|
+
:class:`pysat.formula.CNF` and, thus, their corresponding clauses can
|
|
106
|
+
accessed through variable ``.clauses``.
|
|
107
|
+
|
|
108
|
+
==============
|
|
109
|
+
Module details
|
|
110
|
+
==============
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
#
|
|
114
|
+
#==============================================================================
|
|
115
|
+
from __future__ import print_function
|
|
116
|
+
import collections
|
|
117
|
+
import getopt
|
|
118
|
+
import itertools
|
|
119
|
+
import os
|
|
120
|
+
from pysat.card import *
|
|
121
|
+
from pysat.formula import IDPool, CNF
|
|
122
|
+
from six.moves import range
|
|
123
|
+
import sys
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
#
|
|
127
|
+
#==============================================================================
|
|
128
|
+
class PHP(CNF, object):
|
|
129
|
+
"""
|
|
130
|
+
Generator of :math:`k` pigeonhole principle (:math:`k`-PHP) formulas.
|
|
131
|
+
Given integer parameters :math:`m` and :math:`k`, the :math:`k`
|
|
132
|
+
pigeonhole principle states that if :math:`k\\cdot m+1` pigeons are
|
|
133
|
+
distributes by :math:`m` holes, then at least one hole contains more
|
|
134
|
+
than :math:`k` pigeons.
|
|
135
|
+
|
|
136
|
+
Note that if :math:`k` is 1, the principle degenerates to the
|
|
137
|
+
formulation of the original pigeonhole principle stating that
|
|
138
|
+
:math:`m+1` pigeons cannot be distributed by :math:`m` holes.
|
|
139
|
+
|
|
140
|
+
Assume that a Boolean variable :math:`x_{ij}` encodes that pigeon
|
|
141
|
+
:math:`i` resides in hole :math:`j`. Then a PHP formula can be seen as
|
|
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
|
+
m+1,j})}`. Here each :math:`\\textsf{AtLeast1}` constraint forces every
|
|
146
|
+
pigeon to be placed into at least one hole while each
|
|
147
|
+
:math:`\\textsf{AtMost}k` constraint allows the corresponding hole to
|
|
148
|
+
have at most :math:`k` pigeons. The overall PHP formulas are
|
|
149
|
+
unsatisfiable.
|
|
150
|
+
|
|
151
|
+
PHP formulas are well-known [6]_ to be hard for resolution.
|
|
152
|
+
|
|
153
|
+
.. [6] Armin Haken. *The Intractability of Resolution*. Theor. Comput.
|
|
154
|
+
Sci. 39. 1985. pp. 297-308
|
|
155
|
+
|
|
156
|
+
:param nof_holes: number of holes (:math:`n`)
|
|
157
|
+
:param kval: multiplier :math:`k`
|
|
158
|
+
:param topv: current top variable identifier
|
|
159
|
+
:param verb: defines whether or not the encoder is verbose
|
|
160
|
+
|
|
161
|
+
:type nof_holes: int
|
|
162
|
+
:type kval: int
|
|
163
|
+
:type topv: int
|
|
164
|
+
:type verb: bool
|
|
165
|
+
|
|
166
|
+
:return: object of class :class:`pysat.formula.CNF`.
|
|
167
|
+
"""
|
|
168
|
+
|
|
169
|
+
def __init__(self, nof_holes, kval=1, topv=0, verb=False):
|
|
170
|
+
"""
|
|
171
|
+
Constructor.
|
|
172
|
+
"""
|
|
173
|
+
|
|
174
|
+
# initializing CNF's internal parameters
|
|
175
|
+
super(PHP, self).__init__()
|
|
176
|
+
|
|
177
|
+
# initializing the pool of variable ids
|
|
178
|
+
vpool = IDPool(start_from=topv + 1)
|
|
179
|
+
var = lambda i, j: vpool.id('v_{0}_{1}'.format(i, j))
|
|
180
|
+
|
|
181
|
+
# placing all pigeons into holes
|
|
182
|
+
for i in range(1, kval * nof_holes + 2):
|
|
183
|
+
self.append([var(i, j) for j in range(1, nof_holes + 1)])
|
|
184
|
+
|
|
185
|
+
# there cannot be more than k pigeons in a hole
|
|
186
|
+
pigeons = range(1, kval * nof_holes + 2)
|
|
187
|
+
for j in range(1, nof_holes + 1):
|
|
188
|
+
for comb in itertools.combinations(pigeons, kval + 1):
|
|
189
|
+
self.append([-var(i, j) for i in comb])
|
|
190
|
+
|
|
191
|
+
if verb:
|
|
192
|
+
head = 'c {0}PHP formula for'.format('' if kval == 1 else str(kval) + '-')
|
|
193
|
+
head += ' {0} pigeons and {1} holes'.format(kval * nof_holes + 1, nof_holes)
|
|
194
|
+
self.comments.append(head)
|
|
195
|
+
|
|
196
|
+
for i in range(1, kval * nof_holes + 2):
|
|
197
|
+
for j in range(1, nof_holes + 1):
|
|
198
|
+
self.comments.append('c (pigeon, hole) pair: ({0}, {1}); bool var: {2}'.format(i, j, var(i, j)))
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
#
|
|
202
|
+
#==============================================================================
|
|
203
|
+
class GT(CNF, object):
|
|
204
|
+
"""
|
|
205
|
+
Generator of ordering (or *greater than*, GT) principle formulas. Given
|
|
206
|
+
an integer parameter :math:`n`, the principle states that any partial
|
|
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.
|
|
218
|
+
|
|
219
|
+
GT formulas were originally conjectured [2]_ to be hard for resolution.
|
|
220
|
+
However, [5]_ proved the existence of a polynomial size resolution
|
|
221
|
+
refutation for GT formulas.
|
|
222
|
+
|
|
223
|
+
.. [5] Gunnar Stålmarck. *Short Resolution Proofs for a Sequence of
|
|
224
|
+
Tricky Formulas*. Acta Informatica. 33(3). 1996. pp. 277-280
|
|
225
|
+
|
|
226
|
+
:param size: number of elements (:math:`n`)
|
|
227
|
+
:param topv: current top variable identifier
|
|
228
|
+
:param verb: defines whether or not the encoder is verbose
|
|
229
|
+
|
|
230
|
+
:type size: int
|
|
231
|
+
:type topv: int
|
|
232
|
+
:type verb: bool
|
|
233
|
+
|
|
234
|
+
:return: object of class :class:`pysat.formula.CNF`.
|
|
235
|
+
"""
|
|
236
|
+
|
|
237
|
+
def __init__(self, size, topv=0, verb=False):
|
|
238
|
+
"""
|
|
239
|
+
Constructor.
|
|
240
|
+
"""
|
|
241
|
+
|
|
242
|
+
# initializing CNF's internal parameters
|
|
243
|
+
super(GT, self).__init__()
|
|
244
|
+
|
|
245
|
+
# initializing the pool of variable ids
|
|
246
|
+
vpool = IDPool(start_from=topv + 1)
|
|
247
|
+
var = lambda i, j: vpool.id('v_{0}_{1}'.format(i, j))
|
|
248
|
+
|
|
249
|
+
# anti-symmetric relation clauses
|
|
250
|
+
for i in range(1, size):
|
|
251
|
+
for j in range(i + 1, size + 1):
|
|
252
|
+
self.append([-var(i, j), -var(j, i)])
|
|
253
|
+
|
|
254
|
+
# transitive relation clauses
|
|
255
|
+
for i in range(1, size + 1):
|
|
256
|
+
for j in range(1, size + 1):
|
|
257
|
+
if j != i:
|
|
258
|
+
for k in range(1, size + 1):
|
|
259
|
+
if k != i and k != j:
|
|
260
|
+
self.append([-var(i, j), -var(j, k), var(i, k)])
|
|
261
|
+
|
|
262
|
+
# successor clauses
|
|
263
|
+
for j in range(1, size + 1):
|
|
264
|
+
self.append([var(k, j) for k in range(1, size + 1) if k != j])
|
|
265
|
+
|
|
266
|
+
if verb:
|
|
267
|
+
self.comments.append('c GT formula for {0} elements'.format(size))
|
|
268
|
+
for i in range(1, size + 1):
|
|
269
|
+
for j in range(1, size + 1):
|
|
270
|
+
if i != j:
|
|
271
|
+
self.comments.append('c orig pair: {0}; bool var: {1}'.format((i, j), var(i, j)))
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
#
|
|
275
|
+
#==============================================================================
|
|
276
|
+
class CB(CNF, object):
|
|
277
|
+
"""
|
|
278
|
+
Mutilated chessboard principle (CB). Given an integer :math:`n`, the
|
|
279
|
+
principle states that it is impossible to cover a chessboard of size
|
|
280
|
+
:math:`2n\\cdot 2n` by domino tiles if two diagonally opposite corners
|
|
281
|
+
of the chessboard are removed.
|
|
282
|
+
|
|
283
|
+
Note that the chessboard has :math:`4n^2-2` cells. Introduce a Boolean
|
|
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)
|
|
287
|
+
:math:`(\\neg{x_{ji} \\vee \\neg{x_{ki}}})` for every :math:`i,j \\neq
|
|
288
|
+
k` meaning that no more than one adjacent cell can be paired with the
|
|
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.
|
|
292
|
+
|
|
293
|
+
Clearly, since the two diagonal corners are removed, the formula is
|
|
294
|
+
unsatisfiable. Also note the following. Assuming that the number of
|
|
295
|
+
black cells is larger than the number of the white ones, CB formulas
|
|
296
|
+
are unsatisfiable even if only a half of the formula is present, e.g.
|
|
297
|
+
when :math:`\\textsf{AtMost1}` constraints are formulated only for the
|
|
298
|
+
white cells while the :math:`\\textsf{AtLeast1}` constraints are
|
|
299
|
+
formulated only for the black cells. Depending on the value of
|
|
300
|
+
parameter ``exhaustive`` the encoder applies the *complete* or
|
|
301
|
+
*partial* formulation of the problem.
|
|
302
|
+
|
|
303
|
+
Mutilated chessboard principle is known to be hard for resolution [3]_.
|
|
304
|
+
|
|
305
|
+
:param size: problem size (:math:`n`)
|
|
306
|
+
:param exhaustive: encode the problem exhaustively
|
|
307
|
+
:param topv: current top variable identifier
|
|
308
|
+
:param verb: defines whether or not the encoder is verbose
|
|
309
|
+
|
|
310
|
+
:type size: int
|
|
311
|
+
:type exhaustive: bool
|
|
312
|
+
:type topv: int
|
|
313
|
+
:type verb: bool
|
|
314
|
+
|
|
315
|
+
:return: object of class :class:`pysat.formula.CNF`.
|
|
316
|
+
"""
|
|
317
|
+
|
|
318
|
+
def __init__(self, size, exhaustive=False, topv=0, verb=False):
|
|
319
|
+
"""
|
|
320
|
+
Constructor.
|
|
321
|
+
"""
|
|
322
|
+
|
|
323
|
+
# initializing CNF's internal parameters
|
|
324
|
+
super(CB, self).__init__()
|
|
325
|
+
|
|
326
|
+
# cell number
|
|
327
|
+
cell = lambda i, j: (i - 1) * 2 * size + j
|
|
328
|
+
|
|
329
|
+
# initializing the pool of variable ids
|
|
330
|
+
vpool = IDPool(start_from=topv + 1)
|
|
331
|
+
var = lambda c1, c2: vpool.id('edge: ({0}, {1})'.format(min(c1, c2), max(c1, c2)))
|
|
332
|
+
|
|
333
|
+
for i in range(1, 2 * size + 1):
|
|
334
|
+
for j in range(1, 2 * size + 1):
|
|
335
|
+
adj = []
|
|
336
|
+
|
|
337
|
+
# current cell
|
|
338
|
+
c = cell(i, j)
|
|
339
|
+
|
|
340
|
+
# removing first and last cells (they are white)
|
|
341
|
+
if c in (1, 4 * size * size):
|
|
342
|
+
continue
|
|
343
|
+
|
|
344
|
+
# each cell has 2 <= k <= 4 adjacents
|
|
345
|
+
if i > 1 and cell(i - 1, j) != 1:
|
|
346
|
+
adj.append(var(c, cell(i - 1, j)))
|
|
347
|
+
|
|
348
|
+
if j > 1 and cell(i, j - 1) != 1:
|
|
349
|
+
adj.append(var(c, cell(i, j - 1)))
|
|
350
|
+
|
|
351
|
+
if i < 2 * size and cell(i + 1, j) != 4 * size * size:
|
|
352
|
+
adj.append(var(c, cell(i + 1, j)))
|
|
353
|
+
|
|
354
|
+
if j < 2 * size and cell(i, j + 1) != 4 * size * size:
|
|
355
|
+
adj.append(var(c, cell(i, j + 1)))
|
|
356
|
+
|
|
357
|
+
if not adj: # when n == 1, no clauses will be added
|
|
358
|
+
continue
|
|
359
|
+
|
|
360
|
+
# adding equals1 constraint for black and white cells
|
|
361
|
+
if exhaustive:
|
|
362
|
+
cnf = CardEnc.equals(lits=adj, bound=1, encoding=EncType.pairwise)
|
|
363
|
+
self.extend(cnf.clauses)
|
|
364
|
+
else:
|
|
365
|
+
# atmost1 constraint for white cells
|
|
366
|
+
if i % 2 and c % 2 or i % 2 == 0 and c % 2 == 0:
|
|
367
|
+
am1 = CardEnc.atmost(lits=adj, bound=1, encoding=EncType.pairwise)
|
|
368
|
+
self.extend(am1.clauses)
|
|
369
|
+
else: # atleast1 constrant for black cells
|
|
370
|
+
self.append(adj)
|
|
371
|
+
|
|
372
|
+
if verb:
|
|
373
|
+
head = 'c CB formula for the chessboard of size {0}x{0}'.format(2 * size)
|
|
374
|
+
head += '\nc The encoding is {0}exhaustive'.format('' if exhaustive else 'not ')
|
|
375
|
+
self.comments.append(head)
|
|
376
|
+
|
|
377
|
+
for v in range(1, vpool.top + 1):
|
|
378
|
+
self.comments.append('c {0}; bool var: {1}'.format(vpool.obj(v), v))
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
#
|
|
382
|
+
#==============================================================================
|
|
383
|
+
class PAR(CNF, object):
|
|
384
|
+
"""
|
|
385
|
+
Generator of the parity principle (PAR) formulas. Given an integer
|
|
386
|
+
parameter :math:`n`, the principle states that no graph on :math:`2n+1`
|
|
387
|
+
nodes consists of a complete perfect matching.
|
|
388
|
+
|
|
389
|
+
The encoding of the parity principle uses :math:`\\binom{2n+1}{2}`
|
|
390
|
+
variables :math:`x_{ij},i \\neq j`. If variable :math:`x_{ij}` is
|
|
391
|
+
*true*, then there is an edge between nodes :math:`i` and :math:`j`.
|
|
392
|
+
The formula consists of the following clauses: :math:`(\\vee_{j \\neq
|
|
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]`.
|
|
395
|
+
|
|
396
|
+
The parity principle is known to be hard for resolution [4]_.
|
|
397
|
+
|
|
398
|
+
:param size: problem size (:math:`n`)
|
|
399
|
+
:param topv: current top variable identifier
|
|
400
|
+
:param verb: defines whether or not the encoder is verbose
|
|
401
|
+
|
|
402
|
+
:type size: int
|
|
403
|
+
:type topv: int
|
|
404
|
+
:type verb: bool
|
|
405
|
+
|
|
406
|
+
:return: object of class :class:`pysat.formula.CNF`.
|
|
407
|
+
"""
|
|
408
|
+
|
|
409
|
+
def __init__(self, size, topv=0, verb=False):
|
|
410
|
+
"""
|
|
411
|
+
Constructor.
|
|
412
|
+
"""
|
|
413
|
+
|
|
414
|
+
# initializing CNF's internal parameters
|
|
415
|
+
super(PAR, self).__init__()
|
|
416
|
+
|
|
417
|
+
# initializing the pool of variable ids
|
|
418
|
+
vpool = IDPool(start_from=topv + 1)
|
|
419
|
+
var = lambda i, j: vpool.id('v_{0}_{1}'.format(min(i, j), max(i, j)))
|
|
420
|
+
|
|
421
|
+
for i in range(1, 2 * size + 2):
|
|
422
|
+
self.append([var(i, j) for j in range(1, 2 * size + 2) if j != i])
|
|
423
|
+
|
|
424
|
+
for j in range(1, 2 * size + 2):
|
|
425
|
+
for i, k in itertools.combinations(range(1, 2 * size + 2), 2):
|
|
426
|
+
if i == j or k == j:
|
|
427
|
+
continue
|
|
428
|
+
|
|
429
|
+
self.append([-var(i, j), -var(k, j)])
|
|
430
|
+
|
|
431
|
+
if verb:
|
|
432
|
+
self.comments.append('c Parity formula for m == {0} ({1} vertices)'.format(size, 2 * size + 1))
|
|
433
|
+
for i in range(1, 2 * size + 2):
|
|
434
|
+
for j in range(i + 1, 2 * size + 2):
|
|
435
|
+
self.comments.append('c edge: {0}; bool var: {1}'.format((i, j), var(i, j)))
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
#
|
|
439
|
+
#==============================================================================
|
|
440
|
+
def parse_options():
|
|
441
|
+
"""
|
|
442
|
+
Parses command-line options:
|
|
443
|
+
"""
|
|
444
|
+
|
|
445
|
+
try:
|
|
446
|
+
opts, args = getopt.getopt(sys.argv[1:],
|
|
447
|
+
'k:n:ht:v',
|
|
448
|
+
['kval=',
|
|
449
|
+
'size=',
|
|
450
|
+
'help',
|
|
451
|
+
'type=',
|
|
452
|
+
'verb'])
|
|
453
|
+
except getopt.GetoptError as err:
|
|
454
|
+
sys.stderr.write(str(err).capitalize())
|
|
455
|
+
usage()
|
|
456
|
+
sys.exit(1)
|
|
457
|
+
|
|
458
|
+
kval = 1
|
|
459
|
+
size = 8
|
|
460
|
+
ftype = 'php'
|
|
461
|
+
verb = False
|
|
462
|
+
|
|
463
|
+
for opt, arg in opts:
|
|
464
|
+
if opt in ('-h', '--help'):
|
|
465
|
+
usage()
|
|
466
|
+
sys.exit(0)
|
|
467
|
+
elif opt in ('-k', '--kval'):
|
|
468
|
+
kval = int(arg)
|
|
469
|
+
elif opt in ('-n', '--size'):
|
|
470
|
+
size = int(arg)
|
|
471
|
+
elif opt in ('-t', '--type'):
|
|
472
|
+
ftype = str(arg)
|
|
473
|
+
elif opt in ('-v', '--verb'):
|
|
474
|
+
verb = True
|
|
475
|
+
else:
|
|
476
|
+
assert False, 'Unhandled option: {0} {1}'.format(opt, arg)
|
|
477
|
+
|
|
478
|
+
return ftype, kval, size, verb
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
#
|
|
482
|
+
#==============================================================================
|
|
483
|
+
def usage():
|
|
484
|
+
"""
|
|
485
|
+
Prints usage message.
|
|
486
|
+
"""
|
|
487
|
+
|
|
488
|
+
print('Usage:', os.path.basename(sys.argv[0]), '[options]')
|
|
489
|
+
print('Options:')
|
|
490
|
+
print(' -k, --kval=<int> Value k for generating k-PHP')
|
|
491
|
+
print(' Available values: [1 .. INT_MAX] (default = 1)')
|
|
492
|
+
print(' -n, --size=<int> Integer parameter of formula (its size)')
|
|
493
|
+
print(' Available values: [0 .. INT_MAX] (default = 8)')
|
|
494
|
+
print(' -h, --help')
|
|
495
|
+
print(' -t, --type=<string> Formula type')
|
|
496
|
+
print(' Available values: cb, gt, par, php (default = php)')
|
|
497
|
+
print(' -v, --verb Be verbose (show comments)')
|
|
498
|
+
|
|
499
|
+
#
|
|
500
|
+
#==============================================================================
|
|
501
|
+
if __name__ == '__main__':
|
|
502
|
+
# parse command-line options
|
|
503
|
+
ftype, kval, size, verb = parse_options()
|
|
504
|
+
|
|
505
|
+
# generate formula
|
|
506
|
+
if ftype == 'php':
|
|
507
|
+
cnf = PHP(size, kval=kval, verb=verb)
|
|
508
|
+
elif ftype == 'gt': # gt
|
|
509
|
+
cnf = GT(size, verb=verb)
|
|
510
|
+
elif ftype == 'cb': # cb
|
|
511
|
+
cnf = CB(size, exhaustive=kval, verb=verb)
|
|
512
|
+
else: # parity
|
|
513
|
+
cnf = PAR(size, verb=verb)
|
|
514
|
+
|
|
515
|
+
# print formula in DIMACS to stdout
|
|
516
|
+
cnf.to_fp(sys.stdout)
|