module Data.LinearProgram.GLPK.IO.Internal (readGLPLP, writeGLPLP) where
import Prelude hiding ((+))
import Control.Monad
import Control.Monad.Trans (liftIO, lift)
import Data.Map hiding (map, filter)
import Debug.Trace
import Foreign.Storable
import Data.LinearProgram.Common
import Data.LinearProgram.GLPK.Common
import Control.Monad.LPMonad.Internal
foreign import ccall unsafe "c_glp_write_lp" glpWriteLP :: Ptr GlpProb -> CString -> IO ()
foreign import ccall unsafe "c_glp_read_lp" glpReadLP :: Ptr GlpProb -> CString -> IO ()
foreign import ccall unsafe "c_glp_set_col_name" glpSetColName :: Ptr GlpProb -> CInt -> CString -> IO ()
foreign import ccall unsafe "c_glp_set_row_name" glpSetRowName :: Ptr GlpProb -> CInt -> CString -> IO ()
foreign import ccall unsafe "c_glp_get_obj_dir" glpGetObjDir :: Ptr GlpProb -> IO CInt
foreign import ccall unsafe "c_glp_get_num_rows" glpGetNumRows :: Ptr GlpProb -> IO CInt
foreign import ccall unsafe "c_glp_get_num_cols" glpGetNumCols :: Ptr GlpProb -> IO CInt
foreign import ccall unsafe "c_glp_get_row_name" glpGetRowName :: Ptr GlpProb -> CInt -> IO CString
foreign import ccall unsafe "c_glp_get_col_name" glpGetColName :: Ptr GlpProb -> CInt -> IO CString
foreign import ccall unsafe "c_glp_get_col_kind" glpGetColKind :: Ptr GlpProb -> CInt -> IO CInt
foreign import ccall unsafe "c_glp_get_row_type" glpGetRowType :: Ptr GlpProb -> CInt -> IO CInt
foreign import ccall unsafe "c_glp_get_col_type" glpGetColType :: Ptr GlpProb -> CInt -> IO CInt
foreign import ccall unsafe "c_glp_get_row_lb" glpGetRowLb :: Ptr GlpProb -> CInt -> IO CDouble
foreign import ccall unsafe "c_glp_get_col_lb" glpGetColLb :: Ptr GlpProb -> CInt -> IO CDouble
foreign import ccall unsafe "c_glp_get_row_ub" glpGetRowUb :: Ptr GlpProb -> CInt -> IO CDouble
foreign import ccall unsafe "c_glp_get_col_ub" glpGetColUb :: Ptr GlpProb -> CInt -> IO CDouble
foreign import ccall unsafe "c_glp_get_obj_coef" glpGetObjCoef :: Ptr GlpProb -> CInt -> IO CDouble
foreign import ccall unsafe "c_glp_get_mat_row" glpGetMatRow :: Ptr GlpProb -> CInt -> Ptr CInt -> Ptr CDouble -> IO CInt
writeLP :: FilePath -> GLPK ()
writeLP file = GLP $ withCString file . glpWriteLP
readLP :: FilePath -> GLPK ()
readLP file = GLP $ withCString file . glpReadLP
getDir :: GLPK Direction
getDir = liftM (toEnum . subtract 1 . fromIntegral) $ GLP glpGetObjDir
getRowName, getColName :: Int -> GLPK (Maybe String)
getRowName i = GLP $ peekCAString' <=< flip glpGetRowName (fromIntegral i)
getColName i = GLP $ peekCAString' <=< flip glpGetColName (fromIntegral i)
peekCAString' :: CString -> IO (Maybe String)
peekCAString' str
| str == nullPtr = return Nothing
| otherwise = liftM Just $ peekCAString str
getNumRows, getNumCols :: GLPK Int
getNumRows = liftM fromIntegral $ GLP glpGetNumRows
getNumCols = liftM fromIntegral $ GLP glpGetNumCols
rowBounds, colBounds :: Int -> GLPK (Bounds Double)
rowBounds = loadBounds (getCDouble glpGetRowLb) (getCDouble glpGetRowUb) (getCInt glpGetRowType)
colBounds = loadBounds (getCDouble glpGetColLb) (getCDouble glpGetColUb) (getCInt glpGetColType)
colKind :: Int -> GLPK VarKind
colKind = liftM (toEnum . subtract 1) . getCInt glpGetColKind
getCInt :: (Ptr GlpProb -> CInt -> IO CInt) -> Int -> GLPK Int
getCInt f i = GLP $ \ lp -> liftM fromIntegral $ f lp (fromIntegral i)
getCDouble :: (Ptr GlpProb -> CInt -> IO CDouble) -> Int -> GLPK Double
getCDouble f i = GLP $ \ lp -> liftM realToFrac $ f lp (fromIntegral i)
setRowName :: Int -> String -> GLPK ()
setRowName i nam = GLP $ withCString nam . flip glpSetRowName (fromIntegral i)
setColName :: Int -> String -> GLPK ()
setColName i nam = GLP $ withCString nam . flip glpSetColName (fromIntegral i)
loadBounds :: (Int -> GLPK Double) -> (Int -> GLPK Double) ->
(Int -> GLPK Int) -> Int -> GLPK (Bounds Double)
loadBounds lb ub tp i = do
typ <- tp i
case typ of
1 -> return Free
2 -> liftM LBound (lb i)
3 -> liftM UBound (ub i)
4 -> liftM2 Bound (lb i) (ub i)
_ -> liftM Equ (lb i)
getObjCoef :: Int -> GLPK Double
getObjCoef = getCDouble glpGetObjCoef
getRows :: GLPK [(Int, [(Int, Double)])]
getRows = do n <- getNumRows
m <- getNumCols
ixs <- liftIO $ mallocArray (m+1)
coefs <- liftIO $ mallocArray (m+1)
sequence [do
k <- liftM fromIntegral $ GLP $ \ lp -> glpGetMatRow lp (fromIntegral i) ixs coefs
ixsL <- liftIO $ mapM (peekElemOff ixs) [1..k]
coefsL <- liftIO $ mapM (peekElemOff ixs) [1..k]
return (i, zip (map fromIntegral ixsL) (map realToFrac coefsL))
| i <- [1..n]]
readGLPLP :: FilePath -> GLPK (LP String Double)
readGLPLP file = execLPT $ do
lift $ readLP file
setDirection =<< lift getDir
nCols <- lift getNumCols
names <- lift $ liftM fromList $ mapM (\ i -> do
Just name <- getColName i
return (i, name)) [1..nCols]
sequence_ [do
bds <- lift $ colBounds i
kind <- lift $ colKind i
setVarBounds name bds
setVarKind name kind
return (i, name)
| (i, name) <- assocs names]
rowContents <- lift getRows
sequence_ [do
bds <- lift $ rowBounds i
name <- lift $ getRowName i
maybe constrain constrain' name
(linCombination [(v, names ! j) | (j, v) <- row]) bds
| (i, row) <- rowContents]
obj <- lift $ sequence [do
c <- getObjCoef i
return (name, c) | (i, name) <- assocs names]
setObjective (fromList (filter ((/= 0) . snd) obj))
writeGLPLP :: (Show v, Ord v, Real c) => FilePath -> LP v c -> GLPK ()
writeGLPLP file lp = do
vars <- writeProblem lp
sequence_ [setColName i (show v) | (v, i) <- assocs vars]
sequence_ [setRowName i lab | (i, Constr (Just lab) _ _) <- zip [1..] (constraints lp)]
writeLP file