Skip to content

Commit c295062

Browse files
committed
Allow empty clauses when dumping CNF
1 parent 203d154 commit c295062

File tree

3 files changed

+19
-26
lines changed

3 files changed

+19
-26
lines changed

nnf/dimacs.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,6 @@ def _dump_cnf(
145145
if not isinstance(clause, Or):
146146
raise TypeError("CNF sentences must be conjunctions of "
147147
"disjunctions")
148-
if not len(clause.children) > 0:
149-
raise TypeError("CNF sentences shouldn't have empty clauses")
150148
first = True
151149
for child in clause.children:
152150
if not isinstance(child, Var):
@@ -294,16 +292,15 @@ def _parse_cnf(tokens: t.Iterable[str]) -> And[Or[Var]]:
294292
clause = set() # type: t.Set[Var]
295293
for token in tokens:
296294
if token == '0':
297-
if clause:
298-
clauses.add(Or(clause))
295+
clauses.add(Or(clause))
299296
clause = set()
300297
elif token == '%':
301298
# Some example files end with:
302299
# 0
303300
# %
304301
# 0
305302
# I don't know why.
306-
pass
303+
break
307304
elif token.startswith('-'):
308305
clause.add(Var(int(token[1:]), False))
309306
else:

nnf/dsharp.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import tempfile
2626
import typing as t
2727

28-
from nnf import NNF, And, Or, Var, false, dimacs
28+
from nnf import NNF, And, Or, Var, false, true, dimacs
2929
from nnf.util import Name
3030

3131
__all__ = ('load', 'loads', 'compile')
@@ -100,6 +100,12 @@ def compile(
100100
if not sentence.is_CNF():
101101
raise ValueError("Sentence must be in CNF")
102102

103+
# Handle cases D# doesn't like
104+
if not sentence.children:
105+
return true
106+
if false in sentence.children:
107+
return false
108+
103109
var_labels = dict(enumerate(sentence.vars(), start=1))
104110
var_labels_inverse = {v: k for k, v in var_labels.items()}
105111

test_nnf.py

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,6 @@ def DNF(draw):
126126
@st.composite
127127
def CNF(draw):
128128
sentence = And(draw(st.frozensets(clauses())))
129-
assume(len(sentence.children) > 0)
130129
return sentence
131130

132131

@@ -319,21 +318,15 @@ def test_arbitrary_dimacs_sat_serialize(sentence: nnf.NNF):
319318

320319

321320
@given(CNF())
322-
def test_arbitrary_dimacs_cnf_serialize(sentence: nnf.And):
323-
assume(all(len(clause.children) > 0 for clause in sentence.children))
321+
def test_arbitrary_dimacs_cnf_serialize(sentence: And[Or[Var]]):
324322
reloaded = dimacs.loads(dimacs.dumps(sentence, mode='cnf'))
325323
assert reloaded.is_CNF()
326324
assert reloaded == sentence
327325

328326

329327
@given(NNF())
330328
def test_dimacs_cnf_serialize_accepts_only_cnf(sentence: nnf.NNF):
331-
if (isinstance(sentence, And)
332-
and all(isinstance(clause, Or)
333-
and all(isinstance(var, Var)
334-
for var in clause.children)
335-
and len(clause.children) > 0
336-
for clause in sentence.children)):
329+
if sentence.is_CNF():
337330
event("CNF sentence")
338331
dimacs.dumps(sentence, mode='cnf')
339332
else:
@@ -818,18 +811,17 @@ def test_copying_does_not_copy(sentence: nnf.NNF):
818811

819812
if shutil.which('dsharp') is not None:
820813
def test_dsharp_compile_uf20():
821-
for sentence in uf20_cnf:
822-
compiled = dsharp.compile(sentence)
823-
compiled_smooth = dsharp.compile(sentence, smooth=True)
824-
assert sentence.equivalent(compiled)
825-
assert sentence.equivalent(compiled_smooth)
826-
assert compiled.decomposable()
827-
assert compiled_smooth.decomposable()
828-
assert compiled_smooth.smooth()
814+
sentence = uf20_cnf[0]
815+
compiled = dsharp.compile(sentence)
816+
compiled_smooth = dsharp.compile(sentence, smooth=True)
817+
assert sentence.equivalent(compiled)
818+
assert sentence.equivalent(compiled_smooth)
819+
assert compiled.decomposable()
820+
assert compiled_smooth.decomposable()
821+
assert compiled_smooth.smooth()
829822

830823
@given(CNF())
831824
def test_dsharp_compile(sentence: And[Or[Var]]):
832-
assume(all(len(clause) > 0 for clause in sentence))
833825
compiled = dsharp.compile(sentence)
834826
compiled_smooth = dsharp.compile(sentence, smooth=True)
835827
assert compiled.decomposable()
@@ -841,7 +833,6 @@ def test_dsharp_compile(sentence: And[Or[Var]]):
841833

842834
@given(CNF())
843835
def test_dsharp_compile_converting_names(sentence: And[Or[Var]]):
844-
assume(all(len(clause) > 0 for clause in sentence))
845836
sentence = And(Or(Var(str(var.name), var.true) for var in clause)
846837
for clause in sentence)
847838
compiled = dsharp.compile(sentence)
@@ -924,7 +915,6 @@ def test_kissat_uf20():
924915

925916
@given(CNF())
926917
def test_kissat_cnf(sentence: And[Or[Var]]):
927-
assume(all(len(clause) > 0 for clause in sentence))
928918
with using_kissat():
929919
assert sentence.satisfiable() == sentence._cnf_satisfiable_native()
930920

0 commit comments

Comments
 (0)