feat(preproc): add bounded variable elimination
This commit is contained in:
1 parent
fa34e71864
commit
4c9f61e79c
1 file changed
+82
@@ -0,0 +1,82 @@
|
|||||||
|
module Sift.Preprocess.Bve
|
||||||
|
( BveResult(..)
|
||||||
|
, bve
|
||||||
|
, reconstructBve
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Sift.Types
|
||||||
|
import Data.List (foldl')
|
||||||
|
import Data.Set (Set)
|
||||||
|
import qualified Data.Set as Set
|
||||||
|
import qualified Data.Map.Strict as Map
|
||||||
|
|
||||||
|
data BveResult = BveResult
|
||||||
|
{ bveCnf :: CNF
|
||||||
|
, bveEliminated :: [(Var, [Clause])]
|
||||||
|
} deriving (Eq, Show)
|
||||||
|
|
||||||
|
bve :: CNF -> BveResult
|
||||||
|
bve cnf =
|
||||||
|
let (finalClauses, elimsRev) = foldl' consider (toSets cnf, []) (allVars cnf)
|
||||||
|
in BveResult (fromSets finalClauses) (reverse elimsRev)
|
||||||
|
where
|
||||||
|
consider (clauses, elims) x =
|
||||||
|
let (posC, rest0) = partition' (Set.member (posLit x)) clauses
|
||||||
|
(negC, rest) = partition' (Set.member (negLit x)) rest0
|
||||||
|
in if null posC && null negC
|
||||||
|
then (clauses, elims)
|
||||||
|
else
|
||||||
|
let resolvents =
|
||||||
|
dedupe
|
||||||
|
[ r
|
||||||
|
| p <- posC, q <- negC
|
||||||
|
, Just r <- [resolve x p q] ]
|
||||||
|
in if length resolvents <= length posC + length negC
|
||||||
|
then ( rest ++ resolvents
|
||||||
|
, (x, map Set.toList (posC ++ negC)) : elims )
|
||||||
|
else (clauses, elims)
|
||||||
|
|
||||||
|
partition' :: (a -> Bool) -> [a] -> ([a], [a])
|
||||||
|
partition' p xs = (filter p xs, filter (not . p) xs)
|
||||||
|
|
||||||
|
resolve :: Var -> Set Lit -> Set Lit -> Maybe (Set Lit)
|
||||||
|
resolve x p q =
|
||||||
|
let merged = Set.union (Set.delete (posLit x) p) (Set.delete (negLit x) q)
|
||||||
|
in if isTautology merged then Nothing else Just merged
|
||||||
|
|
||||||
|
isTautology :: Set Lit -> Bool
|
||||||
|
isTautology c = any (\l -> neg l `Set.member` c) (Set.toList c)
|
||||||
|
|
||||||
|
dedupe :: [Set Lit] -> [Set Lit]
|
||||||
|
dedupe = Set.toList . Set.fromList
|
||||||
|
|
||||||
|
toSets :: CNF -> [Set Lit]
|
||||||
|
toSets (CNF cs) = map Set.fromList cs
|
||||||
|
|
||||||
|
fromSets :: [Set Lit] -> CNF
|
||||||
|
fromSets = CNF . map Set.toList
|
||||||
|
|
||||||
|
reconstructBve :: BveResult -> Assignment -> Assignment
|
||||||
|
reconstructBve result asn =
|
||||||
|
foldl' restoreVar (seedFreeVars result asn) (reverse (bveEliminated result))
|
||||||
|
where
|
||||||
|
restoreVar acc (x, cls) =
|
||||||
|
let posNeedsTrue =
|
||||||
|
any (\c -> posLit x `elem` c && not (satisfiedByOthers x c acc)) cls
|
||||||
|
in Map.insert x posNeedsTrue acc
|
||||||
|
|
||||||
|
seedFreeVars :: BveResult -> Assignment -> Assignment
|
||||||
|
seedFreeVars result asn =
|
||||||
|
foldl' (\acc v -> Map.insertWith (\_ old -> old) v True acc) asn freeVars
|
||||||
|
where
|
||||||
|
eliminated = Set.fromList (map fst (bveEliminated result))
|
||||||
|
freeVars =
|
||||||
|
[ v
|
||||||
|
| (_, cls) <- bveEliminated result
|
||||||
|
, c <- cls, l <- c
|
||||||
|
, let v = litVar l
|
||||||
|
, not (Set.member v eliminated) ]
|
||||||
|
|
||||||
|
satisfiedByOthers :: Var -> Clause -> Assignment -> Bool
|
||||||
|
satisfiedByOthers x c asn =
|
||||||
|
any (\l -> litVar l /= x && litValue asn l == Just True) c
|
||||||
Reference in new issue
Block a user