{-# OPTIONS_GHC -Wall #-}
{-# OPTIONS_HADDOCK show-extensions #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
module Numeric.Optimization.MIP
( module Numeric.Optimization.MIP.Base
, readFile
, readLPFile
, readMPSFile
, parseLPString
, parseMPSString
, writeFile
, writeLPFile
, writeMPSFile
, toLPString
, toMPSString
, ParseError
) where
import Prelude hiding (readFile, writeFile)
import Control.Exception
import Data.Char
import Data.Scientific (Scientific)
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.IO as TLIO
import System.FilePath (takeExtension, splitExtension)
import System.IO hiding (readFile, writeFile)
import Numeric.Optimization.MIP.Base
import Numeric.Optimization.MIP.FileUtils (ParseError)
import qualified Numeric.Optimization.MIP.LPFile as LPFile
import qualified Numeric.Optimization.MIP.MPSFile as MPSFile
#ifdef WITH_ZLIB
import qualified Codec.Compression.GZip as GZip
import qualified Data.ByteString.Lazy as BL
import Data.ByteString.Lazy.Encoding (encode, decode)
import qualified Data.CaseInsensitive as CI
import GHC.IO.Encoding (getLocaleEncoding)
#endif
readFile :: FileOptions -> FilePath -> IO (Problem Scientific)
readFile opt fname =
case getExt fname of
".lp" -> readLPFile opt fname
".mps" -> readMPSFile opt fname
ext -> ioError $ userError $ "unknown extension: " ++ ext
readLPFile :: FileOptions -> FilePath -> IO (Problem Scientific)
#ifndef WITH_ZLIB
readLPFile = LPFile.parseFile
#else
readLPFile opt fname = do
s <- readTextFile opt fname
let ret = LPFile.parseString opt fname s
case ret of
Left e -> throw e
Right a -> return a
#endif
readMPSFile :: FileOptions -> FilePath -> IO (Problem Scientific)
#ifndef WITH_ZLIB
readMPSFile = MPSFile.parseFile
#else
readMPSFile opt fname = do
s <- readTextFile opt fname
let ret = MPSFile.parseString opt fname s
case ret of
Left e -> throw e
Right a -> return a
#endif
readTextFile :: FileOptions -> FilePath -> IO TL.Text
#ifndef WITH_ZLIB
readTextFile opt fname = do
h <- openFile fname ReadMode
case optFileEncoding opt of
Nothing -> return ()
Just enc -> hSetEncoding h enc
TLIO.hGetContents h
#else
readTextFile opt fname = do
enc <- case optFileEncoding opt of
Nothing -> getLocaleEncoding
Just enc -> return enc
let f = if CI.mk (takeExtension fname) == ".gz" then GZip.decompress else id
s <- BL.readFile fname
return $ decode enc $ f s
#endif
parseLPString :: FileOptions -> String -> String -> Either (ParseError String) (Problem Scientific)
parseLPString = LPFile.parseString
parseMPSString :: FileOptions -> String -> String -> Either (ParseError String) (Problem Scientific)
parseMPSString = MPSFile.parseString
writeFile :: FileOptions -> FilePath -> Problem Scientific -> IO ()
writeFile opt fname prob =
case getExt fname of
".lp" -> writeLPFile opt fname prob
".mps" -> writeMPSFile opt fname prob
ext -> ioError $ userError $ "unknown extension: " ++ ext
getExt :: String -> String
getExt fname | (base, ext) <- splitExtension fname =
case map toLower ext of
#ifdef WITH_ZLIB
".gz" -> getExt base
#endif
s -> s
writeLPFile :: FileOptions -> FilePath -> Problem Scientific -> IO ()
writeLPFile opt fname prob =
case LPFile.render opt prob of
Left err -> ioError $ userError err
Right s -> writeTextFile opt fname s
writeMPSFile :: FileOptions -> FilePath -> Problem Scientific -> IO ()
writeMPSFile opt fname prob =
case MPSFile.render opt prob of
Left err -> ioError $ userError err
Right s -> writeTextFile opt fname s
writeTextFile :: FileOptions -> FilePath -> TL.Text -> IO ()
writeTextFile opt fname s = do
let writeSimple = do
withFile fname WriteMode $ \h -> do
case optFileEncoding opt of
Nothing -> return ()
Just enc -> hSetEncoding h enc
TLIO.hPutStr h s
#ifdef WITH_ZLIB
if CI.mk (takeExtension fname) /= ".gz" then do
writeSimple
else do
enc <- case optFileEncoding opt of
Nothing -> getLocaleEncoding
Just enc -> return enc
BL.writeFile fname $ GZip.compress $ encode enc s
#else
writeSimple
#endif
toLPString :: FileOptions -> Problem Scientific -> Either String TL.Text
toLPString = LPFile.render
toMPSString :: FileOptions -> Problem Scientific -> Either String TL.Text
toMPSString = MPSFile.render