module Funsat.Utils where
import Control.Monad.ST.Strict
import Control.Monad.State.Lazy hiding ( (>=>), forM_ )
import Data.Array.ST
import Data.Array.Unboxed
import Data.Foldable hiding ( sequence_ )
import Data.Graph.Inductive.Graph( DynGraph, Graph )
import Data.List( foldl1' )
import Data.Map (Map)
import Data.Set (Set)
import Debug.Trace( trace )
import Funsat.Types
import Prelude hiding ( sum, concatMap, elem, foldr, foldl, any, maximum )
import System.IO.Unsafe( unsafePerformIO )
import System.IO( hPutStr, stderr )
import qualified Data.Foldable as Fl
import qualified Data.Graph.Inductive.Graph as Graph
import qualified Data.Graph.Inductive.Query.DFS as DFS
import qualified Data.List as List
import qualified Data.Map as Map
import qualified Data.Set as Set
isUndefUnder :: Model a m => a -> m -> Bool
isUndefUnder x m = isUndef $ x `statusUnder` m
where isUndef (Left ()) = True
isUndef _ = False
isTrueUnder :: Model a m => a -> m -> Bool
isTrueUnder x m = isTrue $ x `statusUnder` m
where isTrue (Right True) = True
isTrue _ = False
isFalseUnder :: Model a m => a -> m -> Bool
isFalseUnder x m = isFalse $ x `statusUnder` m
where isFalse (Right False) = True
isFalse _ = False
isUnitUnder :: (Model a m) => [a] -> m -> Bool
isUnitUnder c m = isSingle (filter (not . (`isFalseUnder` m)) c)
&& not (Fl.any (`isTrueUnder` m) c)
getUnit :: (Model a m, Show a) => [a] -> m -> a
getUnit c m = case filter (not . (`isFalseUnder` m)) c of
[u] -> u
xs -> error $ "getUnit: not unit: " ++ show xs
mytrace msg expr = unsafePerformIO $ do
hPutStr stderr msg
return expr
outputConflict fn g x = unsafePerformIO $ do writeFile fn g
return x
isSingle :: [a] -> Bool
isSingle [_] = True
isSingle _ = False
modifySlot :: (MonadState s m) => (s -> a) -> (s -> a -> s) -> m ()
modifySlot slot f = modify $ \s -> f s (slot s)
modifyArray :: (Monad m, MArray a e m, Ix i) => a i e -> i -> (i -> e -> e) -> m ()
modifyArray arr i f = readArray arr i >>= writeArray arr i . (f i)
newSTUArray :: (MArray (STUArray s) e (ST s), Ix i)
=> (i, i) -> e -> ST s (STUArray s i e)
newSTUArray = newArray
newSTArray :: (MArray (STArray s) e (ST s), Ix i)
=> (i, i) -> e -> ST s (STArray s i e)
newSTArray = newArray
count :: (a -> Bool) -> [a] -> Int
count p = foldl' f 0
where f x y | p y = x + 1
| otherwise = x
argmin :: Ord b => (a -> b) -> a -> a -> a
argmin f x y = if f x <= f y then x else y
argminimum :: Ord b => (a -> b) -> [a] -> a
argminimum f = foldl1' (argmin f)
tracing :: (Show a) => a -> a
tracing x = trace (show x) x
p .&&. q = \x -> p x && q x
uipCut :: (Graph gr) =>
[Lit]
-> FrozenLevelArray
-> gr a b
-> Graph.Node
-> Graph.Node
-> Cut Set gr a b
uipCut dlits levelArr conflGraph conflNode uip =
Cut { reasonSide = Set.filter (\i -> levelArr!(V $ abs i) > 0) $
allNodes Set.\\ impliedByUIP
, conflictSide = impliedByUIP
, cutUIP = uip
, cutGraph = conflGraph }
where
impliedByUIP = Set.insert extraNode $
Set.fromList $ tail $ DFS.reachable uip conflGraph
extraNode = if L (negate conflNode) `elem` dlits || negate conflNode == uip
then conflNode
else negate conflNode
allNodes = Set.fromList $ Graph.nodes conflGraph
cutLearn :: (Graph gr, Foldable f) => IAssignment -> FrozenLevelArray
-> Cut f gr a b -> (Clause, Int)
cutLearn a levelArr cut =
( clause
, maximum0 (map (levelArr!) . (`without` V (abs $ cutUIP cut)) . map var $ clause) )
where
clause =
foldl' (\ls i ->
if any (`elem` conflictSide cut) (Graph.suc (cutGraph cut) i)
then L (negate $ a!(V $ abs i)):ls
else ls)
[] (reasonSide cut)
maximum0 [] = 0
maximum0 xs = maximum xs
mkConflGraph :: DynGraph gr =>
IAssignment
-> FrozenLevelArray
-> Map Var Clause
-> [Lit]
-> (Lit, Clause)
-> gr CGNodeAnnot ()
mkConflGraph mFr lev reasonMap _dlits (cLit, confl) =
Graph.mkGraph nodes' edges'
where
nodes' =
((0, CGNA (L 0) (1)) :) $
((unLit cLit, CGNA cLit (1)) :) $
((negate (unLit cLit), CGNA (negate cLit) (lev!(var cLit))) :) $
map (\v -> (unVar v, CGNA (varToLit v) (lev!v))) $
filter (\v -> v /= var cLit) $
toList nodeSet'
(nodeSet', edges') =
mkGr Set.empty (Set.empty, [ (unLit cLit, 0, ())
, ((negate . unLit) cLit, 0, ()) ])
[negate cLit, cLit]
varToLit v = (if v `isTrueUnder` mFr then id else negate) $ L (unVar v)
mkGr _ ne [] = ne
mkGr (seen :: Set Graph.Node) ne@(nodes, edges) (lit:lits) =
if haveSeen
then mkGr seen ne lits
else newNodes `seq` newEdges `seq`
mkGr seen' (newNodes, newEdges) (lits ++ pred)
where
haveSeen = seen `contains` litNode lit
newNodes = var lit `Set.insert` nodes
newEdges = [ ( litNode (negate x)
, litNode lit, () )
| x <- pred ] ++ edges
pred = filterReason $
if lit == cLit then confl else
Map.findWithDefault [] (var lit) reasonMap `without` lit
filterReason = filter ( ((var lit /=) . var) .&&.
((<= litLevel lit) . litLevel) )
seen' = seen `with` litNode lit
litLevel l = if l == cLit then length _dlits else lev!(var l)
litNode l =
if var l == var cLit
then unLit l
else (abs . unLit) l