satplus-0.1.0.0: SAT/Val.hs
{-|
Module : SAT.Val
Description : Functions for working with symbolic values
-}
module SAT.Val(
-- * The Val type
Val
, newVal
, val
-- * Inspection
, (.=)
, domain
-- * Models
, modelValue
)
where
import qualified SAT
import SAT hiding ( modelValue )
import SAT.Util( usort )
import SAT.Bool( atMostOne )
import SAT.Equal
import SAT.Order
import Data.List( tails )
import Control.Monad( when )
------------------------------------------------------------------------------
-- | The Val type, for representing symbolic values.
newtype Val a = Val [(Lit,a)]
deriving ( Eq, Ord, Show )
-- | Creates a symbolic value, with concrete values all elements of the
-- specified list. The list has to be non-empty.
newVal :: Ord a => Solver -> [a] -> IO (Val a)
newVal s xs =
case xs' of
[] -> do error "SAT.Val.newVal: empty list"
[x] -> do return (val x)
[x,y] -> do q <- newLit s
return (Val [(q,x),(neg q,y)])
_ -> do qs <- sequence [ newLit s | x <- xs' ]
addClause s qs
atMostOne s qs
return (Val (qs `zip` xs'))
where
xs' = usort xs
-- | Creates a symbolic value with only one concrete element.
val :: a -> Val a
val x = Val [(true,x)]
-- | Returns all possible concrete values for a symbolic value.
domain :: Val a -> [a]
domain (Val qxs) = map snd qxs
-- | Returns the literal representing the symbolic value having the concrete
-- specified value.
(.=) :: Ord a => Val a -> a -> Lit
Val qxs .= x = go qxs
where
go [] = false
go ((q,y):qxs) =
case x `compare` y of
LT -> false
EQ -> q
GT -> go qxs
------------------------------------------------------------------------------
instance Ord a => Equal (Val a) where
equalOr s pre p q =
sequence_
[ case pqx of
(Just p, Nothing, _) -> addClause s (neg p : pre)
(Nothing, Just q, _) -> addClause s (neg q : pre)
(Just p, Just q, _) -> addClause s (neg p : q : pre)
| pqx <- stitch p q
]
notEqualOr s pre p q =
sequence_
[ case pqx of
(Just p, Just q, _) -> addClause s (neg p : neg q : pre)
_ -> return ()
| pqx <- stitch p q
]
instance Ord a => Order (Val a) where
lessTupleOr s pre incl (x,p) (y,q) =
do w <- newLessLit s incl p q
when (w /= true) $
notEqualOr s (w:pre) x y
sandwich false true n xys
where
xys = [ (lit a,lit b) | (a,b,_) <- stitch x y ]
n = length xys
lit Nothing = false
lit (Just x) = x
sandwich lft rgt _ [] =
do return ()
sandwich lft rgt n xys | n <= 2 =
do sequence_ [ addClause s (neg lft : neg x : pre) | (x,_) <- xys ]
sequence_ [ addClause s (rgt : neg y : pre) | (_,y) <- xys ]
sequence_ [ addClause s (neg y : neg x : pre)
| (_,y):xys' <- tails xys
, (x,_) <- xys'
]
sandwich lft rgt n xys =
do lft' <- newLit s
rgt' <- newLit s
addClause s [neg lft, lft']
addClause s [neg rgt', lft']
addClause s [neg rgt', rgt]
sandwich lft rgt' k (take k xys)
sandwich lft' rgt (n-k) (drop k xys)
where
k = n `div` 2
stitch :: Ord a => Val a -> Val a -> [(Maybe Lit, Maybe Lit, a)]
stitch (Val pxs) (Val qys) = go pxs qys
where
go [] qys = [ (Nothing, Just q, y) | (q,y) <- qys ]
go pxs [] = [ (Just p, Nothing, x) | (p,x) <- pxs ]
go ((p,x):pxs) ((q,y):qys) =
case x `compare` y of
LT -> (Just p, Nothing, x) : go pxs ((q,y):qys)
EQ -> (Just p, Just q, x) : go pxs qys
GT -> (Nothing, Just q, y) : go ((p,x):pxs) qys
------------------------------------------------------------------------------
-- | Returns the concrete value of the symbolic value in the found model.
-- (/Only use when 'solve' has returned True!/)
modelValue :: Solver -> Val a -> IO a
modelValue s (Val qxs) = go qxs
where
go [] = error "SAT.Val.modelValue: no trues in list"
go ((q,x):qxs) = do b <- SAT.modelValue s q
if b then return x else go qxs
------------------------------------------------------------------------------