Assuming a tree in which the nodes may or may not be present, I would like to generate a formula in which:
- there's a boolean variable for each node (to represent whether it's present or not),
- a root if free (may or may not be present), and
- a node can only be present if its parent is present (child implies the parent).
My goal is to generate all possible subtrees of the given shape using allSat
. For example, consider the datatype and an example tree
:
data Tree
= Leaf
| Tree [ Tree ]
deriving Show
tree :: Tree
tree
= Tree -- T1
[ Leaf -- L1
, Tree -- T2
[ Leaf -- L2
, Leaf -- L3
]
]
translating that tree should introduce booleans for each node T1, T2, L1, L2, L3
and a set of constraints:
L1 => T1
T2 => T1
L2 => T2
L3 => T2
The following code produces the right solutions (11):
main :: IO ()
main = do
res <- allSat . forSome ["T1", "T2", "L1", "L2", "L3"] $
\ (t1::SBool) t2 l1 l2 l3 ->
( (l1 ==> t1)
&&& (t2 ==> t1)
&&& (l2 ==> t2)
&&& (l3 ==> t2)
)
putStrLn $ show res
So, how can I generate the formula given to allSat
given some concrete tree
?
An alternative solution would be to construct the action like this:
main :: IO ()
main = do
res <- allSat $ makePredicate tree
putStrLn $ show res
makePredicate :: Tree -> Predicate
makePredicate _ = do
t1 <- exists "T1"
l1 <- exists "L1"
constrain $ l1 ==> t1
t2 <- exists "T2"
constrain $ t2 ==> t1
l2 <- exists "L2"
constrain $ l2 ==> t2
l3 <- exists "L3"
constrain $ l3 ==> t2
return true
EDIT: I discovered an answer to another SO question, which is related. The idea would be to construct an action like in the alternative solution above but during the fold of the tree. That is possible because Symbolic is a monad.