{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TransformListComp #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-}
module Control.CP.EnumTerm (
EnumTerm(..),
assignment, assignments,
inOrder, firstFail, middleOut, endsOut,
labelling, levelList, enumerate
) where
import GHC.Exts (sortWith)
import Control.CP.Solver
import Control.CP.SearchTree
class (Solver s, Term s t, Show (TermBaseType s t)) => EnumTerm s t where
type TermBaseType s t :: *
getDomainSize :: t -> s (Int)
getDomain :: t -> s [TermBaseType s t]
setValue :: t -> TermBaseType s t -> s [Constraint s]
splitDomain :: t -> s ([[Constraint s]],Bool)
splitDomains :: [t] -> s ([[Constraint s]],[t])
getValue :: t -> s (Maybe (TermBaseType s t))
defaultOrder :: [t] -> s [t]
enumerator :: (MonadTree m, TreeSolver m ~ s) => Maybe ([t] -> m ())
getDomainSize x = do
r <- getDomain x
return $ length r
getValue x = do
d <- getDomain x
return $ case d of
[v] -> Just v
_ -> Nothing
splitDomain x = do
d <- getDomain x
case d of
[] -> return ([],True)
[_] -> return ([[]],True)
_ -> do
rr <- mapM (setValue x) d
return (rr,True)
splitDomains [] = return ([[]],[])
splitDomains (a@(x:b)) = do
s <- getDomainSize x
if s==0
then return ([],[])
else if s==1
then splitDomains b
else do
(r,v) <- splitDomain x
if v
then return (r,b)
else return (r,a)
defaultOrder = firstFail
enumerator = Nothing
enumerate :: (MonadTree m, TreeSolver m ~ s, EnumTerm s t) => [t] -> m ()
enumerate = case enumerator of
Nothing -> labelling defaultOrder
Just x -> x
assignment :: (EnumTerm s t, MonadTree m, TreeSolver m ~ s) => t -> m (TermBaseType s t)
assignment q = label $ getValue q >>= \y -> (case y of Just x -> return $ return x; _ -> return false)
assignments :: (EnumTerm s t, MonadTree m, TreeSolver m ~ s) => [t] -> m [TermBaseType s t]
assignments = mapM assignment
firstFail :: EnumTerm s t => [t] -> s [t]
firstFail qs = do ds <- mapM getDomainSize qs
return [ q | (d,q) <- zip ds qs
, then sortWith by d ]
inOrder :: EnumTerm s t => [t] -> s [t]
inOrder = return
middleOut :: EnumTerm s t => [t] -> s [t]
middleOut l = let n = (length l) `div` 2 in
return $ interleave (drop n l) (reverse $ take n l)
endsOut :: EnumTerm s t => [t] -> s [t]
endsOut l = let n = (length l) `div` 2 in
return $ interleave (reverse $ drop n l) (take n l)
interleave [] ys = ys
interleave (x:xs) ys = x:interleave ys xs
levelList :: (Solver s, MonadTree m, TreeSolver m ~ s) => [m ()] -> m ()
levelList [] = false
levelList [a] = a
levelList l =
let len = length l
(p1,p2) = splitAt (len `div` 2) l
in (levelList p1) \/ (levelList p2)
labelling :: (MonadTree m, TreeSolver m ~ s, EnumTerm s t) => ([t] -> s [t]) -> [t] -> m ()
labelling _ [] = true
labelling o l = label $ do
ll <- o l
(cl,c) <- splitDomains ll
let ml = map (\l -> foldr (/\) true $ map addC l) cl
return $ do
levelList ml
labelling return c