{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE UndecidableInstances #-} 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.Expr.Util 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 -- | state kept by FDInstance, in addition to the underlying solver's internal state data FDSolver s => FDState s = FDState { -- | expression representing unprocessed constraints fdsExpr :: Model, -- | model being processed now fdsModel :: Maybe EGModel, -- | private data for the decomposer (kept to optimize constraints which aren't added in one go) fdsDecomp :: DecompData, -- | when adding constraints, the EGEdgeId's occurring in the decomposed model fdsNewEdges :: Set EGEdgeId, fdsDoneEdges :: Set EGEdgeId, -- | expressions that need to be decomposed fdsForceBool :: [ModelBool], fdsForcedBool :: Map ModelBool (FDBoolTerm s), fdsForceInt :: [ModelInt], fdsForcedInt :: Map ModelInt (FDIntTerm s), fdsForceCol :: [ModelCol], -- | variable counter fdsVars :: Int, -- | already introduced integer variables/terms/constants/expressions fdsIntVars :: Map EGVarId (FDSpecInfoInt s), -- | needed sets of possible types fdsIntVarTypes :: Map EGVarId (Set (FDIntSpecTypeSet s)), -- | which variables are being decomposed right now fdsIntVarBusy :: Set EGVarId, -- | which nodes are unified with which others fdsIntUnifies :: Map EGVarId (Set EGVarId), -- | already introduced boolean variables/terms/constants/expressions fdsBoolVars :: Map EGVarId (FDSpecInfoBool s), fdsBoolVarTypes :: Map EGVarId (Set (FDBoolSpecTypeSet s)), fdsBoolVarBusy :: Set EGVarId, fdsBoolUnifies :: Map EGVarId (Set EGVarId), -- | already introduced collection variables/terms/constants/expressions fdsColVars :: Map EGVarId (FDSpecInfoCol s), fdsColVarTypes :: Map EGVarId (Set (FDColSpecTypeSet s)), fdsColVarBusy :: Set EGVarId, fdsColUnifies :: Map EGVarId (Set EGVarId), -- | db of specifiers fdsDb :: SpecDb s, -- | solver is failed? fdsFailed :: Bool, -- | level of nesting fdsLevel :: Int, -- | levels of dummyness 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) -- case (fdsMinimizeTerm s) of -- q@(Just _) -> return q -- Nothing -> case (fdsMinimizeVar s) of -- Nothing -> return Nothing -- Just v -> do -- q <- getSingleIntTerm v -- put s { fdsMinimizeTerm = Just q } -- return $ Just q 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 :: FDSolver s => EGModel -> (Int -> Maybe (FDSpecInfoBool s), Int -> Maybe (FDSpecInfoInt s), Int -> Maybe (FDSpecInfoCol s)) -> FDInstance 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 -- | initial FDState state 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 -- | run the second argument as long as the first one produces true 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 () -- | a label for an FDInstance; must store the FDState plus the Solver's internal state data FDSolver s => FDLabel s = FDLabel { fdlState :: FDState s, fdlLabel :: Label s } -- | definition of FDInstance, a Solver wrapper that adds power to post boolean expressions as constraints newtype FDSolver s => FDInstance s a = FDInstance { unFDInstance :: StateT (FDState s) s a } deriving (Monad, MonadState (FDState s)) -- | helper function to combine two Maybe'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 -- | lift a monad action for the underlying solver to a monad action for an FDInstance around it 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 -- an m x = case x of -- Just i -> Map.lookup i m -- Nothing -> if Map.null m then Nothing else Just $ snd $ Map.findMin m -- boolX v = FDSpecInfoBool { fdspBoolSpec = an $ boolS v, fdspBoolVar = Just v, fdspBoolVal = getBoolVal_ v s, fdspBoolTypes = Set.fromList $ Map.keys $ boolS v } -- intX v = FDSpecInfoInt { fdspIntSpec = an $ intS v, fdspIntVar = Just v, fdspIntVal = getIntVal_ v s, fdspIntTypes = Set.fromList $ Map.keys $ intS v } -- colX v = FDSpecInfoCol { fdspColSpec = an $ colS v, fdspColVar = Just v, fdspColVal = getColVal_ v s, fdspColTypes = Set.fromList $ Map.keys $ colS v } 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) -- | A solver needs to be an instance of this FDSolver class in order to -- create an FDInstance around it. 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), -- Integral (TermBaseType s (FDIntTerm s)), Num (TermBaseType s (FDBoolTerm s)), Show (FDIntSpec s), Show (FDColSpec s), Show (FDBoolSpec s) ) => FDSolver s where -- term types type FDIntTerm s :: * -- a Term of s, representing Integer variables type FDBoolTerm s :: * -- a Term of s, representing Bool variables -- spec types type FDIntSpec s :: * -- a type specifying an Integer expression; should at least support constant Integer's and FDIntTerm's type FDBoolSpec s :: * -- a type specifying a Bool expression; should at least support constant Bool's and FDBoolTerm's type FDColSpec s :: * -- a type specifying a Integer array expression; should at least support lists of Int's and lists of IntTerm's -- spec type type type FDIntSpecType s :: * -- a type specifying the type of an FDIntSpec s, in case there is more than one type FDBoolSpecType s :: * -- a type specifying the type of an FDIntSpec s, in case there is more than one type FDColSpecType s :: * -- a type specifying the type of an FDIntSpec s, in case there is more than one -- constructors for specifiers 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)) -- function to inform about allowed types for nodes 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 -- rating functions for specification of terms fdSpecify :: Mixin (SpecFn s) fdSpecify = mixinId -- inspect collections fdColInspect :: FDColSpec s -> s [FDIntTerm s] -- function to request processing an edge in a graph fdProcess :: Mixin (EGConstraintSpec -> FDSpecInfo s -> FDInstance s ()) -- add equality constraints 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) -- | mark all new edges(=constraints) of a model given in graph-form as to-be-processed 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 } -- | add an int term addIntVar :: FDSolver s => EGVarId -> FDIntSpecType s -> (FDIntSpec s, Maybe EGPar) -> FDInstance s () addIntVar id typ (spec@(rs,_)) = do -- debug ("addIntVar id="++(show id)++" typ="++(show typ)++" spec="++(show spec)) $ return () 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 } -- | add a bool term addBoolVar :: FDSolver s => EGVarId -> FDBoolSpecType s -> (FDBoolSpec s, Maybe EGBoolPar) -> FDInstance s () addBoolVar id typ (spec@(rs,_)) = do -- debug ("addBoolVar id="++(show id)++" typ="++(show typ)++" spec="++(show spec)) $ return () 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 } -- | add a col term addColVar :: FDSolver s => EGVarId -> FDColSpecType s -> (FDColSpec s, Maybe EGColPar) -> FDInstance s () addColVar id typ (spec@(rs,_)) = do -- debug ("addColVar id="++(show id)++" typ="++(show typ)++" spec="++(show spec)) $ return () 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 () -- search spec type requirements for all to-be-processed edges debug ("addTypeReqs ["++(show $ fdsLevel ss0)++"]") $ addTypeReqs -- optimize type requirements debug ("optimizeVarTypes["++(show $ fdsLevel ss0)++"]") $ optimizeVarTypes ss <- get debug ("DUMP type reqs ["++(show $ fdsLevel ss0)++"]: "++(show $ fdsIntVarTypes ss)) $ return () -- build specifier database for all to-be-processed edges debug ("buildSpecDb ["++(show $ fdsLevel ss0)++"]") $ buildSpecDb ss2 <- get debug ("DUMP spec db ["++(show $ fdsLevel ss0)++"]: "++(show $ fdsDb ss2)) $ return () -- create as much specifiers as possible (marking consumed edges as processed) whileM_ $ debug ("decompBest ["++(show $ fdsLevel ss0)++"]") decompBest -- try default specifier for remaining boolean nodes (=create new underlying term for each) whileM_ $ debug ("decompDefBool ["++(show $ fdsLevel ss0)++"]") decompDefaultBool -- try default specifier for remaining integer nodes (=create new underlying term for each) whileM_ $ debug ("decompDefInt ["++(show $ fdsLevel ss0)++"]") decompDefaultInt ss3 <- get debug ("DUMP specs: "++(dumpSpec ss3)) $ return () -- process remaining edges 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 () -- mark all non-yet-processed edges as to-be-processed 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 var val = return [var @== cte val] 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 var val = return [var @= BoolConst (val /] 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 :: FDSolver s => EGVarId -> s (FDSpecInfoInt s) getFullIntSpec id = do s <- get return $ myFromJust "getFullIntSpec" $ Map.lookup id $ fdsIntVars s -- getFullBoolSpec :: FDSolver s => EGVarId -> s (FDSpecInfoBool s) getFullBoolSpec id = do s <- get return $ myFromJust "getFullBoolSpec" $ Map.lookup id $ fdsBoolVars s -- getFullColSpec :: FDSolver s => EGVarId -> s (FDSpecInfoCol 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