Source code for nnf.tseitin

"""Transformations using the well-known `Tseitin encoding
<https://en.wikipedia.org/wiki/Tseytin_transformation>`_.

The Tseitin transformation converts any arbitrary circuit to one in CNF in
polynomial time/space. It does so at the cost of introducing new variables
(one for each logical connective in the formula).
"""

from nnf import NNF, Var, And, Or, Internal
from nnf.util import memoize


[docs]def to_CNF(theory: NNF, simplify: bool = True) -> And[Or[Var]]: """Convert an NNF into CNF using the Tseitin Encoding. :param theory: Theory to convert. :param simplify: If True, simplify clauses even if that means eliminating variables. """ clauses = [] @memoize def process_node(node: NNF) -> Var: if isinstance(node, Var): return node assert isinstance(node, Internal) children = {process_node(c) for c in node.children} if len(children) == 1: [child] = children return child aux = Var.aux() if simplify and any(~var in children for var in children): if isinstance(node, And): clauses.append(Or({~aux})) else: clauses.append(Or({aux})) elif isinstance(node, And): clauses.append(Or({~c for c in children} | {aux})) for c in children: clauses.append(Or({~aux, c})) elif isinstance(node, Or): clauses.append(Or(children | {~aux})) for c in children: clauses.append(Or({~c, aux})) else: raise TypeError(node) return aux @memoize def process_required(node: NNF) -> None: """For nodes that have to be satisfied. This lets us perform some optimizations. """ if isinstance(node, Var): clauses.append(Or({node})) return assert isinstance(node, Internal) if len(node.children) == 1: [child] = node.children process_required(child) elif isinstance(node, Or): children = {process_node(c) for c in node.children} if simplify and any(~v in children for v in children): return clauses.append(Or(children)) elif isinstance(node, And): for child in node.children: process_required(child) else: raise TypeError(node) process_required(theory) ret = And(clauses) NNF._is_CNF_loose.set(ret, True) NNF._is_CNF_strict.set(ret, True) return ret