@@ -1733,26 +1733,27 @@ def decision(
17331733 return (var & if_true ) | (~ var & if_false )
17341734
17351735def flatten (nnf : NNF ):
1736- set_and_children = set ()
1737- set_other = set ()
1738- operator_type = type (nnf )
1736+ """Flattens a formula by removing unnecessary extra nestings.
17391737
1738+ param var: The formula to be flattened.
1739+ """
1740+ new_children = set ()
1741+ outer_operator = type (nnf )
1742+ # iterate through all children
17401743 for c in nnf .children :
17411744 if type (c ) == Var :
1742- set_and_children .add (c )
1745+ new_children .add (c )
1746+ # atoms don't need to be nested
17431747 elif len (c .children ) == 1 :
1744- set_and_children .update (c .children )
1745- elif type (c ) == operator_type :
1746- set_and_children .update (c .children )
1748+ new_children .update (c .children )
1749+ # if the operator type is the same as the outer operator, flatten the formula
1750+ # and remove the nested operator by only taking the children (i.e. And(And()) or Or(Or()))
1751+ elif type (c ) == outer_operator :
1752+ new_children .update (flatten (c ).children )
17471753 else :
1748- set_other .add (c )
1749- nnf = operator_type (set_and_children | set_other )
1750-
1751- for c in nnf .children :
1752- if type (c ) == operator_type :
1753- return flatten (nnf )
1754- return nnf
1755-
1754+ # otherwise, continue to flatten the children but keep the operator (i.e. And(Or) or Or(And))
1755+ new_children .add (flatten (c ))
1756+ return outer_operator (new_children )
17561757
17571758#: A node that's always true. Technically an And node without children.
17581759true = And () # type: And[Bottom]
@@ -1881,4 +1882,59 @@ def __call__(self, **settings: str) -> _ConfigContext:
18811882config = _Config ()
18821883
18831884
1884- from nnf import amc , dsharp , kissat , operators , pysat , tseitin # noqa: E402
1885+ from nnf import amc , dsharp , kissat , operators , pysat , tseitin # noqa: E402
1886+
1887+ if __name__ == "__main__" :
1888+ # test nnf nesting - and
1889+ nnf_formula = Var (1 )
1890+ for i in range (10 ):
1891+ nnf_formula = nnf_formula & Var (i )
1892+ nnf_formula_2 = Var (10 )
1893+ for i in range (11 , 20 ):
1894+ nnf_formula_2 = nnf_formula_2 & Var (i )
1895+ nnf_formula_3 = nnf_formula & nnf_formula_2
1896+ print ()
1897+ print (nnf_formula )
1898+ print (nnf_formula_2 )
1899+ print (nnf_formula_3 )
1900+ print (flatten (nnf_formula_3 ))
1901+
1902+ # test nnf nesting - or
1903+ nnf_formula = Var (1 )
1904+ for i in range (10 ):
1905+ nnf_formula = nnf_formula | Var (i )
1906+ nnf_formula_2 = Var (10 )
1907+ for i in range (11 , 20 ):
1908+ nnf_formula_2 = nnf_formula_2 | Var (i )
1909+ nnf_formula_3 = nnf_formula | nnf_formula_2
1910+ print ()
1911+ print (nnf_formula )
1912+ print (nnf_formula_2 )
1913+ print (nnf_formula_3 )
1914+ print (flatten (nnf_formula_3 ))
1915+
1916+ #test nnf nesting - both and's and or's
1917+ print ()
1918+ nnf_formula = Var (1 )
1919+ for i in range (10 ):
1920+ nnf_formula = nnf_formula & (Var (i ) | Var (i + 1 ))
1921+ print (nnf_formula )
1922+ print (flatten (nnf_formula ))
1923+
1924+ print ()
1925+ nnf_formula = Var (1 )
1926+ for i in range (10 ):
1927+ nnf_formula = nnf_formula | (Var (i ) & Var (i + 1 ))
1928+ print (nnf_formula )
1929+ print (flatten (nnf_formula ))
1930+
1931+ x , a , y , z , b , c = Var ("x" ), Var ("a" ), Var ("y" ), Var ("z" ), Var ("b" ), Var ("c" )
1932+ nnf_formula = x | ((a & y ) & z & (b | c ))
1933+ print ()
1934+ print (nnf_formula )
1935+ print (flatten (nnf_formula ))
1936+
1937+ nnf_formula = x | (((a & ((y | ((x | z ) & b )) & c ))))
1938+ print ()
1939+ print (nnf_formula )
1940+ print (flatten (nnf_formula ))
0 commit comments