|
32 | 32 |
|
33 | 33 | __all__ = ('NNF', 'Internal', 'And', 'Or', 'Var', 'Aux', 'Builder', |
34 | 34 | 'all_models', 'complete_models', 'decision', 'true', 'false', |
35 | | - 'dsharp', 'dimacs', 'amc', 'tseitin', 'operators') |
| 35 | + 'dsharp', 'dimacs', 'amc', 'kissat', 'using_kissat', 'tseitin', |
| 36 | + 'operators') |
36 | 37 |
|
37 | 38 |
|
38 | 39 | def all_models(names: 't.Iterable[Name]') -> t.Iterator[Model]: |
@@ -60,6 +61,26 @@ def all_models(names: 't.Iterable[Name]') -> t.Iterator[Model]: |
60 | 61 | T_NNF_co = t.TypeVar('T_NNF_co', bound='NNF', covariant=True) |
61 | 62 | _Tristate = t.Optional[bool] |
62 | 63 |
|
| 64 | +# Valid values: native and kissat |
| 65 | +SAT_BACKEND = 'native' |
| 66 | + |
| 67 | + |
| 68 | +class using_kissat(): |
| 69 | + """Context manager to use the kissat solver in a block of code.""" |
| 70 | + |
| 71 | + def __init__(self) -> None: |
| 72 | + self.setting = SAT_BACKEND |
| 73 | + |
| 74 | + def __enter__(self) -> 'using_kissat': |
| 75 | + global SAT_BACKEND |
| 76 | + SAT_BACKEND = 'kissat' |
| 77 | + return self |
| 78 | + |
| 79 | + def __exit__(self, *_: t.Any) -> None: |
| 80 | + global SAT_BACKEND |
| 81 | + SAT_BACKEND = self.setting |
| 82 | + |
| 83 | + |
63 | 84 | if t.TYPE_CHECKING: |
64 | 85 | def memoize(func: T) -> T: |
65 | 86 | ... |
@@ -264,10 +285,9 @@ def satisfiable( |
264 | 285 |
|
265 | 286 | if cnf: |
266 | 287 | return self._cnf_satisfiable() |
267 | | - |
268 | | - # todo: use a better fallback |
269 | | - return any(self.satisfied_by(model) |
270 | | - for model in all_models(self.vars())) |
| 288 | + else: |
| 289 | + from nnf import tseitin |
| 290 | + return tseitin.to_CNF(self)._cnf_satisfiable() |
271 | 291 |
|
272 | 292 | def _satisfiable_decomposable(self) -> bool: |
273 | 293 | """Checks satisfiability of decomposable sentences. |
@@ -596,6 +616,16 @@ def to_CNF(self) -> 'And[Or[Var]]': |
596 | 616 | return tseitin.to_CNF(self) |
597 | 617 |
|
598 | 618 | def _cnf_satisfiable(self) -> bool: |
| 619 | + """Call a SAT solver on the presumed CNF theory.""" |
| 620 | + if SAT_BACKEND == 'native': |
| 621 | + return self._cnf_satisfiable_native() |
| 622 | + elif SAT_BACKEND == 'kissat': |
| 623 | + from nnf import kissat |
| 624 | + return kissat.solve(t.cast(And[Or[Var]], self)) is not None |
| 625 | + else: |
| 626 | + raise NotImplementedError('Unrecognized SAT backend: '+SAT_BACKEND) |
| 627 | + |
| 628 | + def _cnf_satisfiable_native(self) -> bool: |
599 | 629 | """A naive DPLL SAT solver.""" |
600 | 630 | def DPLL(clauses: t.FrozenSet[t.FrozenSet[Var]]) -> bool: |
601 | 631 | if not clauses: |
|
0 commit comments