{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE DatatypeContexts #-}
module Control.CP.FD.FD (
module Data.Expr.Sugar,
FDInstance,
FDSolver(..),
FDSpecInfo,
FDSpecInfoBool(..), FDSpecInfoInt(..), FDSpecInfoCol(..),
liftFD, addFD,
SpecFn, SpecFnRes, SpecResult(..),
getBoolSpec_, getIntSpec_, getColSpec_,
getBoolSpec, getIntSpec, getColSpec,
getEdge, markEdge,
setFailed,
getLevel,
getIntVal, getBoolVal, getColVal,
getIntTerm, getBoolTerm, getColTerm,
getSingleIntTerm,
getDefBoolSpec, getDefIntSpec, getDefColSpec,
getFullBoolSpec, getFullIntSpec, getFullColSpec,
getColItems,
fdSpecInfo_spec,
specInfoBoolTerm, specInfoIntTerm,
Control.CP.FD.FD.newInt, Control.CP.FD.FD.newBool, Control.CP.FD.FD.newCol,
procSubModel, procSubModelEx, specSubModelEx,
runFD,
setMinimizeVar, boundMinimize, getMinimizeTerm, getMinimizeVar,
fdNewvar,
) where
import Control.Monad.State.Lazy
import Control.Monad.Trans
import qualified Data.Map as Map
import Data.Map(Map)
import Data.Maybe
import Data.List
import qualified Data.Set as Set
import Data.Set(Set)
import Control.CP.Debug
import Data.Expr.Sugar
import Data.Expr.Data
import Control.CP.FD.Model
import Control.CP.FD.Decompose
import Control.CP.FD.Graph
import Control.CP.SearchTree
import Control.CP.ComposableTransformers
import Control.CP.EnumTerm
import Control.CP.Solver
import Control.Mixin.Mixin
data FDSolver s => FDState s = FDState {
fdsExpr :: Model,
fdsModel :: Maybe EGModel,
fdsDecomp :: DecompData,
fdsNewEdges :: Set EGEdgeId,
fdsDoneEdges :: Set EGEdgeId,
fdsForceBool :: [ModelBool], fdsForcedBool :: Map ModelBool (FDBoolTerm s),
fdsForceInt :: [ModelInt], fdsForcedInt :: Map ModelInt (FDIntTerm s),
fdsForceCol :: [ModelCol],
fdsVars :: Int,
fdsIntVars :: Map EGVarId (FDSpecInfoInt s),
fdsIntVarTypes :: Map EGVarId (Set (FDIntSpecTypeSet s)),
fdsIntVarBusy :: Set EGVarId,
fdsIntUnifies :: Map EGVarId (Set EGVarId),
fdsBoolVars :: Map EGVarId (FDSpecInfoBool s),
fdsBoolVarTypes :: Map EGVarId (Set (FDBoolSpecTypeSet s)),
fdsBoolVarBusy :: Set EGVarId,
fdsBoolUnifies :: Map EGVarId (Set EGVarId),
fdsColVars :: Map EGVarId (FDSpecInfoCol s),
fdsColVarTypes :: Map EGVarId (Set (FDColSpecTypeSet s)),
fdsColVarBusy :: Set EGVarId,
fdsColUnifies :: Map EGVarId (Set EGVarId),
fdsDb :: SpecDb s,
fdsFailed :: Bool,
fdsLevel :: Int,
fdsDummyLevel :: Int,
fdsMinimizeVar :: Maybe ModelInt,
fdsMinimizeTerm :: Maybe (FDIntTerm s)
}
myFromJust str m = case m of
Nothing -> error $ "myFromJust: " ++ str
Just x -> x
unifyInts a b = do
s <- get
let sa = Map.findWithDefault (Set.singleton a) a (fdsIntUnifies s)
let sb = Map.findWithDefault (Set.singleton b) b (fdsIntUnifies s)
let sc = Set.union sa sb
put s { fdsIntUnifies = foldr (\a b -> Map.insert a sc b) (fdsIntUnifies s) $ Set.toList sc }
unifyBools a b = do
s <- get
let sa = Map.findWithDefault (Set.singleton a) a (fdsBoolUnifies s)
let sb = Map.findWithDefault (Set.singleton b) b (fdsBoolUnifies s)
let sc = Set.union sa sb
put s { fdsBoolUnifies = foldr (\a b -> Map.insert a sc b) (fdsBoolUnifies s) $ Set.toList sc }
unifyCols a b = do
s <- get
let sa = Map.findWithDefault (Set.singleton a) a (fdsColUnifies s)
let sb = Map.findWithDefault (Set.singleton b) b (fdsColUnifies s)
let sc = Set.union sa sb
put s { fdsColUnifies = foldr (\a b -> Map.insert a sc b) (fdsColUnifies s) $ Set.toList sc }
mapVals :: Show b => (a -> Maybe b) -> [a] -> [String]
mapVals f l = nub $ sort $ map show $ catMaybes $ map f l
dumpSpec :: FDSolver s => FDState s -> String
dumpSpec s =
foldl (++) "" (map (\(i,r) -> "i" ++ (show $ unVarId i) ++ "\n" ++ foldl (++) "" (map (\x -> " "++x++"\n") (mapVals (fdspIntSpec r) (Nothing : (map Just $ Set.toList $ fdspIntTypes r))))) $ Map.toList (fdsIntVars s)) ++
foldl (++) "" (map (\(i,r) -> "b" ++ (show $ unVarId i) ++ "\n" ++ foldl (++) "" (map (\x -> " "++x++"\n") (mapVals (fdspBoolSpec r) (Nothing : (map Just $ Set.toList $ fdspBoolTypes r))))) $ Map.toList (fdsBoolVars s)) ++
foldl (++) "" (map (\(i,r) -> "c" ++ (show $ unVarId i) ++ "\n" ++ foldl (++) "" (map (\x -> " "++x++"\n") (mapVals (fdspColSpec r) (Nothing : (map Just $ Set.toList $ fdspColTypes r))))) $ Map.toList (fdsColVars s))
setMinimizeVar :: (Show (FDIntTerm s), FDSolver s) => ModelInt -> FDInstance s ()
setMinimizeVar v = do
s <- get
case Map.lookup v (fdsForcedInt s) of
Just t -> debug ("setMinimizeVar: (cached) var="++(show v)++" term="++(show t)) $ put s { fdsMinimizeVar = Just v, fdsMinimizeTerm = Just t }
Nothing -> do
var <- getSingleIntTerm v
s2 <- get
debug ("setMinimizeVar: (not cached) var="++(show v)++" term="++(show var)) $ put s2 { fdsMinimizeVar = Just v, fdsMinimizeTerm = Just var }
getMinimizeVar :: (Show (FDIntTerm s), FDSolver s) => FDInstance s (Maybe ModelInt)
getMinimizeVar = do
s <- get
return $ fdsMinimizeVar s
getMinimizeTerm :: (Show (FDIntTerm s), FDSolver s) => FDInstance s (Maybe (FDIntTerm s))
getMinimizeTerm = do
s <- get
debug ("getMinimizeTerm: "++(show $ fdsMinimizeTerm s)) $ return ()
return (fdsMinimizeTerm s)
boundMinimize :: (Show (FDIntTerm s), FDSolver s, EnumTerm s (FDIntTerm s), Integral (TermBaseType s (FDIntTerm s))) => NewBound (FDInstance s)
boundMinimize = do
bound <- getMinimizeTerm
case bound of
Nothing -> error "no bound variable defined"
Just bndvar -> do
x <- liftFD $ getValue bndvar
case x of
Just val -> do
con <- liftFD $ fdConstrainIntTerm bndvar (toInteger val)
let f = Bound (\x -> (Add (Right con) x))
return f
_ -> error "bound variable is not assigned"
runFD :: FDSolver s => FDInstance s a -> s a
runFD (FDInstance { unFDInstance = u }) = evalStateT u baseFDState
linkExterns :: FDSolver s => (Int -> Maybe (FDSpecInfoBool s), Int -> Maybe (FDSpecInfoInt s), Int -> Maybe (FDSpecInfoCol s)) -> EGEdgeId -> FDInstance s ()
linkExterns (sfb,sfi,sfc) id = do
s <- get
let Just jm = fdsModel s
let Just edge = Map.lookup id $ egmEdges jm
case (egeCons edge) of
EGBoolExtern p -> do
case sfb p of
Nothing -> return ()
Just spec -> do
let [varid] = boolData $ egeLinks edge
if (Map.member varid $ fdsBoolVars s) then error "double bool import" else return ()
put $ s { fdsBoolVars = Map.insert varid spec $ fdsBoolVars s, fdsBoolVarTypes = Map.delete varid $ fdsBoolVarTypes s }
markEdge id
EGIntExtern p -> do
case sfi p of
Nothing -> return ()
Just spec -> do
let [varid] = intData $ egeLinks edge
if (Map.member varid $ fdsIntVars s) then error "double int import" else return ()
put $ s { fdsIntVars = Map.insert varid spec $ fdsIntVars s, fdsIntVarTypes = Map.delete varid $ fdsIntVarTypes s }
markEdge id
EGColExtern p -> do
case sfc p of
Nothing -> return ()
Just spec -> do
let [varid] = colData $ egeLinks edge
if (Map.member varid $ fdsColVars s) then error "double col import" else return ()
put $ s { fdsColVars = Map.insert varid spec $ fdsColVars s, fdsColVarTypes = Map.delete varid $ fdsColVarTypes s }
markEdge id
_ -> return ()
procSubModel :: FDSolver s => EGModel -> (Int -> FDSpecInfoBool s, Int -> FDSpecInfoInt s, Int -> FDSpecInfoCol s) -> FDInstance s ()
procSubModel sm (fb,fi,fc) = procSubModelEx sm (Just . fb,Just . fi,Just . fc)
procSubModelEx :: FDSolver s => EGModel -> (Int -> Maybe (FDSpecInfoBool s), Int -> Maybe (FDSpecInfoInt s), Int -> Maybe (FDSpecInfoCol s)) -> FDInstance s ()
procSubModelEx sm specfn = do
s <- get
let ss = baseFDState {
fdsModel = Just sm,
fdsVars = fdsVars s,
fdsFailed = fdsFailed s,
fdsLevel = 1 + fdsLevel s
}
put ss
initForModel
s2 <- get
mapM_ (linkExterns specfn) $ Set.toList $ fdsNewEdges s2
process
s3 <- get
put $ s { fdsFailed = fdsFailed s || fdsFailed s3, fdsVars = fdsVars s3 }
getLevel :: FDSolver s => FDInstance s Int
getLevel = do
s <- get
return $ fdsLevel s
specSubModelEx sm specfn = do
s <- get
let ss = baseFDState {
fdsModel = Just sm,
fdsVars = fdsVars s,
fdsFailed = fdsFailed s,
fdsLevel = 1 + fdsLevel s
}
put ss
initForModel
s2 <- get
mapM_ (linkExterns specfn) $ Set.toList $ fdsNewEdges s2
s3 <- get
put s3 { fdsDummyLevel = 1 }
processEx False
s4 <- get
put $ s { fdsFailed = fdsFailed s || fdsFailed s4, fdsVars = fdsVars s4 }
return (fdsBoolVars s4, fdsIntVars s4, fdsColVars s4)
optimizeSetSet :: Ord a => Set (Set a) -> Set (Set a)
optimizeSetSet x =
let (min,xx) = Set.deleteFindMin x
inter = Set.fold Set.intersection min xx
in if Set.null inter then x else Set.singleton inter
optimizeVarTypes :: FDSolver s => FDInstance s ()
optimizeVarTypes = do
s <- get
put $ s {
fdsBoolVarTypes = Map.map optimizeSetSet $ fdsBoolVarTypes s,
fdsIntVarTypes = Map.map optimizeSetSet $ fdsIntVarTypes s,
fdsColVarTypes = Map.map optimizeSetSet $ fdsColVarTypes s
}
checkNeedSpecType var typ db = any (Set.member typ) $ Set.toList $ Map.findWithDefault Set.empty var db
decompSpec fn db un unfn ex vars typs = do
s <- get
let tri [] = do
debug ("decompSpec vars="++(show vars)++": no spec left, failing") $ return ()
return Nothing
tri (((_,_,id),_):rest) | not (Set.member id vars) = tri rest
tri ((key@(_,_,id),(eid,s)):rest) = case ex s of
Nothing -> tri rest
Just spec -> do
res <- spec
case res of
SpecResNone -> tri rest
SpecResSpec (typ,spec) -> if Set.member typ typs
then do
rr <- liftFD spec
debug ("decompSpec: got spec: " ++ (show rr)) $ return ()
fn (Set.findMin vars) typ rr
case eid of
Nothing -> return ()
Just e -> do
debug ("decompSpec: marking edge "++(show e)) $ return ()
markEdge e
return $ Just (typ,rr)
else tri rest
SpecResUnify v -> do
unfn id v
decompSpec fn db un unfn ex vars typs
tri $ Map.toDescList $ db
decompBestHelp id spec fn unfn eid prio db = do
res <- spec
case res of
SpecResNone -> do
debug ("decompBestHelp: level "++(show prio)++" specifier for var "++(show id)++" by edge "++(show eid)++" has failed") $ return ()
return ()
SpecResSpec (typ,ss) -> if checkNeedSpecType id typ db
then do
rr <- liftFD ss
res <- fn id typ rr
case eid of
Nothing -> return ()
Just e -> do
debug ("decompBestHelp: marking edge "++(show e)) $ return ()
markEdge e
return ()
return res
else do
debug ("decompBestHelp: typ "++(show typ)++" specifier for id "++(show id)++" seems not needed") $ return ()
return ()
SpecResUnify v -> do
unfn id v
return ()
decompBest :: FDSolver s => FDInstance s Bool
decompBest = do
s1 <- debug "in decompBest: get" $ get
debug "in decompBest" $ return ()
if Map.null $ fdsDb s1
then return False
else do
let (((prio,knd,id),(eid,spec)),nm) = Map.deleteFindMax $ fdsDb $ debug "s1?" s1
s2 = debug ("got best spec: prio="++(show prio)++", knd="++(show knd)++", id="++(show id)++", eid="++(show eid)++", spec=?") $ s1 { fdsDb = nm }
put s2
case knd of
FDTBool -> do
let s3 = s2 { fdsBoolVarBusy = Set.insert id $ fdsBoolVarBusy s2 }
put s3
let Just j = fdsBoolSel spec
decompBestHelp id j addBoolVar unifyBools eid prio $ fdsBoolVarTypes s3
s4 <- get
put $ s4 { fdsBoolVarBusy = Set.delete id $ fdsBoolVarBusy s4 }
FDTInt -> do
let s3 = s2 { fdsIntVarBusy = Set.insert id $ fdsIntVarBusy s2 }
put s3
let Just j = fdsIntSel spec
decompBestHelp id j addIntVar unifyInts eid prio $ fdsIntVarTypes s3
s4 <- get
put $ s4 { fdsIntVarBusy = Set.delete id $ fdsIntVarBusy s4 }
FDTCol -> do
let s3 = s2 { fdsColVarBusy = Set.insert id $ fdsColVarBusy s2 }
put s3
let Just j = fdsColSel spec
decompBestHelp id j addColVar unifyCols eid prio $ fdsColVarTypes s3
s4 <- get
put $ s4 { fdsColVarBusy = Set.delete id $ fdsColVarBusy s4 }
return True
decompDefaultBool :: FDSolver s => FDInstance s Bool
decompDefaultBool = do
s1 <- get
if Map.null $ fdsBoolVarTypes s1
then return False
else do
let ((varid,set),nm) = Map.deleteFindMin $ fdsBoolVarTypes s1
s2 = s1 { fdsBoolVarTypes = nm }
put s2
if Set.null set
then return True
else do
defaultBoolDecomp varid Nothing
return True
decompDefaultInt :: FDSolver s => FDInstance s Bool
decompDefaultInt = do
s1 <- get
if Map.null $ fdsIntVarTypes s1
then return False
else do
let ((varid,set),nm) = Map.deleteFindMin $ fdsIntVarTypes s1
s2 = s1 { fdsIntVarTypes = nm }
put s2
if Set.null set
then return True
else do
defaultIntDecomp varid Nothing
return True
defaultBoolDecomp :: FDSolver s => EGVarId -> (Maybe (FDBoolSpecTypeSet s)) -> FDInstance s (Maybe (FDBoolSpecType s, FDBoolSpec s))
defaultBoolDecomp var typs = do
s <- get
if fdsDummyLevel s > 0
then return Nothing
else do
vt <- liftFD $ fdTypeVarBool
let Just jt = typs
if (isNothing typs || not (Set.null $ Set.intersection vt jt))
then do
Just v <- fdNewvar
let (ty,sp) = fdBoolSpec_term v
rs <- liftFD sp
addBoolVar var ty (rs, Nothing)
return $ Just (ty,rs)
else return Nothing
defaultIntDecomp :: FDSolver s => EGVarId -> (Maybe (FDIntSpecTypeSet s)) -> FDInstance s (Maybe (FDIntSpecType s, FDIntSpec s))
defaultIntDecomp var typs = do
s <- get
if fdsDummyLevel s > 0
then return Nothing
else do
vt <- liftFD $ fdTypeVarInt
let Just jt = typs
if (isNothing typs || not (Set.null $ Set.intersection vt jt))
then do
Just v <- fdNewvar
let (ty,sp) = fdIntSpec_term v
rs <- liftFD sp
addIntVar var ty (rs, Nothing)
return $ Just (ty,rs)
else return Nothing
getBoolSpec_ :: FDSolver s => EGVarId -> FDBoolSpecTypeSet s -> FDInstance s (Maybe (FDBoolSpecType s, FDBoolSpec s))
getBoolSpec_ var typs = do
s <- get
let vars = Map.findWithDefault (Set.singleton var) var $ fdsBoolUnifies s
getBoolSpec__ vars typs
getBoolSpec__ :: FDSolver s => Set EGVarId -> FDBoolSpecTypeSet s -> FDInstance s (Maybe (FDBoolSpecType s, FDBoolSpec s))
getBoolSpec__ vars typs = do
s <- get
let mp = foldl (\b a -> case Map.lookup a (fdsBoolVars s) of { Nothing -> b; Just x -> case b of { Nothing -> Just x; Just r -> Just $ unionSpecBool r x }}) Nothing (Set.toList vars)
let sp = Set.intersection (maybe Set.empty fdspBoolTypes mp) typs
let db = fdsDb s
if Set.null sp
then if not (Set.null $ Set.intersection vars $ fdsBoolVarBusy s)
then return Nothing
else do
put $ s { fdsBoolVarBusy = Set.union vars $ fdsBoolVarBusy s }
res <- decompSpec addBoolVar db (\x -> Map.lookup x $ fdsBoolUnifies s) unifyBools fdsBoolSel vars typs
s2 <- get
put $ s2 { fdsBoolVarBusy = Set.difference (fdsBoolVarBusy s) vars }
case res of
Just (tp,(sp,_)) -> return $ Just (tp,sp)
_ -> defaultBoolDecomp (Set.findMin vars) $ Just typs
else do
let lp = Set.findMin sp
let Just jmp = mp
let Just j = fdspBoolSpec jmp $ Just lp
return $ Just (lp,j)
getBoolSpec :: FDSolver s => EGVarId -> FDInstance s (Maybe (FDBoolSpec s))
getBoolSpec var = do
s <- allBoolSpec
q <- getBoolSpec_ var s
return $ case q of
Just (_,x) -> Just x
Nothing -> Nothing
getIntSpec_ :: FDSolver s => EGVarId -> FDIntSpecTypeSet s -> FDInstance s (Maybe (FDIntSpecType s, FDIntSpec s))
getIntSpec_ var typs = do
s <- get
let vars = Map.findWithDefault (Set.singleton var) var $ fdsIntUnifies s
getIntSpec__ vars typs
getIntSpec__ :: FDSolver s => Set EGVarId -> FDIntSpecTypeSet s -> FDInstance s (Maybe (FDIntSpecType s, FDIntSpec s))
getIntSpec__ vars typs = do
s <- get
let mp = foldl (\b a -> case Map.lookup a (fdsIntVars s) of { Nothing -> b; Just x -> case b of { Nothing -> Just x; Just r -> Just $ unionSpecInt r x }}) Nothing $ Set.toList vars
let sp = Set.intersection (maybe Set.empty fdspIntTypes mp) typs
let db = fdsDb s
if Set.null sp
then if not (Set.null $ Set.intersection vars $ fdsIntVarBusy s)
then do
debug ("getIntSpec__ "++(show (vars,typs))++": busy, failing") $ return ()
return Nothing
else do
put $ s { fdsIntVarBusy = Set.union vars $ fdsIntVarBusy s }
res <- decompSpec addIntVar db (\x -> Map.lookup x $ fdsIntUnifies s) unifyInts fdsIntSel vars typs
s2 <- get
put $ s2 { fdsIntVarBusy = Set.difference (fdsIntVarBusy s) vars }
case res of
Just (tp,(sp,_)) -> return $ Just (tp,sp)
_ -> defaultIntDecomp (Set.findMin vars) $ Just typs
else do
let lp = Set.findMin sp
let Just jmp = mp
let Just j = fdspIntSpec jmp $ Just lp
return $ Just (lp,j)
getIntSpec :: FDSolver s => EGVarId -> FDInstance s (Maybe (FDIntSpec s))
getIntSpec var = do
s <- allIntSpec
q <- getIntSpec_ var s
return $ case q of
Just (_,x) -> Just x
Nothing -> Nothing
getColSpec_ :: FDSolver s => EGVarId -> FDColSpecTypeSet s -> FDInstance s (Maybe (FDColSpecType s, FDColSpec s))
getColSpec_ var typs = do
s <- get
let vars = Map.findWithDefault (Set.singleton var) var $ fdsColUnifies s
getColSpec__ vars typs
getColSpec__ :: FDSolver s => Set EGVarId -> FDColSpecTypeSet s -> FDInstance s (Maybe (FDColSpecType s, FDColSpec s))
getColSpec__ vars typs = do
s <- get
let mp = foldl (\b a -> case Map.lookup a (fdsColVars s) of { Nothing -> b; Just x -> case b of { Nothing -> Just x; Just r -> Just $ unionSpecCol r x }}) Nothing (Set.toList vars)
let sp = Set.intersection (maybe Set.empty fdspColTypes mp) typs
let db = fdsDb s
if Set.null sp
then if not (Set.null $ Set.intersection vars $ fdsColVarBusy s)
then return Nothing
else do
put $ s { fdsColVarBusy = Set.union vars $ fdsColVarBusy s }
res <- decompSpec addColVar db (\x -> Map.lookup x $ fdsColUnifies s) unifyCols fdsColSel vars typs
s2 <- get
put $ s2 { fdsColVarBusy = Set.difference (fdsColVarBusy s) vars }
case res of
Just (tp,(sp,_)) -> return $ Just (tp,sp)
_ -> return Nothing
else do
let lp = Set.findMin sp
let Just jmp = mp
let Just j = fdspColSpec jmp $ Just lp
return $ Just (lp,j)
getColSpec :: (Show (FDColSpec s), FDSolver s) => EGVarId -> FDInstance s (Maybe (FDColSpec s))
getColSpec var = do
s <- allColSpec
q <- getColSpec_ var s
return $ case q of
Just (_,x) -> Just x
Nothing -> Nothing
baseFDState :: FDSolver s => FDState s
baseFDState = FDState {
fdsVars = 0,
fdsExpr = BoolConst True,
fdsForceBool = [],
fdsForcedBool = Map.empty,
fdsForceInt = [],
fdsForcedInt = Map.empty,
fdsForceCol = [],
fdsModel = Nothing,
fdsNewEdges = Set.empty,
fdsDoneEdges = Set.empty,
fdsDecomp = baseDecompData,
fdsIntVars = Map.empty,
fdsIntVarTypes = Map.empty,
fdsIntVarBusy = Set.empty,
fdsIntUnifies = Map.empty,
fdsBoolVars = Map.empty,
fdsBoolVarTypes = Map.empty,
fdsBoolVarBusy = Set.empty,
fdsBoolUnifies = Map.empty,
fdsColVars = Map.empty,
fdsColVarTypes = Map.empty,
fdsColVarBusy = Set.empty,
fdsColUnifies = Map.empty,
fdsDb = Map.empty,
fdsFailed = False,
fdsLevel = 0,
fdsDummyLevel = 0,
fdsMinimizeVar = Nothing,
fdsMinimizeTerm = Nothing
}
edgesLeft :: FDSolver s => FDInstance s Bool
edgesLeft = get >>= return . Set.null . fdsNewEdges
whileM :: Monad m => m Bool -> m a -> m ()
whileM cond act = do
x <- cond
if x
then do
act
whileM cond act
else return ()
whileM_ :: Monad m => m Bool -> m ()
whileM_ cond = whileM cond $ return ()
data FDSolver s => FDLabel s = FDLabel {
fdlState :: FDState s,
fdlLabel :: Label s
}
newtype FDSolver s => FDInstance s a = FDInstance { unFDInstance :: StateT (FDState s) s a }
deriving (Monad, Applicative, Functor, MonadState (FDState s))
joinWith :: (a -> a -> a) -> Maybe a -> Maybe a -> Maybe a
joinWith f a b = case (a,b) of
(Nothing,_) -> b
(_,Nothing) -> a
(Just x,Just y) -> Just $ f x y
liftFD :: FDSolver s => s a -> FDInstance s a
liftFD = FDInstance . lift
liftFDTree :: (FDSolver s, MonadTree m, TreeSolver m ~ (FDInstance s)) => Tree s a -> m a
liftFDTree = mapTree liftFD
data SpecResult t =
SpecResNone
| SpecResSpec t
| SpecResUnify EGVarId
type SpecBool s = FDInstance s (SpecResult (FDBoolSpecType s, s (FDBoolSpec s, Maybe EGBoolPar)))
type SpecInt s = FDInstance s (SpecResult (FDIntSpecType s, s (FDIntSpec s, Maybe EGPar)))
type SpecCol s = FDInstance s (SpecResult (FDColSpecType s, s (FDColSpec s, Maybe EGColPar)))
type SpecFnRes s =
(
[(Int, EGVarId, Bool, SpecBool s)],
[(Int, EGVarId, Bool, SpecInt s)],
[(Int, EGVarId, Bool, SpecCol s)]
)
type SpecFn s = EGEdge -> SpecFnRes s
data TermType = FDTBool | FDTInt | FDTCol
deriving (Eq,Ord,Bounded,Enum,Show)
fdsBoolSel x = case x of
FDSBool a -> Just a
_ -> Nothing
fdsIntSel x = case x of
FDSInt a -> Just a
_ -> Nothing
fdsColSel x = case x of
FDSCol a -> Just a
_ -> Nothing
data TermTypeSpec s = FDSBool (SpecBool s) | FDSInt (SpecInt s) | FDSCol (SpecCol s)
instance Show (TermTypeSpec s) where
show (FDSBool _) = "FDSBool"
show (FDSInt _) = "FDSInt"
show (FDSCol _) = "FDSCol"
type SpecDb s = Map (Int,TermType,EGVarId) (Maybe EGEdgeId,TermTypeSpec s)
addBoolSpec :: FDSolver s => SpecDb s -> (Int,EGVarId,Maybe EGEdgeId,SpecBool s) -> SpecDb s
addBoolSpec db (prio,var,eid,spec) = Map.insert (prio,FDTBool,var) (eid,FDSBool spec) db
addIntSpec :: FDSolver s => SpecDb s -> (Int,EGVarId,Maybe EGEdgeId,SpecInt s) -> SpecDb s
addIntSpec db (prio,var,eid,spec) = Map.insert (prio,FDTInt,var) (eid,FDSInt spec) db
addColSpec :: FDSolver s => SpecDb s -> (Int,EGVarId,Maybe EGEdgeId,SpecCol s) -> SpecDb s
addColSpec db (prio,var,eid,spec) = Map.insert (prio,FDTCol,var) (eid,FDSCol spec) db
emptyFDSpecInfoBool :: FDSolver s => EGVarId -> FDState s -> FDSpecInfoBool s
emptyFDSpecInfoBool v s = FDSpecInfoBool { fdspBoolSpec = const Nothing, fdspBoolVar = Just v, fdspBoolVal = getBoolVal_ v s, fdspBoolTypes = Set.empty }
emptyFDSpecInfoInt :: FDSolver s => EGVarId -> FDState s -> FDSpecInfoInt s
emptyFDSpecInfoInt v s = FDSpecInfoInt { fdspIntSpec = const Nothing, fdspIntVar = Just v, fdspIntVal = getIntVal_ v s, fdspIntTypes = Set.empty }
emptyFDSpecInfoCol :: FDSolver s => EGVarId -> FDState s -> FDSpecInfoCol s
emptyFDSpecInfoCol v s = FDSpecInfoCol { fdspColSpec = const Nothing, fdspColVar = Just v, fdspColVal = getColVal_ v s, fdspColTypes = Set.empty }
data FDSpecInfoBool s = FDSpecInfoBool { fdspBoolSpec :: Maybe (FDBoolSpecType s) -> Maybe (FDBoolSpec s), fdspBoolVar :: Maybe EGVarId, fdspBoolVal :: Maybe EGBoolPar, fdspBoolTypes :: Set (FDBoolSpecType s) }
data FDSpecInfoInt s = FDSpecInfoInt { fdspIntSpec :: Maybe (FDIntSpecType s) -> Maybe (FDIntSpec s), fdspIntVar :: Maybe EGVarId, fdspIntVal :: Maybe EGPar, fdspIntTypes :: Set (FDIntSpecType s) }
data FDSpecInfoCol s = FDSpecInfoCol { fdspColSpec :: Maybe (FDColSpecType s) -> Maybe (FDColSpec s), fdspColVar :: Maybe EGVarId, fdspColVal :: Maybe EGColPar, fdspColTypes :: Set (FDColSpecType s) }
unionSpecBool (FDSpecInfoBool { fdspBoolSpec = s1, fdspBoolVar = n1, fdspBoolVal = v1, fdspBoolTypes = t1 }) (FDSpecInfoBool { fdspBoolSpec = s2, fdspBoolVar = n2, fdspBoolVal = v2, fdspBoolTypes = t2 }) =
FDSpecInfoBool { fdspBoolSpec = \t -> (s1 t) `mplus` (s2 t), fdspBoolVal = v1 `mplus` v2, fdspBoolVar = n1 `mplus` n2, fdspBoolTypes = Set.union t1 t2 }
unionSpecInt (FDSpecInfoInt { fdspIntSpec = s1, fdspIntVar = n1, fdspIntVal = v1, fdspIntTypes = t1 }) (FDSpecInfoInt { fdspIntSpec = s2, fdspIntVar = n2, fdspIntVal = v2, fdspIntTypes = t2 }) =
FDSpecInfoInt { fdspIntSpec = \t -> (s1 t) `mplus` (s2 t), fdspIntVal = v1 `mplus` v2, fdspIntVar = n1 `mplus` n2, fdspIntTypes = Set.union t1 t2 }
unionSpecCol (FDSpecInfoCol { fdspColSpec = s1, fdspColVar = n1, fdspColVal = v1, fdspColTypes = t1 }) (FDSpecInfoCol { fdspColSpec = s2, fdspColVar = n2, fdspColVal = v2, fdspColTypes = t2 }) =
FDSpecInfoCol { fdspColSpec = \t -> (s1 t) `mplus` (s2 t), fdspColVal = v1 `mplus` v2, fdspColVar = n1 `mplus` n2, fdspColTypes = Set.union t1 t2 }
instance (Ord (FDBoolSpec s), Ord (FDBoolSpecType s)) => Eq (FDSpecInfoBool s) where
a == b = (compare a b) == EQ
instance (Ord (FDBoolSpec s), Ord (FDBoolSpecType s)) => Ord (FDSpecInfoBool s) where
compare (FDSpecInfoBool { fdspBoolSpec = s1, fdspBoolVar = r1, fdspBoolVal = v1, fdspBoolTypes = t1 }) (FDSpecInfoBool { fdspBoolSpec = s2, fdspBoolVar = r2, fdspBoolVal = v2, fdspBoolTypes = t2 }) =
compare r1 r2 <<>> compare v1 v2 <<>> compare (s1 Nothing) (s2 Nothing) <<>> compare (Map.fromList $ map (\x -> (x,s1 $ Just x)) $ Set.toList t1) (Map.fromList $ map (\x -> (x,s2 $ Just x)) $ Set.toList t2)
instance (Ord (FDIntSpec s), Ord (FDIntSpecType s)) => Eq (FDSpecInfoInt s) where
a == b = (compare a b) == EQ
instance (Ord (FDIntSpec s), Ord (FDIntSpecType s)) => Ord (FDSpecInfoInt s) where
compare (FDSpecInfoInt { fdspIntSpec = s1, fdspIntVar = r1, fdspIntVal = v1, fdspIntTypes = t1 }) (FDSpecInfoInt { fdspIntSpec = s2, fdspIntVar = r2, fdspIntVal = v2, fdspIntTypes = t2 }) =
compare r1 r2 <<>> compare v1 v2 <<>> compare (s1 Nothing) (s2 Nothing) <<>> compare (Map.fromList $ map (\x -> (x,s1 $ Just x)) $ Set.toList t1) (Map.fromList $ map (\x -> (x,s2 $ Just x)) $ Set.toList t2)
instance (Ord (FDColSpec s), Ord (FDColSpecType s)) => Eq (FDSpecInfoCol s) where
a == b = (compare a b) == EQ
instance (Ord (FDColSpec s), Ord (FDColSpecType s)) => Ord (FDSpecInfoCol s) where
compare (FDSpecInfoCol { fdspColSpec = s1, fdspColVar = r1, fdspColVal = v1, fdspColTypes = t1 }) (FDSpecInfoCol { fdspColSpec = s2, fdspColVar = r2, fdspColVal = v2, fdspColTypes = t2 }) =
compare r1 r2 <<>> compare v1 v2 <<>> compare (s1 Nothing) (s2 Nothing) <<>> compare (Map.fromList $ map (\x -> (x,s1 $ Just x)) $ Set.toList t1) (Map.fromList $ map (\x -> (x,s2 $ Just x)) $ Set.toList t2)
specInfoMapBool :: FDSolver s => FDSpecInfoBool s -> Map (FDBoolSpecType s) (FDBoolSpec s)
specInfoMapBool (FDSpecInfoBool { fdspBoolSpec = f, fdspBoolTypes = t }) = Map.fromList $ map (\t -> (t,myFromJust "specInfoMapBool" $ f $ Just t)) $ Set.toList t
specInfoMapInt :: FDSolver s => FDSpecInfoInt s -> Map (FDIntSpecType s) (FDIntSpec s)
specInfoMapInt (FDSpecInfoInt { fdspIntSpec = f, fdspIntTypes = t }) = Map.fromList $ map (\t -> (t,myFromJust "specInfoMapInt" $ f $ Just t)) $ Set.toList t
specInfoMapCol :: FDSolver s => FDSpecInfoCol s -> Map (FDColSpecType s) (FDColSpec s)
specInfoMapCol (FDSpecInfoCol { fdspColSpec = f, fdspColTypes = t }) = Map.fromList $ map (\t -> (t,myFromJust "specInfoMapCol" $ f $ Just t)) $ Set.toList t
specInfoBoolTerm :: FDSolver s => FDBoolTerm s -> s (FDSpecInfoBool s)
specInfoBoolTerm t = do
let (tp,sp) = fdBoolSpec_term t
s <- sp
return $ FDSpecInfoBool { fdspBoolSpec = \t -> case t of { Nothing -> Just s; Just tt | tp==tt -> Just s; _ -> Nothing }, fdspBoolVar = Nothing, fdspBoolVal = Nothing, fdspBoolTypes = Set.singleton tp }
specInfoIntTerm :: FDSolver s => FDIntTerm s -> s (FDSpecInfoInt s)
specInfoIntTerm t = do
let (tp,sp) = fdIntSpec_term t
s <- sp
return $ FDSpecInfoInt { fdspIntSpec = \t -> case t of { Nothing -> Just s; Just tt | tp==tt -> Just s; _ -> Nothing }, fdspIntVar = Nothing, fdspIntVal = Nothing, fdspIntTypes = Set.singleton tp }
instance Show (FDBoolSpec s) => Show (FDSpecInfoBool s) where
show (FDSpecInfoBool { fdspBoolSpec = f, fdspBoolVar = e, fdspBoolVal = v }) = "FSSpecInfoBool { default:" ++ (show $ f Nothing) ++ ", var:" ++ (show e) ++ ", val:" ++ (show v) ++ "}"
instance Show (FDIntSpec s) => Show (FDSpecInfoInt s) where
show (FDSpecInfoInt { fdspIntSpec = f, fdspIntVar = e, fdspIntVal = v }) = "FSSpecInfoInt { default:" ++ (show $ f Nothing) ++ ", var:" ++ (show e) ++ ", val:" ++ (show v) ++ "}"
instance Show (FDColSpec s) => Show (FDSpecInfoCol s) where
show (FDSpecInfoCol { fdspColSpec = f, fdspColVar = e, fdspColVal = v }) = "FSSpecInfoCol { default:" ++ (show $ f Nothing) ++ ", var:" ++ (show e) ++ ", val:" ++ (show v) ++ "}"
type FDSpecInfo s = ([FDSpecInfoBool s],[FDSpecInfoInt s],[FDSpecInfoCol s])
fdSpecInfo_edge :: FDSolver s => EGEdgeId -> FDInstance s (FDSpecInfo s)
fdSpecInfo_edge f = do
s <- get
let edge = getJustEdge f s
intS p = Map.findWithDefault (emptyFDSpecInfoInt p s) p $ fdsIntVars s
boolS p = Map.findWithDefault (emptyFDSpecInfoBool p s) p $ fdsBoolVars s
colS p = Map.findWithDefault (emptyFDSpecInfoCol p s) p $ fdsColVars s
return (map boolS $ boolData $ egeLinks edge, map intS $ intData $ egeLinks edge, map colS $ colData $ egeLinks edge)
fdSpecInfo_spec :: FDSolver s => ([Either (FDSpecInfoBool s) (FDBoolSpecType s,FDBoolSpec s)],[Either (FDSpecInfoInt s) (FDIntSpecType s,FDIntSpec s)],[Either (FDSpecInfoCol s) (FDColSpecType s,FDColSpec s)]) -> FDSpecInfo s
fdSpecInfo_spec (b,i,c) = (fdSpecInfo_spec_b b, fdSpecInfo_spec_i i, fdSpecInfo_spec_c c)
fdSpecInfo_spec_b :: FDSolver s => [Either (FDSpecInfoBool s) (FDBoolSpecType s,FDBoolSpec s)] -> [FDSpecInfoBool s]
fdSpecInfo_spec_b b =
let fb (Right x) = FDSpecInfoBool { fdspBoolSpec = nt x, fdspBoolVar = Nothing, fdspBoolVal = Nothing, fdspBoolTypes = Set.singleton $ fst x }
fb (Left x) = x
nt (_,x) Nothing = Just x
nt (t1,x) (Just t2) | t1==t2 = Just x
nt _ _ = Nothing
in (map fb b)
fdSpecInfo_spec_i :: FDSolver s => [Either (FDSpecInfoInt s) (FDIntSpecType s,FDIntSpec s)] -> [FDSpecInfoInt s]
fdSpecInfo_spec_i i =
let fi (Right x) = FDSpecInfoInt { fdspIntSpec = nt x, fdspIntVar = Nothing, fdspIntVal = Nothing, fdspIntTypes = Set.singleton $ fst x }
fi (Left x) = x
nt (_,x) Nothing = Just x
nt (t1,x) (Just t2) | t1==t2 = Just x
nt _ _ = Nothing
in (map fi i)
fdSpecInfo_spec_c :: FDSolver s => [Either (FDSpecInfoCol s) (FDColSpecType s,FDColSpec s)] -> [FDSpecInfoCol s]
fdSpecInfo_spec_c c =
let fc (Right x) = FDSpecInfoCol { fdspColSpec = nt x, fdspColVar = Nothing, fdspColVal = Nothing, fdspColTypes = Set.singleton $ fst x }
fc (Left x) = x
nt (_,x) Nothing = Just x
nt (t1,x) (Just t2) | t1==t2 = Just x
nt _ _ = Nothing
in (map fc c)
class
(
Solver s,
Term s (FDIntTerm s),
Term s (FDBoolTerm s),
Eq (FDBoolSpecType s), Ord (FDBoolSpecType s), Enum (FDBoolSpecType s), Bounded (FDBoolSpecType s), Show (FDBoolSpecType s),
Eq (FDIntSpecType s), Ord (FDIntSpecType s), Enum (FDIntSpecType s), Bounded (FDIntSpecType s), Show (FDIntSpecType s),
Eq (FDColSpecType s), Ord (FDColSpecType s), Enum (FDColSpecType s), Bounded (FDColSpecType s), Show (FDColSpecType s),
Show (FDIntSpec s), Show (FDColSpec s), Show (FDBoolSpec s)
) => FDSolver s where
type FDIntTerm s :: *
type FDBoolTerm s :: *
type FDIntSpec s :: *
type FDBoolSpec s :: *
type FDColSpec s :: *
type FDIntSpecType s :: *
type FDBoolSpecType s :: *
type FDColSpecType s :: *
fdIntSpec_const :: EGPar -> (FDIntSpecType s, s (FDIntSpec s))
fdBoolSpec_const :: EGBoolPar -> (FDBoolSpecType s, s (FDBoolSpec s))
fdColSpec_const :: EGColPar -> (FDColSpecType s, s (FDColSpec s))
fdColSpec_list :: [FDIntSpec s] -> (FDColSpecType s, s (FDColSpec s))
fdIntSpec_term :: FDIntTerm s -> (FDIntSpecType s, s (FDIntSpec s))
fdBoolSpec_term :: FDBoolTerm s -> (FDBoolSpecType s, s (FDBoolSpec s))
fdColSpec_size :: EGPar -> (FDColSpecType s, s (FDColSpec s))
fdIntVarSpec :: FDIntSpec s -> s (Maybe (FDIntTerm s))
fdBoolVarSpec :: FDBoolSpec s -> s (Maybe (FDBoolTerm s))
fdTypeReqBool :: s (EGEdge -> [(EGVarId,FDBoolSpecTypeSet s)])
fdTypeReqInt :: s (EGEdge -> [(EGVarId,FDIntSpecTypeSet s)])
fdTypeReqCol :: s (EGEdge -> [(EGVarId,FDColSpecTypeSet s)])
fdTypeReqBool = return (\(EGEdge { egeLinks = EGTypeData { boolData = l } }) -> map (\x -> (x,Set.fromList [minBound..maxBound])) l)
fdTypeReqInt = return (\(EGEdge { egeLinks = EGTypeData { intData = l } }) -> map (\x -> (x,Set.fromList [minBound..maxBound])) l)
fdTypeReqCol = return (\(EGEdge { egeLinks = EGTypeData { colData = l } }) -> map (\x -> (x,Set.fromList [minBound..maxBound])) l)
fdTypeVarInt :: s (Set (FDIntSpecType s))
fdTypeVarBool :: s (Set (FDBoolSpecType s))
fdTypeVarInt = return $ Set.singleton maxBound
fdTypeVarBool = return $ Set.singleton maxBound
fdSpecify :: Mixin (SpecFn s)
fdSpecify = mixinId
fdColInspect :: FDColSpec s -> s [FDIntTerm s]
fdProcess :: Mixin (EGConstraintSpec -> FDSpecInfo s -> FDInstance s ())
fdEqualBool :: FDBoolSpec s -> FDBoolSpec s -> FDInstance s ()
fdEqualInt :: FDIntSpec s -> FDIntSpec s -> FDInstance s ()
fdEqualCol :: FDColSpec s -> FDColSpec s -> FDInstance s ()
fdConstrainIntTerm :: FDIntTerm s -> Integer -> s (Constraint s)
fdSplitIntDomain :: FDIntTerm s -> s ([Constraint s],Bool)
fdSplitBoolDomain :: FDBoolTerm s -> s ([Constraint s],Bool)
fdGetValBool :: (FDSolver s, EnumTerm s (FDBoolTerm s)) => FDBoolSpec s -> s (Maybe (TermBaseType s (FDBoolTerm s)))
fdGetValInt :: (FDSolver s, EnumTerm s (FDIntTerm s)) => FDIntSpec s -> s (Maybe (TermBaseType s (FDIntTerm s)))
fdGetValBool s = fdBoolVarSpec s >>= \x -> case x of
Just t -> getValue t
_ -> return Nothing
fdGetValInt s = fdIntVarSpec s >>= \x -> case x of
Just t -> getValue t
_ -> return Nothing
type FDBoolSpecTypeSet s = Set (FDBoolSpecType s)
type FDIntSpecTypeSet s = Set (FDIntSpecType s)
type FDColSpecTypeSet s = Set (FDColSpecType s)
fdCombineSpecify :: FDSolver s => SpecFn s -> SpecFn s -> SpecFn s
fdCombineSpecify a b edge =
let (a1,a2,a3) = a edge
(b1,b2,b3) = b edge
in (a1++b1,a2++b2,a3++b3)
procEdge :: FDSolver s => FDInstance s Bool
procEdge = do
s <- get
if (Set.null $ fdsNewEdges s)
then return False
else do
let f = Set.findMin $ fdsNewEdges s
edge = getJustEdge f s
debug ("procEdge("++(show f)++")") $ return ()
info <- fdSpecInfo_edge f
full_fdProcess (egeCons edge) info
debug ("procEdge: marking edge "++(show f)) $ return ()
markEdge f
s2 <- get
return $ not $ Set.null $ fdsNewEdges s2
getEdge :: FDSolver s => EGEdgeId -> FDInstance s (Maybe EGEdge)
getEdge id = do
s <- get
return $ do
v <- fdsModel s
Map.lookup id $ egmEdges v
markEdge :: FDSolver s => EGEdgeId -> FDInstance s ()
markEdge id = do
s <- get
debug ("markEdge: "++(show $ id)) $ return ()
put $ s { fdsNewEdges = Set.delete id $ fdsNewEdges s, fdsDoneEdges = Set.insert id $ fdsDoneEdges s }
sureMaybe :: [Maybe a] -> Maybe [a]
sureMaybe [] = Just []
sureMaybe (Nothing:_) = Nothing
sureMaybe ((Just a):b) = case sureMaybe b of
Nothing -> Nothing
Just l -> Just (a:l)
allIntSpec :: FDSolver s => FDInstance s (Set (FDIntSpecType s))
allIntSpec = return $ Set.fromList [minBound..maxBound]
allBoolSpec :: FDSolver s => FDInstance s (Set (FDBoolSpecType s))
allBoolSpec = return $ Set.fromList [minBound..maxBound]
allColSpec :: FDSolver s => FDInstance s (Set (FDColSpecType s))
allColSpec = return $ Set.fromList [minBound..maxBound]
default_fdSpecify :: FDSolver s => SpecFn s
default_fdSpecify edge = case (debug ("default_fdSpecify("++(show edge)++")") edge) of
EGEdge { egeCons = EGIntValue c, egeLinks = EGTypeData { intData = [v] } } ->
([],[(1000,v,True,do
let (tp, m) = fdIntSpec_const c
return $ SpecResSpec (tp,m >>= (\x -> return (x, Just c)))
)],[])
EGEdge { egeCons = EGBoolValue c, egeLinks = EGTypeData { boolData = [v] } } ->
([(1000,v,True,do
let (tp, m) = fdBoolSpec_const c
return $ SpecResSpec (tp, m >>= (\x -> return (x, Just c)))
)],[],[])
EGEdge { egeCons = EGColValue c, egeLinks = EGTypeData { colData = [v] } } ->
([],[],[(990,v,True,do
let (tp, m) = fdColSpec_const c
return $ SpecResSpec (tp, m >>= (\x -> return (x, Just c)))
)])
EGEdge { egeCons = EGList s, egeLinks = EGTypeData { colData = [c], intData = l } } ->
([],[],[(500,c,True,do
x <- mapM (\x -> getIntSpec x) l
case sureMaybe x of
Nothing -> return SpecResNone
Just ll -> do
let (tp, m) = fdColSpec_list ll
return $ SpecResSpec $ (tp, m >>= (\x -> return (x, Nothing)))
)])
EGEdge { egeCons = EGSize, egeLinks = EGTypeData { colData = [c], intData=[s] } } ->
([],[],[(250,c,True,do
ss <- get
let k = getIntVal_ s ss
case k of
Nothing -> return SpecResNone
Just ll -> do
let (tp, m) = fdColSpec_size ll
return $ SpecResSpec $ (tp, m >>= (\x -> return (x, Nothing)))
)])
EGEdge { egeCons = EGRange, egeLinks = EGTypeData { colData = [c], intData=[l,h] } } ->
([],[],[(250,c,False,do
ss <- get
let ll = getIntVal_ l ss
hh = getIntVal_ h ss
case (ll,hh) of
(Just (Const jl), Just (Const jh)) -> do
let (tp,m) = fdColSpec_size (Const $ jh-jl+1)
return $ SpecResSpec $ (tp, m >>= (\x -> return (x, Just $ ColList [Const x | x <- [jl..jh]])))
(Just jl, Just jh) -> do
let (tp,m) = fdColSpec_size (jh-jl+1)
return $ SpecResSpec $ (tp, m >>= (\x -> return (x, Nothing)))
_ -> return SpecResNone
)])
_ -> ([],[],[])
default_fdProcess :: FDSolver s => EGConstraintSpec -> FDSpecInfo s -> FDInstance s ()
default_fdProcess cons _ = error $ "Cannot process "++(show cons)
initForModel :: FDSolver s => FDInstance s ()
initForModel = do
s <- get
let Just model = fdsModel s
put $ s {
fdsNewEdges = Set.difference (Set.union (fdsNewEdges s) $ Set.fromList $ Map.keys $ egmEdges model) $ fdsDoneEdges s
}
setAlter :: Ord a => a -> Maybe (Set (Set a)) -> Maybe (Set (Set a))
setAlter _ Nothing = Nothing
setAlter typ (Just x) = let f = fl x in if Set.null f then Nothing else Just f
where fl = Set.filter $ not . Set.member typ
addSpecInt :: FDSolver s => FDIntSpecType s -> (FDIntSpec s, Maybe EGPar) -> EGVarId -> FDState s -> Maybe (FDSpecInfoInt s) -> Maybe (FDSpecInfoInt s)
addSpecInt tp def id s Nothing = addSpecInt tp def id s (Just $ emptyFDSpecInfoInt id s)
addSpecInt tp (def,val) _ _ (Just (m@(FDSpecInfoInt { fdspIntSpec = f, fdspIntTypes = t }))) =
Just $ m {
fdspIntSpec = \x -> case x of
Just tt | tt==tp -> Just $ def
Nothing -> case f Nothing of
Nothing -> Just def
Just ttt -> Just ttt
k -> f k,
fdspIntTypes = Set.insert tp t,
fdspIntVal = case val of
Nothing -> fdspIntVal m
_ -> val
}
addSpecBool :: FDSolver s => FDBoolSpecType s -> (FDBoolSpec s, Maybe EGBoolPar) -> EGVarId -> FDState s -> Maybe (FDSpecInfoBool s) -> Maybe (FDSpecInfoBool s)
addSpecBool tp def id s Nothing = addSpecBool tp def id s (Just $ emptyFDSpecInfoBool id s)
addSpecBool tp (def,val) _ _ (Just (m@(FDSpecInfoBool { fdspBoolSpec = f, fdspBoolTypes = t }))) =
Just $ m {
fdspBoolSpec = \x -> case x of
Just tt | tt==tp -> Just $ def
Nothing -> case f Nothing of
Nothing -> Just def
Just ttt -> Just ttt
k -> f k,
fdspBoolTypes = Set.insert tp t,
fdspBoolVal = case val of
Nothing -> fdspBoolVal m
_ -> val
}
addSpecCol :: FDSolver s => FDColSpecType s -> (FDColSpec s, Maybe EGColPar) -> EGVarId -> FDState s -> Maybe (FDSpecInfoCol s) -> Maybe (FDSpecInfoCol s)
addSpecCol tp def id s Nothing = addSpecCol tp def id s (Just $ emptyFDSpecInfoCol id s)
addSpecCol tp (def,val) _ _ (Just (m@(FDSpecInfoCol { fdspColSpec = f, fdspColTypes = t }))) =
Just $ m {
fdspColSpec = \x -> case x of
Just tt | tt==tp -> Just $ def
Nothing -> case f Nothing of
Nothing -> Just def
Just ttt -> Just ttt
k -> f k,
fdspColTypes = Set.insert tp t,
fdspColVal = case val of
Nothing -> fdspColVal m
_ -> val
}
addIntVar :: FDSolver s => EGVarId -> FDIntSpecType s -> (FDIntSpec s, Maybe EGPar) -> FDInstance s ()
addIntVar id typ (spec@(rs,_)) = do
s <- get
case (Map.lookup id $ fdsIntVars s) of
Just t | not (Set.null $ fdspIntTypes t) -> case (fdspIntSpec t Nothing) of
Just x -> fdEqualInt rs x
Nothing -> case fdspIntSpec t $ Just $ Set.findMax $ fdspIntTypes t of
Just x -> fdEqualInt rs x
Nothing -> return ()
_ -> return ()
s2 <- get
put $ s2
{
fdsIntVars = Map.alter (addSpecInt typ spec id s2) id $ fdsIntVars s2,
fdsIntVarBusy = Set.delete id $ fdsIntVarBusy s2,
fdsIntVarTypes = Map.alter (setAlter typ) id $ fdsIntVarTypes s2
}
addBoolVar :: FDSolver s => EGVarId -> FDBoolSpecType s -> (FDBoolSpec s, Maybe EGBoolPar) -> FDInstance s ()
addBoolVar id typ (spec@(rs,_)) = do
s <- get
case (Map.lookup id $ fdsBoolVars s) of
Just t | not (Set.null $ fdspBoolTypes t) -> case (fdspBoolSpec t Nothing) of
Just x -> fdEqualBool rs x
Nothing -> case fdspBoolSpec t $ Just $ Set.findMax $ fdspBoolTypes t of
Just x -> fdEqualBool rs x
Nothing -> return ()
_ -> return ()
s2 <- get
put $ s2
{
fdsBoolVars = Map.alter (addSpecBool typ spec id s2) id $ fdsBoolVars s2,
fdsBoolVarBusy = Set.delete id $ fdsBoolVarBusy s2,
fdsBoolVarTypes = Map.alter (setAlter typ) id $ fdsBoolVarTypes s2
}
addColVar :: FDSolver s => EGVarId -> FDColSpecType s -> (FDColSpec s, Maybe EGColPar) -> FDInstance s ()
addColVar id typ (spec@(rs,_)) = do
s <- get
case (Map.lookup id $ fdsColVars s) of
Just t | not (Set.null $ fdspColTypes t) -> case (fdspColSpec t Nothing) of
Just x -> fdEqualCol rs x
Nothing -> case fdspColSpec t $ Just $ Set.findMax $ fdspColTypes t of
Just x -> fdEqualCol rs x
Nothing -> return ()
_ -> return ()
s2 <- get
put $ s2
{
fdsColVars = Map.alter (addSpecCol typ spec id s2) id $ fdsColVars s2,
fdsColVarBusy = Set.delete id $ fdsColVarBusy s2,
fdsColVarTypes = Map.alter (setAlter typ) id $ fdsColVarTypes s2
}
full_fdProcess :: FDSolver s => EGConstraintSpec -> FDSpecInfo s -> FDInstance s ()
full_fdProcess = mixin (fdProcess <@> mixinLift default_fdProcess)
full_fdSpecify :: FDSolver s => SpecFn s
full_fdSpecify = mixin (fdSpecify <@> mixinLift default_fdSpecify)
getJustEdge :: FDSolver s => EGEdgeId -> FDState s -> EGEdge
getJustEdge i s =
let Just m = fdsModel s
Just x = Map.lookup i (egmEdges m)
in x
buildSpecDb :: FDSolver s => FDInstance s ()
buildSpecDb = do
s <- get
let origDb = fdsDb s
ne = debug "bsdb: ne" $ map (\k -> (k,getJustEdge k s)) $ Set.toList $ debug "bsbd: fdsne" $ fdsNewEdges s
proc db (eid,edge) = do
let (lB,lI,lC) = debug ("bsbd: specify("++(show edge)++")") $ full_fdSpecify edge
dB = foldr (\(prio,var,full,spec) d -> debug "bsbd: addbool" $ addBoolSpec d (prio,var,if full then Just eid else Nothing,spec)) db $ debug ("lB["++(show $ length lB)++"]") lB
dI = foldr (\(prio,var,full,spec) d -> debug "bsbd: addint" $ addIntSpec d (prio,var,if full then Just eid else Nothing,spec)) dB $ debug ("lI["++(show $ length lI)++"]") lI
dC = foldr (\(prio,var,full,spec) d -> debug "bsbd: addcol" $ addColSpec d (prio,var,if full then Just eid else Nothing,spec)) dI $ debug ("lC["++(show $ length lC)++"]") lC
in dC
newDb = foldl proc origDb ne
put $ s { fdsDb = newDb }
addBoolTypeReq :: FDSolver s => EGVarId -> FDBoolSpecTypeSet s -> FDInstance s ()
addBoolTypeReq var set = do
s <- get
let chk tp = case Map.lookup var (fdsBoolVars s) of
Nothing -> False
Just x -> Set.member tp (fdspBoolTypes x)
sset = Map.findWithDefault Set.empty var (fdsBoolVarTypes s)
if Set.member set sset
then return ()
else if any chk (Set.toList set)
then return ()
else do
let nsset = Set.insert set sset
put $ s
{
fdsBoolVarTypes = Map.insert var nsset $ fdsBoolVarTypes s
}
addIntTypeReq :: FDSolver s => EGVarId -> FDIntSpecTypeSet s -> FDInstance s ()
addIntTypeReq var set = do
s <- get
let chk tp = case Map.lookup var (fdsIntVars s) of
Nothing -> False
Just x -> Set.member tp (fdspIntTypes x)
sset = Map.findWithDefault Set.empty var (fdsIntVarTypes s)
if Set.member set sset
then return ()
else if any chk (Set.toList set)
then return ()
else do
let nsset = Set.insert set sset
put $ s
{
fdsIntVarTypes = Map.insert var nsset $ fdsIntVarTypes s
}
addColTypeReq :: FDSolver s => EGVarId -> FDColSpecTypeSet s -> FDInstance s ()
addColTypeReq var set = do
s <- get
let chk tp = case Map.lookup var (fdsColVars s) of
Nothing -> False
Just x -> Set.member tp (fdspColTypes x)
sset = Map.findWithDefault Set.empty var (fdsColVarTypes s)
if Set.member set sset
then return ()
else if any chk (Set.toList set)
then return ()
else do
let nsset = Set.insert set sset
put $ s
{
fdsColVarTypes = Map.insert var nsset (fdsColVarTypes s)
}
addTypeReqs :: FDSolver s => FDInstance s ()
addTypeReqs = do
s <- get
fBool <- liftFD fdTypeReqBool
fInt <- liftFD fdTypeReqInt
fCol <- liftFD fdTypeReqCol
let ne = map (\k -> getJustEdge k s) $ Set.toList $ fdsNewEdges s
proc edge = do
mapM_ (uncurry addBoolTypeReq) $ fBool edge
mapM_ (uncurry addIntTypeReq) $ fInt edge
mapM_ (uncurry addColTypeReq) $ fCol edge
mapM_ proc ne
processEx :: FDSolver s => Bool -> FDInstance s ()
processEx x = do
ssm1 <- get
let ss0 = ssm1 { fdsModel = Just $ pruneNodes $ myFromJust "processEx" $ fdsModel ssm1 }
debug ("process ["++(show $ fdsLevel ss0)++"]") $ return ()
debug ("addTypeReqs ["++(show $ fdsLevel ss0)++"]") $ addTypeReqs
debug ("optimizeVarTypes["++(show $ fdsLevel ss0)++"]") $ optimizeVarTypes
ss <- get
debug ("DUMP type reqs ["++(show $ fdsLevel ss0)++"]: "++(show $ fdsIntVarTypes ss)) $ return ()
debug ("buildSpecDb ["++(show $ fdsLevel ss0)++"]") $ buildSpecDb
ss2 <- get
debug ("DUMP spec db ["++(show $ fdsLevel ss0)++"]: "++(show $ fdsDb ss2)) $ return ()
whileM_ $ debug ("decompBest ["++(show $ fdsLevel ss0)++"]") decompBest
whileM_ $ debug ("decompDefBool ["++(show $ fdsLevel ss0)++"]") decompDefaultBool
whileM_ $ debug ("decompDefInt ["++(show $ fdsLevel ss0)++"]") decompDefaultInt
ss3 <- get
debug ("DUMP specs: "++(dumpSpec ss3)) $ return ()
if x
then whileM_ $ debug ("procEdge ["++(show $ fdsLevel ss0)++"]") procEdge
else return ()
process :: FDSolver s => FDInstance s ()
process = processEx True
commit :: FDSolver s => FDInstance s ()
commit = do
s <- get
debug "begin commit" $ return ()
case (fdsExpr s,fdsForceBool s,fdsForceInt s,fdsForceCol s) of
(BoolConst True,[],[],[]) -> return ()
(expr,_,_,_) -> do
debug ("expr=["++(show expr)++"]") $ return ()
let (dcd,graph,vars) = debug "decomposing" $ decomposeEx (fdsDecomp s) (fdsVars s) expr (fdsForceBool s,fdsForceInt s,fdsForceCol s) $ fdsModel s
put $ s { fdsExpr = BoolConst True, fdsDecomp = dcd, fdsModel = Just graph, fdsForceBool=[], fdsForceInt=[], fdsForceCol=[], fdsVars = max vars (fdsVars s) }
debug ("graph=["++(present graph)++"]"++"]") $ return ()
debug "initForModel" $ initForModel
process
instance FDSolver s => Solver (FDInstance s) where
type Constraint (FDInstance s) = Either Model (Constraint s)
type Label (FDInstance s) = FDLabel s
add (Left expr) = do
s <- get
if (fdsFailed s)
then return False
else do
put $ s { fdsExpr = (fdsExpr s) @&& expr }
return True
add (Right col) = do
s <- get
if (fdsFailed s)
then return False
else do
ret <- liftFD $ add col
if ret
then return True
else do
setFailed
return False
mark = do
commit
ss <- get
sl <- liftFD mark
return $ FDLabel { fdlState=ss, fdlLabel=sl }
markn n = do
commit
ss <- get
sl <- liftFD $ markn n
return $ FDLabel { fdlState=ss, fdlLabel=sl }
goto label = do
liftFD $ goto $ fdlLabel label
put $ fdlState label
run x = run $ runFD x
instance FDSolver s => Term (FDInstance s) ModelInt where
newvar = do
s <- get
let i = fdsVars s
put $ s { fdsVars = 1+i }
return $ Term $ ModelIntVar i
type Help (FDInstance s) ModelInt = ()
help _ _ = ()
instance FDSolver s => Term (FDInstance s) ModelBool where
newvar = do
s <- get
let i = fdsVars s
put $ s { fdsVars = 1+i }
return $ BoolTerm $ ModelBoolVar i
type Help (FDInstance s) ModelBool = ()
help _ _ = ()
instance FDSolver s => Term (FDInstance s) ModelCol where
newvar = do
s <- get
let i = fdsVars s
put $ s { fdsVars = 1+i }
return $ ColTerm $ ModelColVar i
type Help (FDInstance s) ModelCol = ()
help _ _ = ()
newCol :: FDSolver s => FDInstance s ModelCol
newCol = newvar
newInt :: FDSolver s => FDInstance s ModelInt
newInt = newvar
newBool :: FDSolver s => FDInstance s ModelBool
newBool = newvar
combine :: [Maybe a] -> [a] -> [a]
combine [] _ = []
combine (Nothing:r) (a:b) = a:(combine r b)
combine (Just x:r) b = x:(combine r b)
realGetIntTerm :: FDSolver s => [ModelInt] -> FDInstance s [FDIntTerm s]
realGetIntTerm m = do
s <- debug ("realGetIntTerm: "++(show m)) $ get
put $ s { fdsForceInt = m++(fdsForceInt s) }
commit
s2 <- get
let ids = map (\x -> decompIntLookup (fdsDecomp s2) x) m
tp <- liftFD $ fdTypeVarInt
specs <- mapM (\(Just id) -> getIntSpec_ id tp) ids
vars <- mapM (\(Just (_,spec)) -> liftFD $ fdIntVarSpec spec) specs
let rvars = map (\(Just x) -> x) vars
s3 <- get
put $ s3 { fdsForcedInt = Map.union (fdsForcedInt s3) (Map.fromList $ zip m rvars) }
return rvars
getSingleIntTerm :: FDSolver s => ModelInt -> FDInstance s (FDIntTerm s)
getSingleIntTerm m = do
s <- get
case Map.lookup m (fdsForcedInt s) of
Nothing -> realGetIntTerm [m] >>= return.head
Just d -> return d
getIntTerm :: FDSolver s => [ModelInt] -> FDInstance s [FDIntTerm s]
getIntTerm m = do
s <- get
let lo = map (\x -> (x,Map.lookup x $ fdsForcedInt s)) m
let go = map fst $ filter (\(_,x) -> isNothing x) lo
vo <- case go of
[] -> return []
_ -> realGetIntTerm go
return $ combine (map snd lo) vo
realGetBoolTerm :: FDSolver s => [ModelBool] -> FDInstance s [FDBoolTerm s]
realGetBoolTerm m = do
s <- get
put $ s { fdsForceBool = m++(fdsForceBool s) }
commit
s2 <- get
let ids = map (\x -> decompBoolLookup (fdsDecomp s2) x) m
tp <- liftFD $ fdTypeVarBool
specs <- mapM (\(Just id) -> getBoolSpec_ id tp) ids
vars <- mapM (\(Just (_,spec)) -> liftFD $ fdBoolVarSpec spec) specs
let rvars = map (\(Just x) -> x) vars
s3 <- get
put $ s3 { fdsForcedBool = Map.union (fdsForcedBool s3) (Map.fromList $ zip m rvars) }
return rvars
getBoolTerm :: FDSolver s => [ModelBool] -> FDInstance s [FDBoolTerm s]
getBoolTerm m = do
s <- get
let lo = map (\x -> (x,Map.lookup x $ fdsForcedBool s)) m
let go = map fst $ filter (\(_,x) -> isNothing x) lo
vo <- case go of
[] -> return []
_ -> realGetBoolTerm go
return $ combine (map snd lo) vo
getColTerm :: FDSolver s => [ModelCol] -> FDColSpecType s -> FDInstance s [FDColSpec s]
getColTerm m tp = do
s <- get
put $ s { fdsForceCol = m++(fdsForceCol s) }
commit
s2 <- get
let ids = map (\x -> decompColLookup (fdsDecomp s2) x) m
specs <- mapM (\(Just id) -> getColSpec_ id (Set.singleton tp)) ids
return $ map (snd . myFromJust ("getColTerm(tp="++(show tp)++")")) specs
getColItems :: FDSolver s => ModelCol -> FDColSpecType s -> FDInstance s [FDIntTerm s]
getColItems c tp = do
[cc] <- getColTerm [c] tp
lst <- liftFD $ fdColInspect cc
return lst
instance (FDSolver s, EnumTerm s (FDIntTerm s)) => EnumTerm (FDInstance s) ModelInt where
type TermBaseType (FDInstance s) ModelInt = TermBaseType s (FDIntTerm s)
getDomainSize v = do
f <- getFailed
if f
then return 0
else do
var <- getSingleIntTerm v
liftFD $ getDomainSize var
getValue v = do
var <- getSingleIntTerm v
liftFD $ getValue var
setValue _ = error "setting of boolean variable through FD interface is not implemented"
getDomain var = error "retrieval of full domain not implemented in FD"
splitDomain v = do
var <- getSingleIntTerm v
(doms,full) <- liftFD $ fdSplitIntDomain var
return (map (\x -> [Right x]) doms, full)
enumerator = case enumerator of
Nothing -> Nothing
Just e -> Just $ \l -> label $ do
f <- getFailed
if f
then return false
else do
ll <- getIntTerm l
return $ liftFDTree $ e ll
instance (FDSolver s, EnumTerm s (FDBoolTerm s)) => EnumTerm (FDInstance s) ModelBool where
type TermBaseType (FDInstance s) ModelBool = TermBaseType s (FDBoolTerm s)
getDomainSize v = do
f <- getFailed
if f
then return 0
else do
[var] <- getBoolTerm [v]
liftFD $ getDomainSize var
getValue v = do
[var] <- getBoolTerm [v]
liftFD $ getValue var
setValue _ = error "setting of boolean variable through FD interface is not implemented"
getDomain var = error "retrieval of full boolean domain not implemented in FD"
splitDomain v = do
[var] <- getBoolTerm [v]
(doms,full) <- liftFD $ fdSplitBoolDomain var
return (map (\x -> [Right x]) doms, full)
enumerator = case enumerator of
Nothing -> Nothing
Just e -> Just $ \l -> label $ do
f <- getFailed
if f
then return false
else do
ll <- getBoolTerm l
return $ liftFDTree $ e ll
getIntVal_ :: FDSolver s => EGVarId -> FDState s -> Maybe EGPar
getIntVal_ id s =
let r1 =
case Map.lookup id (fdsIntVars s) of
Nothing -> Nothing
Just x -> fdspIntVal x
in case r1 of
Nothing ->
let Just j = fdsModel s
ei = findEdge j EGIntType id (==0) (\x -> case x of { EGIntValue _ -> True; _ -> False })
in case ei of
Nothing -> Nothing
Just (_,ed) -> case egeCons ed of { EGIntValue c -> Just c }
Just x -> r1
getIntVal :: FDSolver s => EGVarId -> FDInstance s (Maybe EGPar)
getIntVal id = gets $ getIntVal_ id
getBoolVal_ :: FDSolver s => EGVarId -> FDState s -> Maybe EGBoolPar
getBoolVal_ id s =
let r1 =
case Map.lookup id (fdsBoolVars s) of
Nothing -> Nothing
Just x -> fdspBoolVal x
in case r1 of
Nothing ->
let Just j = fdsModel s
l = getConnectedEdges j EGBoolType id
f (EGEdge { egeCons = EGBoolValue c },_) _ = Just c
f _ s = s
in foldr f Nothing l
Just x -> r1
getBoolVal :: FDSolver s => EGVarId -> FDInstance s (Maybe EGBoolPar)
getBoolVal id = gets $ getBoolVal_ id
getColVal_ :: FDSolver s => EGVarId -> FDState s -> Maybe EGColPar
getColVal_ id s =
let r1 =
case Map.lookup id (fdsColVars s) of
Nothing -> Nothing
Just x -> fdspColVal x
in case r1 of
Nothing ->
let Just j = fdsModel s
l = getConnectedEdges j EGColType id
f (EGEdge { egeCons = EGColValue c },_) _ = Just c
f _ s = s
in foldr f Nothing l
Just x -> r1
getColVal :: FDSolver s => EGVarId -> FDInstance s (Maybe EGColPar)
getColVal id = gets $ getColVal_ id
setFailed :: FDSolver s => FDInstance s ()
setFailed = do
s <- get
debug "setFailed!" $ return ()
put $ s { fdsFailed = True }
getFailed :: FDSolver s => FDInstance s Bool
getFailed = do
s <- get
return $ fdsFailed s
addFD :: (Show (Constraint s), FDSolver s) => Constraint s -> FDInstance s ()
addFD c = do
s <- get
if (fdsFailed s)
then debug ("addFD("++(show c)++"): already failed") $ return ()
else do
x <- liftFD $ add c
debug ("addFD("++(show c)++"): result="++(show x)) $ return ()
if not x then setFailed else return ()
getDefIntSpec :: FDSolver s => FDSpecInfoInt s -> FDIntSpec s
getDefIntSpec (FDSpecInfoInt { fdspIntSpec = f }) = case f Nothing of
Just t -> t
Nothing -> error "getDefIntSpec: no spec"
getDefBoolSpec :: FDSolver s => FDSpecInfoBool s -> FDBoolSpec s
getDefBoolSpec (FDSpecInfoBool { fdspBoolSpec = f }) = case f Nothing of
Just t -> t
Nothing -> error "getDefBoolSpec: no spec"
getDefColSpec :: FDSolver s => FDSpecInfoCol s -> FDColSpec s
getDefColSpec (FDSpecInfoCol { fdspColSpec = f }) = case f Nothing of
Just t -> t
Nothing -> error "getDefColSpec: no spec"
getFullIntSpec id = do
s <- get
return $ myFromJust "getFullIntSpec" $ Map.lookup id $ fdsIntVars s
getFullBoolSpec id = do
s <- get
return $ myFromJust "getFullBoolSpec" $ Map.lookup id $ fdsBoolVars s
getFullColSpec id = do
s <- get
return $ myFromJust "getFullColSpec" $ Map.lookup id $ fdsColVars s
fdNewvar :: (FDSolver s, Term s t) => FDInstance s (Maybe t)
fdNewvar = do
s <- get
if fdsDummyLevel s > 0
then return Nothing
else liftFD newvar >>= return . Just