packages feed

monadiccp-0.6: Control/CP/FD/Gecode/RuntimeSolver.hs

{-# LANGUAGE CPP #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE MultiParamTypeClasses #-}

#ifdef RGECODE

module Control.CP.FD.Gecode.RuntimeSolver (
  SearchSolver(..),
  RuntimeSolver(..)
) where

import Maybe (fromMaybe,catMaybes,isJust,fromJust)
import List (findIndex,find)
import Data.Map hiding (map,filter)

import Control.Monad.State.Lazy
import Control.Monad.Trans
import Control.Monad.Cont

import Data.Bits
import Data.Word
import Foreign
import Foreign.Storable
import Foreign.Marshal
import Foreign.Marshal.Array
import Foreign.Ptr
import Foreign.ForeignPtr
import Foreign.C.String
import Foreign.C.Types

import Control.CP.SearchTree hiding (label)
import Control.CP.Solver
import Control.CP.FD.FD
import Control.CP.FD.Expr
import Control.CP.Debug
import Control.CP.Mixin
import Control.CP.EnumTerm

import Control.CP.FD.Gecode.Common
import Control.CP.FD.Gecode.Interface

class (Monad s, MonadState (GecodeState s) s, MonadIO s, Term s IntTerm) => RuntimeGecodeSolver s where
  stateM :: s a -> StateT (GecodeState s) IO a

instance Solver RuntimeSolver where
   type Constraint RuntimeSolver = GConstraint
   type Label RuntimeSolver = GecodeState RuntimeSolver
   add   = addRuntimeGecode
   run   = fst . runRuntimeGecode False
   mark  = do
     s <- get
     copyState s
   goto s = do
     x <- copyState s
     put x

instance Solver SearchSolver where
   type Constraint SearchSolver = GConstraint
   type Label SearchSolver = GecodeState SearchSolver
   add   = addRuntimeGecode
   run   = fst . runRuntimeGecode False
   mark  = do
     s <- get
     copyState s
   goto s = do
     x <- copyState s
     put x

--------------------------------------------------------------------------------
-- | Gecode terms
--------------------------------------------------------------------------------

instance Term SearchSolver IntTerm where
  newvar = newVarInt
  type Help SearchSolver IntTerm = ()
  help _ _ = ()
instance Term RuntimeSolver IntTerm where
  newvar = newVarInt
  type Help RuntimeSolver IntTerm = ()
  help _ _ = ()
instance Term SearchSolver BoolTerm where
  newvar = newVarBool
  type Help SearchSolver BoolTerm = ()
  help _ _ = ()
instance Term RuntimeSolver BoolTerm where
  newvar = newVarBool
  type Help RuntimeSolver BoolTerm = ()
  help _ _ = ()
  

--------------------------------------------------------------------------------
-- | Gecode monad definition 
--------------------------------------------------------------------------------

data RuntimeGecodeSolver s => GecodeState s = GecodeState { spaceRef :: Space, cexpr :: Map (ExprKey (FDTerm s)) Int }


newtype RuntimeSolver a = RuntimeSolver { rStateM :: StateT (GecodeState RuntimeSolver) IO a }
  deriving (Monad, MonadState (GecodeState RuntimeSolver), MonadIO)
newtype SearchSolver a = SearchSolver { sStateM :: StateT (GecodeState SearchSolver) IO a }
  deriving (Monad, MonadState (GecodeState SearchSolver), MonadIO)

newState :: RuntimeGecodeSolver s => Bool -> IO (GecodeState s)
newState gcs = do
  initSpace <- newSpace
  return $ GecodeState { spaceRef = initSpace, cexpr = Data.Map.empty }

copyState :: RuntimeGecodeSolver s => GecodeState s -> s (GecodeState s)
copyState state = do
  x <- liftIO $ copySpace (spaceRef state)
  return $ state { spaceRef = x }

runRuntimeGecode :: RuntimeGecodeSolver s => Bool -> s a -> (a, GecodeState s)
runRuntimeGecode gcs p = unsafePerformIO $ do
  initState <- newState gcs
  runStateT (stateM p) initState

continueRuntimeGecode :: RuntimeGecodeSolver s => GecodeState s -> s a -> (a, GecodeState s)
continueRuntimeGecode st p = unsafePerformIO $ runStateT (stateM p) st

intTermInfo :: RuntimeGecodeSolver s => IntTerm -> s IntTermInfo
intTermInfo (IntVar i) = do
  GecodeState { spaceRef = s } <- get
  liftIO $ getIntTermInfo s i

addRuntimeGecode :: RuntimeGecodeSolver s => GConstraint -> s Bool
addRuntimeGecode (CDom (IntVar i) low high) = proc $ \ptr -> c_gecode_int_dom ptr (toCGIntVar i) (toCGVal low) (toCGVal high)
addRuntimeGecode (CRel (IntVar i1) op (IntVar i2)) = proc $ \ptr -> c_gecode_int_rel ptr (toCGIntVar i1) (mapGOperator op) (toCGIntVar i2)
addRuntimeGecode (CRel (IntConst c1) op (IntVar i2)) = proc $ \ptr -> c_gecode_int_rel_cf ptr (toCGVal c1) (mapGOperator op) (toCGIntVar i2)
addRuntimeGecode (CRel (IntVar i1) op (IntConst c2)) = proc $ \ptr -> c_gecode_int_rel_cs ptr (toCGIntVar i1) (mapGOperator op) (toCGVal c2)
addRuntimeGecode (CValue (IntVar i) val) = proc $ \ptr -> c_gecode_int_value ptr (toCGIntVar i) (toCGVal val)
addRuntimeGecode (CMult (IntVar i1) (IntVar i2) (IntVar ir)) = proc $ \ptr -> c_gecode_int_mult ptr (toCGIntVar i1) (toCGIntVar i2) (toCGIntVar ir)
addRuntimeGecode (CDiv (IntVar i1) (IntVar i2) (IntVar ir)) = proc $ \ptr -> c_gecode_int_div ptr (toCGIntVar i1) (toCGIntVar i2) (toCGIntVar ir)
addRuntimeGecode (CMod (IntVar i1) (IntVar i2) (IntVar ir)) = proc $ \ptr -> c_gecode_int_mod ptr (toCGIntVar i1) (toCGIntVar i2) (toCGIntVar ir)
addRuntimeGecode (CAbs (IntVar i) (IntVar ir)) = proc $ \ptr -> c_gecode_int_abs ptr (toCGIntVar i) (toCGIntVar ir)
addRuntimeGecode (CLinear l op val) = do
  GecodeState { spaceRef = s } <- get
  let len = length l
  let vars = map (\(IntVar var,_) -> toCGIntVar var) l
  let coefs = map (\(_,coef) -> toCGVal coef) l
  liftIO $ 
    withArray vars $ \pVars ->
      withArray coefs $ \pCoefs -> do
        b <- withForeignPtr s $ \ptr -> c_gecode_int_linear ptr (fromIntegral len) pVars pCoefs (mapGOperator op) (toCGVal val)
        return $ fromCGBool b
addRuntimeGecode (CAllDiff l) = do
  GecodeState { spaceRef = s } <- get
  let len = length l
  let vars = map (\(IntVar i) -> toCGIntVar i) l
  liftIO $
    withArray vars $ \pVars -> do
      b <- withForeignPtr s $ \ptr -> c_gecode_int_alldiff ptr (fromIntegral len) pVars
      return $ fromCGBool b
addRuntimeGecode (CSorted l strict) = do
  GecodeState { spaceRef = s } <- get
  let len = length l
  let vars = map (\(IntVar i) -> toCGIntVar i) l
  liftIO $
    withArray vars $ \pVars -> do
      b <- withForeignPtr s $ \ptr -> c_gecode_int_sorted ptr (fromIntegral len) pVars (toCGBool strict)
      return $ fromCGBool b

proc f = do
  GecodeState { spaceRef = s } <- get
  liftIO $ do
    b <- withForeignPtr s f
    return $ fromCGBool b

--------------------------------------------------------------------------------
-- | RuntimeSolver solver implementation
--------------------------------------------------------------------------------

newVarInt :: RuntimeGecodeSolver s => s IntTerm
newVarInt = do
  GecodeState { spaceRef = s } <- get
  (CGIntVar r) <- liftIO $ withForeignPtr s $ c_gecode_int_newvar 
  return (IntVar $ fromIntegral r)

newVarBool :: RuntimeGecodeSolver s => s BoolTerm
newVarBool = do
  GecodeState { spaceRef = s } <- get
  (CGBoolVar r) <- liftIO $ withForeignPtr s $ c_gecode_bool_newvar
  return (BoolVar $ fromIntegral r)

--------------------------------------------------------------------------------
-- | RuntimeSolver FDSolver instance
--------------------------------------------------------------------------------

instance (RuntimeGecodeSolver s, Ord (FDTerm s)) => GecodeSolver s where
  caching_decompose super this x = Label $ do
    s <- get
    let wx = ExprKey x
    case Data.Map.lookup wx (cexpr s) of
      Nothing -> return $ do
        n@(IntVar i) <- super x
        Label $ do
          s <- get
          put $ s { cexpr = insert wx i $ cexpr s }
          return $ return n
      Just i -> return $ return $ IntVar i
  setVarImplicit (IntVar i) b = return ()

instance FDSolver RuntimeSolver where
  type FDTerm RuntimeSolver = IntTerm
  specific_compile_constraint = linearCompile <@> basicCompile
  specific_decompose = caching_decompose
  specific_fresh_var super this = do
    v@(IntVar i) <- super
    Label $ do
      setVarImplicit (IntVar i) True
      return $ Return v

instance FDSolver SearchSolver where
  type FDTerm SearchSolver = IntTerm
  specific_compile_constraint = linearCompile <@> basicCompile
  specific_decompose = caching_decompose
  specific_fresh_var super this = do
    v@(IntVar i) <- super
    Label $ do
      setVarImplicit (IntVar i) True
      return $ Return v


instance EnumTerm RuntimeSolver IntTerm where
  type TermDomain RuntimeSolver IntTerm = CInt
  get_domain_size v = do
    IntTermInfo { iti_size = size } <- intTermInfo v
    return $ fromIntegral size
  get_value v = do
    IntTermInfo { iti_val = val } <- intTermInfo v
    return val
  split_domain_partial v@(IntVar it) = do
    IntTermInfo { iti_val = val, iti_med = med, iti_size = size } <- intTermInfo v
    return $ if size == 0
      then []
      else if isJust val
        then [return ()]
        else [Add (CRel v OLess (IntConst $ (fromIntegral med)+1)) $ enumerate [v],Add (CRel (IntConst $ fromIntegral med) OLess v) $ enumerate [v]]


instance EnumTerm SearchSolver IntTerm where
  type TermDomain SearchSolver IntTerm = CInt
  get_domain_size v = do
    IntTermInfo { iti_size = size } <- intTermInfo v
    return $ fromIntegral size
  get_value v = do
    IntTermInfo { iti_val = val } <- intTermInfo v
    return val
    
  split_domains lst = do
    let 
      folder a b = case a of
        IntVar i -> (i:b)
        _ -> b
    let vars = map toCGIntVar $ foldr folder [] lst
    state <- get
    liftIO $ withArray vars $ \ptr -> withForeignPtr (spaceRef state) $ \sptr -> c_gecode_int_branch sptr (fromIntegral $ length vars) ptr
    search <- liftIO $ newSearch $ spaceRef state
    let 
      go i = unsafePerformIO $ do
        res <- runSearch search
        case res of
          Nothing -> return $ return ()
          Just x -> return $ Try (Label $ do
              put state { spaceRef = x }
              return $ return ()
            ) (go $ i+1)
    return $ go 0

  split_domain_partial v = do
    x <- split_domains [v]
    return [x]

  label _   = Label . split_domains
  enumerate = Label . split_domains

---------------------------------------------
-- | RuntimeGecodeSolver instances
---------------------------------------------

instance RuntimeGecodeSolver RuntimeSolver where
  stateM = rStateM

instance RuntimeGecodeSolver SearchSolver where
  stateM = sStateM

#endif