python-sat 1.8.dev26__tar.gz → 1.8.dev28__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.8.dev26/python_sat.egg-info → python_sat-1.8.dev28}/PKG-INFO +1 -1
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/examples/rc2.py +2 -2
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/pysat/__init__.py +1 -1
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/pysat/formula.py +109 -32
- {python_sat-1.8.dev26 → python_sat-1.8.dev28/python_sat.egg-info}/PKG-INFO +1 -1
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/LICENSE.txt +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/MANIFEST.in +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/README.rst +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/allies/__init__.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/allies/approxmc.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/allies/unigen.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/cardenc/bitwise.hh +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/cardenc/card.hh +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/cardenc/clset.hh +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/cardenc/common.hh +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/cardenc/itot.hh +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/cardenc/ladder.hh +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/cardenc/mto.hh +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/cardenc/pairwise.hh +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/cardenc/ptypes.hh +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/cardenc/pycard.cc +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/cardenc/seqcounter.hh +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/cardenc/sortcard.hh +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/cardenc/utils.hh +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/examples/__init__.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/examples/bbscan.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/examples/bica.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/examples/fm.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/examples/genhard.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/examples/hitman.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/examples/lbx.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/examples/lsu.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/examples/mcsls.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/examples/models.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/examples/musx.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/examples/optux.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/examples/primer.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/examples/usage.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/pysat/_fileio.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/pysat/_utils.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/pysat/card.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/pysat/engines.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/pysat/pb.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/pysat/process.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/pysat/solvers.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/python_sat.egg-info/SOURCES.txt +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/python_sat.egg-info/dependency_links.txt +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/python_sat.egg-info/requires.txt +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/python_sat.egg-info/top_level.txt +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/requirements.txt +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/setup.cfg +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/setup.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/cadical103.tar.gz +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/cadical153.tar.gz +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/cadical195.tar.gz +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/glucose30.tar.gz +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/glucose41.tar.gz +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/glucose421.tar.gz +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/lingeling.tar.gz +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/maplechrono.zip +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/maplecm.zip +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/maplesat.zip +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/mergesat3.tar.gz +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/minicard.tar.gz +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/minisat22.tar.gz +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/minisatgh.zip +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/patches/cadical103.patch +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/patches/cadical153.patch +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/patches/cadical195.patch +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/patches/glucose30.patch +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/patches/glucose41.patch +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/patches/glucose421.patch +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/patches/gluecard30.patch +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/patches/gluecard41.patch +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/patches/lingeling.patch +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/patches/maplechrono.patch +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/patches/maplecm.patch +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/patches/maplesat.patch +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/patches/mergesat3.patch +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/patches/minicard.patch +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/patches/minisat22.patch +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/patches/minisatgh.patch +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/prepare.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/solvers/pysolvers.cc +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/tests/test_accum_stats.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/tests/test_atmost.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/tests/test_atmost1.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/tests/test_atmostk.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/tests/test_boolengine.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/tests/test_clausification.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/tests/test_cnf.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/tests/test_encode_pb_conditional.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/tests/test_equals1.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/tests/test_formula_unique.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/tests/test_idpool.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/tests/test_process.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/tests/test_propagate.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/tests/test_unique_model.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/tests/test_unique_mus.py +0 -0
- {python_sat-1.8.dev26 → python_sat-1.8.dev28}/tests/test_warmstart.py +0 -0
|
@@ -345,8 +345,8 @@ class RC2(object):
|
|
|
345
345
|
else:
|
|
346
346
|
# adding to formula's hard clauses
|
|
347
347
|
# if any preprocessing is required
|
|
348
|
-
formula.hard.append(cl
|
|
349
|
-
formula.soft[i] = [
|
|
348
|
+
formula.hard.append(cl)
|
|
349
|
+
formula.soft[i] = [selv]
|
|
350
350
|
|
|
351
351
|
if selv not in self.wght:
|
|
352
352
|
# record selector and its weight
|
|
@@ -4036,26 +4036,34 @@ class WCNF(object):
|
|
|
4036
4036
|
|
|
4037
4037
|
.. code-block:: python
|
|
4038
4038
|
|
|
4039
|
-
>>> with open('some-file.
|
|
4039
|
+
>>> with open('some-file.wcnf', 'r') as fp:
|
|
4040
4040
|
... cnf1 = WCNF()
|
|
4041
4041
|
... cnf1.from_fp(fp)
|
|
4042
4042
|
>>>
|
|
4043
|
-
>>> with open('another-file.
|
|
4043
|
+
>>> with open('another-file.wcnf', 'r') as fp:
|
|
4044
4044
|
... cnf2 = WCNF(from_fp=fp)
|
|
4045
4045
|
"""
|
|
4046
4046
|
|
|
4047
4047
|
def parse_wght(string):
|
|
4048
|
-
|
|
4049
|
-
|
|
4048
|
+
if string == 'h':
|
|
4049
|
+
return None
|
|
4050
|
+
else:
|
|
4051
|
+
wght = float(string)
|
|
4052
|
+
return int(wght) if wght.is_integer() else decimal.Decimal(string)
|
|
4050
4053
|
|
|
4051
4054
|
self.nv = 0
|
|
4052
4055
|
self.hard = []
|
|
4053
4056
|
self.soft = []
|
|
4054
4057
|
self.wght = []
|
|
4055
|
-
self.topw =
|
|
4058
|
+
self.topw = decimal.Decimal('+inf')
|
|
4056
4059
|
self.comments = []
|
|
4057
4060
|
comment_lead = set(['p']).union(set(comment_lead))
|
|
4058
4061
|
|
|
4062
|
+
# we are now expecting the new WCNF format
|
|
4063
|
+
assert 'h' not in comment_lead, \
|
|
4064
|
+
"Character 'h' cannot be used for comments" \
|
|
4065
|
+
" (reserved to signify hard clauses)"
|
|
4066
|
+
|
|
4059
4067
|
# soft clauses with negative weights
|
|
4060
4068
|
negs = []
|
|
4061
4069
|
|
|
@@ -4066,7 +4074,7 @@ class WCNF(object):
|
|
|
4066
4074
|
w, items = line.split(sep=None, maxsplit=1)
|
|
4067
4075
|
w = parse_wght(w)
|
|
4068
4076
|
|
|
4069
|
-
if w >= self.topw:
|
|
4077
|
+
if w is None or w >= self.topw:
|
|
4070
4078
|
self.hard.append(list(map(int, items.split()[:-1])))
|
|
4071
4079
|
elif w > 0:
|
|
4072
4080
|
self.soft.append(list(map(int, items.split()[:-1])))
|
|
@@ -4078,12 +4086,16 @@ class WCNF(object):
|
|
|
4078
4086
|
elif not line.startswith('p wcnf '):
|
|
4079
4087
|
self.comments.append(line)
|
|
4080
4088
|
else: # expecting the preamble
|
|
4089
|
+
assert len(self.soft) == len(self.hard) == 0, \
|
|
4090
|
+
'Preamble goes after some of the clauses have been read'
|
|
4091
|
+
|
|
4081
4092
|
preamble = line.split(' ')
|
|
4082
4093
|
if len(preamble) == 5: # preamble should be "p wcnf nvars nclauses topw"
|
|
4083
4094
|
self.topw = parse_wght(preamble[-1])
|
|
4084
4095
|
else: # preamble should be "p wcnf nvars nclauses", with topw omitted
|
|
4085
4096
|
self.topw = decimal.Decimal('+inf')
|
|
4086
4097
|
|
|
4098
|
+
# potentially expensive: calculating the largest variable identifier
|
|
4087
4099
|
self.nv = max(map(lambda cl: max(map(abs, cl)), itertools.chain.from_iterable([[[self.nv]], self.hard, self.soft])))
|
|
4088
4100
|
|
|
4089
4101
|
# if there is any soft clause with negative weight
|
|
@@ -4198,7 +4210,8 @@ class WCNF(object):
|
|
|
4198
4210
|
|
|
4199
4211
|
return wcnf
|
|
4200
4212
|
|
|
4201
|
-
def to_file(self, fname, comments=None, compress_with='use_ext'
|
|
4213
|
+
def to_file(self, fname, comments=None, compress_with='use_ext',
|
|
4214
|
+
format='mse22'):
|
|
4202
4215
|
"""
|
|
4203
4216
|
The method is for saving a WCNF formula into a file in the DIMACS
|
|
4204
4217
|
CNF format. A file name is expected as an argument. Additionally,
|
|
@@ -4206,13 +4219,20 @@ class WCNF(object):
|
|
|
4206
4219
|
parameter. Also, a file can be compressed using either gzip, bzip2,
|
|
4207
4220
|
lzma (xz), or zstd.
|
|
4208
4221
|
|
|
4222
|
+
The ``format`` parameter can be set either to value ``'mse22'``
|
|
4223
|
+
(set by default) or ``'legacy'``. Both variants are described on
|
|
4224
|
+
the `MSE 2022 webpage
|
|
4225
|
+
<https://maxsat-evaluations.github.io/2022/rules.html#input>`__.
|
|
4226
|
+
|
|
4209
4227
|
:param fname: a file name where to store the formula.
|
|
4210
4228
|
:param comments: additional comments to put in the file.
|
|
4211
4229
|
:param compress_with: file compression algorithm
|
|
4230
|
+
:param format: WCNF format to use
|
|
4212
4231
|
|
|
4213
4232
|
:type fname: str
|
|
4214
4233
|
:type comments: list(str)
|
|
4215
4234
|
:type compress_with: str
|
|
4235
|
+
:type format: str
|
|
4216
4236
|
|
|
4217
4237
|
Note that the ``compressed_with`` parameter can be ``None`` (i.e.
|
|
4218
4238
|
the file is uncompressed), ``'gzip'``, ``'bzip2'``, ``'lzma'``,
|
|
@@ -4234,20 +4254,27 @@ class WCNF(object):
|
|
|
4234
4254
|
"""
|
|
4235
4255
|
|
|
4236
4256
|
with FileObject(fname, mode='w', compression=compress_with) as fobj:
|
|
4237
|
-
self.to_fp(fobj.fp, comments)
|
|
4257
|
+
self.to_fp(fobj.fp, comments, format=format)
|
|
4238
4258
|
|
|
4239
|
-
def to_fp(self, file_pointer, comments=None):
|
|
4259
|
+
def to_fp(self, file_pointer, comments=None, format='mse22'):
|
|
4240
4260
|
"""
|
|
4241
4261
|
The method can be used to save a WCNF formula into a file pointer.
|
|
4242
4262
|
The file pointer is expected as an argument. Additionally,
|
|
4243
4263
|
supplementary comment lines can be specified in the ``comments``
|
|
4244
4264
|
parameter.
|
|
4245
4265
|
|
|
4266
|
+
The ``format`` parameter can be set either to value ``'mse22'``
|
|
4267
|
+
(set by default) or ``'legacy'``. Both variants are described on
|
|
4268
|
+
the `MSE 2022 webpage
|
|
4269
|
+
<https://maxsat-evaluations.github.io/2022/rules.html#input>`__.
|
|
4270
|
+
|
|
4246
4271
|
:param file_pointer: a file pointer where to store the formula.
|
|
4247
4272
|
:param comments: additional comments to put in the file.
|
|
4273
|
+
:param format: WCNF format to use
|
|
4248
4274
|
|
|
4249
4275
|
:type file_pointer: file pointer
|
|
4250
4276
|
:type comments: list(str)
|
|
4277
|
+
:type format: str
|
|
4251
4278
|
|
|
4252
4279
|
Example:
|
|
4253
4280
|
|
|
@@ -4270,21 +4297,32 @@ class WCNF(object):
|
|
|
4270
4297
|
for c in comments:
|
|
4271
4298
|
print(c, file=file_pointer)
|
|
4272
4299
|
|
|
4273
|
-
|
|
4300
|
+
if format == 'legacy':
|
|
4301
|
+
print('p wcnf', self.nv, len(self.hard) + len(self.soft), self.topw, file=file_pointer)
|
|
4274
4302
|
|
|
4275
4303
|
# soft clauses are dumped first because
|
|
4276
4304
|
# some tools (e.g. LBX) cannot count them properly
|
|
4277
4305
|
for i, cl in enumerate(self.soft):
|
|
4278
4306
|
print(self.wght[i], ' '.join(str(l) for l in cl), '0', file=file_pointer)
|
|
4279
4307
|
|
|
4308
|
+
# hard clause either have a top weight or are marked as 'h'
|
|
4309
|
+
topw = self.topw if format == 'legacy' else 'h'
|
|
4280
4310
|
for cl in self.hard:
|
|
4281
|
-
print(
|
|
4311
|
+
print(topw, ' '.join(str(l) for l in cl), '0', file=file_pointer)
|
|
4282
4312
|
|
|
4283
|
-
def to_dimacs(self):
|
|
4313
|
+
def to_dimacs(self, format='mse22'):
|
|
4284
4314
|
"""
|
|
4285
4315
|
Return the current state of the object in extended DIMACS format.
|
|
4286
4316
|
|
|
4287
|
-
|
|
4317
|
+
The ``format`` parameter can be set either to value ``'mse22'``
|
|
4318
|
+
(set by default) or ``'legacy'``. Both variants are described on
|
|
4319
|
+
the `MSE 2022 webpage
|
|
4320
|
+
<https://maxsat-evaluations.github.io/2022/rules.html#input>`__.
|
|
4321
|
+
|
|
4322
|
+
:param format: WCNF format to use
|
|
4323
|
+
:type format: str
|
|
4324
|
+
|
|
4325
|
+
For example, if 'some-file.wcnf' contains:
|
|
4288
4326
|
|
|
4289
4327
|
::
|
|
4290
4328
|
|
|
@@ -4299,20 +4337,31 @@ class WCNF(object):
|
|
|
4299
4337
|
.. code-block:: python
|
|
4300
4338
|
|
|
4301
4339
|
>>> from pysat.formula import WCNF
|
|
4302
|
-
>>> cnf = WCNF(from_file='some-file.
|
|
4303
|
-
>>> print(cnf.to_dimacs())
|
|
4340
|
+
>>> cnf = WCNF(from_file='some-file.wcnf')
|
|
4341
|
+
>>> print(cnf.to_dimacs(format='legacy'))
|
|
4304
4342
|
c Example
|
|
4305
4343
|
p wcnf 2 3 10
|
|
4306
4344
|
10 1 2 0
|
|
4307
4345
|
1 -1 0
|
|
4308
4346
|
2 -2 0
|
|
4347
|
+
>>>
|
|
4348
|
+
>>> print(cnf.to_dimacs())
|
|
4349
|
+
c Example
|
|
4350
|
+
h 1 2 0
|
|
4351
|
+
1 -1 0
|
|
4352
|
+
2 -2 0
|
|
4309
4353
|
"""
|
|
4310
4354
|
|
|
4311
|
-
header_lines = [f'p wcnf {self.nv} {len(self.hard) + len(self.soft)} {self.topw}']
|
|
4312
4355
|
comment_lines = [f'{comment}' for comment in self.comments]
|
|
4313
|
-
hard_lines = [f'{self.topw} ' + ' '.join(map(str, clause)) + ' 0' for clause in self.hard]
|
|
4314
4356
|
soft_lines = [f'{weight} ' + ' '.join(map(str, clause)) + ' 0' for clause, weight in zip(self.soft, self.wght)]
|
|
4315
4357
|
|
|
4358
|
+
if format == 'legacy':
|
|
4359
|
+
header_lines = [f'p wcnf {self.nv} {len(self.hard) + len(self.soft)} {self.topw}']
|
|
4360
|
+
hard_lines = [f'{self.topw} ' + ' '.join(map(str, clause)) + ' 0' for clause in self.hard]
|
|
4361
|
+
else:
|
|
4362
|
+
header_lines = []
|
|
4363
|
+
hard_lines = ['h ' + ' '.join(map(str, clause)) + ' 0' for clause in self.hard]
|
|
4364
|
+
|
|
4316
4365
|
lines = '\n'.join(comment_lines + header_lines + hard_lines + soft_lines)
|
|
4317
4366
|
return lines
|
|
4318
4367
|
|
|
@@ -5173,18 +5222,26 @@ class WCNFPlus(WCNF, object):
|
|
|
5173
5222
|
"""
|
|
5174
5223
|
|
|
5175
5224
|
def parse_wght(string):
|
|
5176
|
-
|
|
5177
|
-
|
|
5225
|
+
if string == 'h':
|
|
5226
|
+
return None
|
|
5227
|
+
else:
|
|
5228
|
+
wght = float(string)
|
|
5229
|
+
return int(wght) if wght.is_integer() else decimal.Decimal(string)
|
|
5178
5230
|
|
|
5179
5231
|
self.nv = 0
|
|
5180
5232
|
self.hard = []
|
|
5181
5233
|
self.atms = []
|
|
5182
5234
|
self.soft = []
|
|
5183
5235
|
self.wght = []
|
|
5184
|
-
self.topw =
|
|
5236
|
+
self.topw = decimal.Decimal('+inf')
|
|
5185
5237
|
self.comments = []
|
|
5186
5238
|
comment_lead = set(['p']).union(set(comment_lead))
|
|
5187
5239
|
|
|
5240
|
+
# we are now expecting the new WCNF format
|
|
5241
|
+
assert 'h' not in comment_lead, \
|
|
5242
|
+
"Character 'h' cannot be used for comments" \
|
|
5243
|
+
" (reserved to signify hard clauses)"
|
|
5244
|
+
|
|
5188
5245
|
# soft clauses with negative weights
|
|
5189
5246
|
negs = []
|
|
5190
5247
|
|
|
@@ -5196,7 +5253,7 @@ class WCNFPlus(WCNF, object):
|
|
|
5196
5253
|
w, items = line.split(sep=None, maxsplit=1)
|
|
5197
5254
|
w = parse_wght(w)
|
|
5198
5255
|
|
|
5199
|
-
if w >= self.topw:
|
|
5256
|
+
if w is None or w >= self.topw:
|
|
5200
5257
|
self.hard.append(list(map(int, items.split()[:-1])))
|
|
5201
5258
|
elif w > 0:
|
|
5202
5259
|
self.soft.append(list(map(int, items.split()[:-1])))
|
|
@@ -5227,6 +5284,9 @@ class WCNFPlus(WCNF, object):
|
|
|
5227
5284
|
elif not line.startswith('p wcnf'): # wcnf is allowed here
|
|
5228
5285
|
self.comments.append(line)
|
|
5229
5286
|
else: # expecting the preamble
|
|
5287
|
+
assert len(self.soft) == len(self.hard) == len(self.atms) == 0, \
|
|
5288
|
+
'Preamble goes after some of the clauses have been read'
|
|
5289
|
+
|
|
5230
5290
|
preamble = line.split(' ')
|
|
5231
5291
|
if len(preamble) == 5: # preamble should be "p wcnf nvars nclauses topw"
|
|
5232
5292
|
self.topw = parse_wght(preamble[-1])
|
|
@@ -5246,18 +5306,25 @@ class WCNFPlus(WCNF, object):
|
|
|
5246
5306
|
if type(self.topw) == decimal.Decimal and self.topw.is_infinite():
|
|
5247
5307
|
self.topw = 1 + sum(self.wght)
|
|
5248
5308
|
|
|
5249
|
-
def to_fp(self, file_pointer, comments=None):
|
|
5309
|
+
def to_fp(self, file_pointer, comments=None, format='mse22'):
|
|
5250
5310
|
"""
|
|
5251
5311
|
The method can be used to save a WCNF+ formula into a file pointer.
|
|
5252
5312
|
The file pointer is expected as an argument. Additionally,
|
|
5253
5313
|
supplementary comment lines can be specified in the ``comments``
|
|
5254
5314
|
parameter.
|
|
5255
5315
|
|
|
5316
|
+
The ``format`` parameter can be set either to value ``'mse22'``
|
|
5317
|
+
(set by default) or ``'legacy'``. Both variants are described on
|
|
5318
|
+
the `MSE 2022 webpage
|
|
5319
|
+
<https://maxsat-evaluations.github.io/2022/rules.html#input>`__.
|
|
5320
|
+
|
|
5256
5321
|
:param file_pointer: a file pointer where to store the formula.
|
|
5257
5322
|
:param comments: additional comments to put in the file.
|
|
5323
|
+
:param format: WCNF format to use
|
|
5258
5324
|
|
|
5259
5325
|
:type file_pointer: file pointer
|
|
5260
5326
|
:type comments: list(str)
|
|
5327
|
+
:type format: str
|
|
5261
5328
|
|
|
5262
5329
|
Example:
|
|
5263
5330
|
|
|
@@ -5280,25 +5347,28 @@ class WCNFPlus(WCNF, object):
|
|
|
5280
5347
|
for c in comments:
|
|
5281
5348
|
print(c, file=file_pointer)
|
|
5282
5349
|
|
|
5283
|
-
|
|
5284
|
-
|
|
5285
|
-
|
|
5350
|
+
if format == 'legacy':
|
|
5351
|
+
ftype = 'wcnf+' if self.atms else 'wcnf'
|
|
5352
|
+
print('p', ftype, self.nv, len(self.hard) + len(self.soft) + len(self.atms),
|
|
5353
|
+
self.topw, file=file_pointer)
|
|
5286
5354
|
|
|
5287
5355
|
# soft clauses are dumped first because
|
|
5288
5356
|
# some tools (e.g. LBX) cannot count them properly
|
|
5289
5357
|
for i, cl in enumerate(self.soft):
|
|
5290
5358
|
print(self.wght[i], ' '.join(str(l) for l in cl), '0', file=file_pointer)
|
|
5291
5359
|
|
|
5360
|
+
# hard clause either have a top weight or are marked as 'h'
|
|
5361
|
+
topw = self.topw if format == 'legacy' else 'h'
|
|
5292
5362
|
for cl in self.hard:
|
|
5293
|
-
print(
|
|
5363
|
+
print(topw, ' '.join(str(l) for l in cl), '0', file=file_pointer)
|
|
5294
5364
|
|
|
5295
5365
|
# atmost constraints are hard
|
|
5296
5366
|
for am in self.atms:
|
|
5297
5367
|
if len(am) == 2: # cardinality constraint
|
|
5298
|
-
print(
|
|
5368
|
+
print(topw, ' '.join(str(l) for l in am[0]), '<=', am[1], file=file_pointer)
|
|
5299
5369
|
else: # len(am) == 3 => PB constraint
|
|
5300
5370
|
assert len(am[0]) == len(am[2]), 'Number of literals should be equal to the number of weights'
|
|
5301
|
-
print(
|
|
5371
|
+
print(topw, 'w', ' '.join('{0}*{1}'.format(str(w), str(l)) for w, l in zip(am[2], am[0])), '<=', am[1], file=file_pointer)
|
|
5302
5372
|
|
|
5303
5373
|
def to_dimacs(self):
|
|
5304
5374
|
"""
|
|
@@ -5329,18 +5399,25 @@ class WCNFPlus(WCNF, object):
|
|
|
5329
5399
|
10 -4 -5 -6 7 <= 2
|
|
5330
5400
|
"""
|
|
5331
5401
|
|
|
5332
|
-
header_lines = [f'p wcnf+ {self.nv} {len(self.hard) + len(self.soft) + len(self.atms)} {self.topw}']
|
|
5333
5402
|
comment_lines = [f'{comment}' for comment in self.comments]
|
|
5334
|
-
hard_lines = [f'{self.topw} ' + ' '.join(map(str,clause)) + ' 0' for clause in self.hard]
|
|
5335
5403
|
soft_lines = [f'{weight} ' + ' '.join(map(str,clause)) + ' 0' for clause, weight in zip(self.soft, self.wght)]
|
|
5336
5404
|
|
|
5405
|
+
if format == 'legacy':
|
|
5406
|
+
header_lines = [f'p wcnf+ {self.nv} {len(self.hard) + len(self.soft) + len(self.atms)} {self.topw}']
|
|
5407
|
+
topw = self.topw
|
|
5408
|
+
else:
|
|
5409
|
+
header_lines = []
|
|
5410
|
+
topw = 'h'
|
|
5411
|
+
|
|
5412
|
+
hard_lines = [f'{topw} ' + ' '.join(map(str,clause)) + ' 0' for clause in self.hard]
|
|
5413
|
+
|
|
5337
5414
|
atmost_lines = []
|
|
5338
5415
|
for am in self.atms:
|
|
5339
5416
|
if len(am) == 2: # cardinality constraint
|
|
5340
|
-
atmost_lines.append(f'{
|
|
5417
|
+
atmost_lines.append(f'{topw} ' + ' '.join(str(l) for l in am[0]) + ' <= ' + str(am[1]))
|
|
5341
5418
|
else: # len(am) == 3 => PB constraint
|
|
5342
5419
|
assert len(am[0]) == len(am[2]), 'Number of literals should be equal to the number of weights'
|
|
5343
|
-
atmost_lines.append(f'{
|
|
5420
|
+
atmost_lines.append(f'{topw} ' + 'w ' + ' '.join('{0}*{1}'.format(str(w), str(l)) for w, l in zip(am[2], am[0])) + ' <= ' + str(am[1]))
|
|
5344
5421
|
|
|
5345
5422
|
lines = '\n'.join(comment_lines + header_lines + hard_lines + soft_lines + atmost_lines) + '\n'
|
|
5346
5423
|
|
|
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
|
|
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
|