module Data.LinearProgram.GLPK.IO.Internal (readGLPLP, writeGLPLP) where
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