Skip to content

Commit c2e81fd

Browse files
authored
Merge pull request #27 from beckydvn/add-implication-remove-nesting
Add Implication and Remove Nesting
2 parents cf9c6b3 + ed31611 commit c2e81fd

File tree

2 files changed

+111
-0
lines changed

2 files changed

+111
-0
lines changed

nnf/__init__.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,32 @@ class NNF(metaclass=abc.ABCMeta):
9090

9191
def __and__(self: T_NNF, other: U_NNF) -> 'And[t.Union[T_NNF, U_NNF]]':
9292
"""And({self, other})"""
93+
# prevent unnecessary nesting
94+
if config.auto_simplify:
95+
if not isinstance(self, And) and isinstance(other, And):
96+
return And({self, *other.children})
97+
elif isinstance(self, And) and not isinstance(other, And):
98+
return And({*self.children, other})
99+
elif isinstance(self, And) and isinstance(other, And):
100+
return And({*self.children, *other.children})
93101
return And({self, other})
94102

95103
def __or__(self: T_NNF, other: U_NNF) -> 'Or[t.Union[T_NNF, U_NNF]]':
96104
"""Or({self, other})"""
105+
# prevent unnecessary nesting
106+
if config.auto_simplify:
107+
if not isinstance(self, Or) and isinstance(other, Or):
108+
return Or({self, *other.children})
109+
elif isinstance(self, Or) and not isinstance(other, Or):
110+
return Or({*self.children, other})
111+
elif isinstance(self, Or) and isinstance(other, Or):
112+
return Or({*self.children, *other.children})
97113
return Or({self, other})
98114

115+
def __rshift__(self, other: 'NNF') -> 'Or[NNF]':
116+
"""Or({self.negate(), other})"""
117+
return Or({self.negate(), other})
118+
99119
def walk(self) -> t.Iterator['NNF']:
100120
"""Yield all nodes in the sentence, depth-first.
101121
@@ -1788,6 +1808,7 @@ class _Config:
17881808
sat_backend = _Setting("auto", {"auto", "native", "kissat", "pysat"})
17891809
models_backend = _Setting("auto", {"auto", "native", "pysat"})
17901810
pysat_solver = _Setting("minisat22")
1811+
auto_simplify = _Setting(False, {True, False})
17911812

17921813
__slots__ = ()
17931814

@@ -1839,6 +1860,14 @@ def __call__(self, **settings: str) -> _ConfigContext:
18391860
#: `pysat.solvers.SolverNames
18401861
#: <https://pysathq.github.io/docs/html/api/solvers.html
18411862
#: #pysat.solvers.SolverNames>`_. Default: ``minisat22``.
1863+
#:
1864+
#: - ``auto_simplify``: An optional setting to prevent "extra" nesting when
1865+
#: NNF formulas are added onto with & or |.
1866+
#:
1867+
#: - ``True``: Remove nesting whenever & or | are used on an NNF formula.
1868+
#: - ``False``: Generate formulas as normal, with nesting reflecting exactly
1869+
#: how the formula was created.
1870+
18421871
config = _Config()
18431872

18441873

test_nnf.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,3 +1105,85 @@ def test_models(sentence: nnf.NNF):
11051105
models = list(sentence.models())
11061106
assert len(real_models) == len(models)
11071107
assert model_set(real_models) == model_set(models)
1108+
1109+
1110+
@config(auto_simplify=False)
1111+
def test_nesting():
1112+
a, b, c, d, e, f = Var("a"), Var("b"), Var("c"), Var("d"), \
1113+
Var("e"), Var("f")
1114+
1115+
# test left nestings on And
1116+
config.auto_simplify = False
1117+
formula = a & (b & c)
1118+
formula = formula & (d | e)
1119+
assert formula == And({And({And({b, c}), a}), Or({d, e})})
1120+
config.auto_simplify = True
1121+
formula = a & (b & c)
1122+
formula = formula & (d | e)
1123+
assert formula == And({a, b, c, Or({d, e})})
1124+
1125+
# test right nestings on And
1126+
config.auto_simplify = False
1127+
formula = a & (b & c)
1128+
formula = (d | e) & formula
1129+
assert formula == And({And({And({b, c}), a}), Or({d, e})})
1130+
config.auto_simplify = True
1131+
formula = a & (b & c)
1132+
formula = (d | e) & formula
1133+
assert formula == And({a, b, c, Or({d, e})})
1134+
1135+
# test nestings on both sides with And
1136+
config.auto_simplify = False
1137+
formula = a & (b & c)
1138+
formula2 = d & (e & f)
1139+
formula = formula & formula2
1140+
assert formula == And({(And({a, And({b, c})})), And({d, And({e, f})})})
1141+
config.auto_simplify = True
1142+
formula = a & (b & c)
1143+
formula2 = d & (e & f)
1144+
formula = formula & formula2
1145+
assert formula == And({a, b, c, d, e, f})
1146+
1147+
# test left nestings on Or
1148+
config.auto_simplify = False
1149+
formula = a | (b | c)
1150+
formula = formula | (d & e)
1151+
assert formula == Or({Or({Or({b, c}), a}), And({d, e})})
1152+
config.auto_simplify = True
1153+
formula = a | (b | c)
1154+
formula = formula | (d & e)
1155+
assert formula == Or({a, b, c, And({d, e})})
1156+
1157+
# test right nestings on Or
1158+
config.auto_simplify = False
1159+
formula = a | (b | c)
1160+
formula = (d & e) | formula
1161+
assert formula == Or({Or({Or({b, c}), a}), And({d, e})})
1162+
config.auto_simplify = True
1163+
formula = a | (b | c)
1164+
formula = (d & e) | formula
1165+
assert formula == Or({a, b, c, And({d, e})})
1166+
1167+
# test nestings on both sides with Or
1168+
config.auto_simplify = False
1169+
formula = a | (b | c)
1170+
formula2 = d | (e | f)
1171+
formula = formula | formula2
1172+
assert formula == Or({(Or({a, Or({b, c})})), Or({d, Or({e, f})})})
1173+
config.auto_simplify = True
1174+
formula = a | (b | c)
1175+
formula2 = d | (e | f)
1176+
formula = formula | formula2
1177+
assert formula == Or({a, b, c, d, e, f})
1178+
1179+
# test nestings with both And and Or
1180+
config.auto_simplify = False
1181+
formula = a & (b | c)
1182+
formula2 = d & (e & f)
1183+
formula = formula | formula2
1184+
assert formula == Or({(And({a, Or({b, c})})), And({d, And({e, f})})})
1185+
config.auto_simplify = True
1186+
formula = a & (b | c)
1187+
formula2 = d & (e & f)
1188+
formula = formula | formula2
1189+
assert formula == Or({(And({a, Or({b, c})})), And({d, e, f})})

0 commit comments

Comments
 (0)