{-# OPTIONS -funbox-strict-fields #-} {-# LANGUAGE TupleSections, RecordWildCards #-} module Data.LinearProgram.GLPK.Solver ( -- * Solver options GLPOpts(..), simplexDefaults, mipDefaults, -- * Running the solver glpSolveVars, RowValue(..), glpSolveAll, -- * GLPK enumerations ReturnCode(..), MsgLev(..), BranchingTechnique(..), BacktrackTechnique(..), Preprocessing(..), Cuts(..)) where import Control.Monad -- import Control.Monad.Trans -- import Debug.Trace import Data.Map -- import Data.Maybe (catMaybes) import Data.LinearProgram.Common import Data.LinearProgram.GLPK.Internal import Data.LinearProgram.GLPK.Types -- import Data.Time.Clock -- import System.Time import GHC.Exts(build) -- | Options available for customizing GLPK operations. This also determines -- which kind of solving is performed -- relaxed LP, or MIP. data GLPOpts = SimplexOpts {msgLev :: MsgLev, tmLim :: !Int, presolve :: Bool} | MipOpts {msgLev :: MsgLev, tmLim :: !Int, presolve :: Bool, brTech :: BranchingTechnique, btTech :: BacktrackTechnique, ppTech :: Preprocessing, fpHeur :: Bool, cuts :: [Cuts], mipGap :: !Double} data RowValue v c = RowVal {row :: !(Constraint v c), rowVal :: !Double} simplexDefaults, mipDefaults :: GLPOpts simplexDefaults = SimplexOpts MsgOn 10000 True mipDefaults = MipOpts MsgOn 10000 True DrTom LocBound AllPre False [] 0.0 -- | Solves the linear or mixed integer programming problem. Returns -- the value of the objective function, and the values of the variables. glpSolveVars :: (Ord v, Real c) => GLPOpts -> LP v c -> IO (ReturnCode, Maybe (Double, Map v Double)) glpSolveVars opts@SimplexOpts{} lp = runGLPK $ do (code, vars) <- doGLP opts lp liftM (code, ) $ maybe (return Nothing) ( \ vars -> do obj <- getObjVal vals <- sequence [do val <- getColPrim i return (v, val) | (v, i) <- assocs vars] return (Just (obj, fromDistinctAscList vals))) vars glpSolveVars opts@MipOpts{} lp = runGLPK $ do (code, vars) <- doGLP opts lp liftM (code, ) $ maybe (return Nothing) (\ vars -> do obj <- mipObjVal vals <- sequence [do val <- mipColVal i return (v, val) | (v, i) <- assocs vars] return (Just (obj, fromDistinctAscList vals))) vars -- | Solves the linear or mixed integer programming problem. Returns -- the value of the objective function, the values of the variables, -- and the values of any labeled rows. glpSolveAll :: (Ord v, Real c) => GLPOpts -> LP v c -> IO (ReturnCode, Maybe (Double, Map v Double, [RowValue v c])) glpSolveAll opts@SimplexOpts{} lp@LP{..} = runGLPK $ do (code, vars) <- doGLP opts lp liftM (code, ) $ maybe (return Nothing) (\ vars -> do obj <- getObjVal vals <- sequence [do val <- getColPrim i return (v, val) | (v, i) <- assocs vars] rows <- sequence [liftM (RowVal c) (getRowPrim i) | (i, c) <- zip [1..] constraints] return (Just (obj, fromDistinctAscList vals, rows))) vars glpSolveAll opts@MipOpts{} lp@LP{..} = runGLPK $ do (code, vars) <- doGLP opts lp liftM (code, ) $ maybe (return Nothing) (\ vars -> do obj <- mipObjVal vals <- sequence [do val <- mipColVal i return (v, val) | (v, i) <- assocs vars] rows <- sequence [liftM (RowVal c) (getRowPrim i) | (i, c) <- zip [1..] constraints] return (Just (obj, fromDistinctAscList vals, rows))) vars doGLP :: (Ord v, Real c) => GLPOpts -> LP v c -> GLPK (ReturnCode, Maybe (Map v Int)) doGLP SimplexOpts{..} lp = do vars <- writeProblem lp success <- solveSimplex msgLev tmLim presolve return (success, guard (gaveAnswer success) >> Just vars) doGLP MipOpts{..} lp = do vars <- writeProblem lp -- time <- getTime -- solveSimplex msgLev tmLim presolve -- time' <- getTime let tmLim' = tmLim --- round (toRational (time' `diffUTCTime` time)) success <- mipSolve msgLev brTech btTech ppTech fpHeur cuts mipGap (fromIntegral tmLim') presolve return (success, guard (gaveAnswer success) >> Just vars) --(if success then Just vars else Nothing) -- where getTime = liftIO getCurrentTime {-# RULES "assocs" assocs = \ m -> build (\ c n -> foldWithKey (curry c) n m); "elems" elems = \ m -> build (\ c n -> foldWithKey (const c) n m); "keys" keys = \ m -> build (\ c n -> foldWithKey (\ k _ -> c k) n m); #-}