• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

msakai / haskell-MIP / 351

04 Jan 2026 10:32PM UTC coverage: 77.291% (+0.005%) from 77.286%
351

push

github

msakai
update ChangeLog for v0.2.0.1

1518 of 1964 relevant lines covered (77.29%)

0.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

74.58
/MIP/src/Numeric/Optimization/MIP.hs
1
{-# OPTIONS_GHC -Wall #-}
2
{-# OPTIONS_HADDOCK show-extensions #-}
3
{-# LANGUAGE CPP #-}
4
{-# LANGUAGE FlexibleContexts #-}
5
{-# LANGUAGE OverloadedStrings #-}
6
{-# LANGUAGE TypeFamilies #-}
7
{-# LANGUAGE TypeOperators #-}
8
-----------------------------------------------------------------------------
9
-- |
10
-- Module      :  Numeric.Optimization.MIP
11
-- Copyright   :  (c) Masahiro Sakai 2011-2014
12
-- License     :  BSD-style
13
--
14
-- Maintainer  :  masahiro.sakai@gmail.com
15
-- Stability   :  provisional
16
-- Portability :  non-portable
17
--
18
-- Mixed-Integer Programming Problems with some commmonly used extensions
19
--
20
-----------------------------------------------------------------------------
21
module Numeric.Optimization.MIP
22
  (
23
  -- * Mixed-Integer Programming (MIP) problem specification
24

25
  -- ** MIP problems
26
    Problem (..)
27

28
  -- *** Set of variables
29
  , variables
30
  , continuousVariables
31
  , integerVariables
32
  , binaryVariables
33
  , semiContinuousVariables
34
  , semiIntegerVariables
35

36
  -- *** Variable's attributes
37
  , varTypes
38
  , varType
39
  , getVarType
40
  , varBounds
41
  , getBounds
42

43
  -- ** Variables
44
  , Var (Var)
45
  , varName
46
  , toVar
47
  , fromVar
48

49
  -- *** Variable types
50
  , VarType (..)
51

52
  -- *** Variable bounds
53
  , BoundExpr
54
  , Extended (..)
55
  , Bounds
56
  , defaultBounds
57
  , defaultLB
58
  , defaultUB
59

60
  -- ** Labels
61
  , Label
62

63
  -- ** Expressions
64
  , Expr (Expr)
65
  , varExpr
66
  , constExpr
67
  , terms
68
  , Term (..)
69

70
  -- ** Objective function
71
  , OptDir (..)
72
  , ObjectiveFunction (..)
73

74
  -- ** Constraints
75

76
  -- *** Linear (or Quadratic or Polynomial) constraints
77
  , Constraint (..)
78
  , (.==.)
79
  , (.<=.)
80
  , (.>=.)
81
  , RelOp (..)
82

83
  -- *** SOS constraints
84
  , SOSType (..)
85
  , SOSConstraint (..)
86

87
  -- * Solutions
88
  , Solution (..)
89
  , Status (..)
90
  , meetStatus
91

92
  -- * Evaluation
93
  , Tol (..)
94
  , zeroTol
95
  , Eval (..)
96

97
  -- * File I/O
98
  -- $IO
99
  , FileOptions (..)
100
  , WriteSetting (..)
101

102
  -- ** Reading problem files
103
  , readFile
104
  , readLPFile
105
  , readMPSFile
106
  , parseLPString
107
  , parseMPSString
108
  , ParseError
109

110
  -- ** Generating problem files
111
  , writeFile
112
  , writeLPFile
113
  , writeMPSFile
114
  , toLPString
115
  , toMPSString
116

117
  -- * Utilities
118
  , Default (..)
119
  , Variables (..)
120
  , intersectBounds
121
  ) where
122

123
import Prelude hiding (readFile, writeFile)
124
import Control.Exception
125
import Data.Char
126
import Data.Scientific (Scientific)
127
import Data.String
128
import qualified Data.Text.Lazy as TL
129
import qualified Data.Text.Lazy.IO as TLIO
130
import System.FilePath (takeExtension, splitExtension)
131
import System.IO hiding (readFile, writeFile)
132
import Text.Megaparsec (Stream (..))
133

134
import Numeric.Optimization.MIP.Base
135
import Numeric.Optimization.MIP.FileUtils (ParseError)
136
import qualified Numeric.Optimization.MIP.LPFile as LPFile
137
import qualified Numeric.Optimization.MIP.MPSFile as MPSFile
138

139
#ifdef WITH_ZLIB
140
import qualified Codec.Compression.GZip as GZip
141
import qualified Data.ByteString.Lazy as BL
142
import Data.ByteString.Lazy.Encoding (encode, decode)
143
import qualified Data.CaseInsensitive as CI
144
import GHC.IO.Encoding (getLocaleEncoding)
145
#endif
146

147
-- | Parse LP or MPS file based on file extension.
148
readFile :: FileOptions -> FilePath -> IO (Problem Scientific)
149
readFile opt fname =
1✔
150
  case getExt fname of
1✔
151
    ".lp"  -> readLPFile opt fname
1✔
152
    ".mps" -> readMPSFile opt fname
1✔
153
    ext -> ioError $ userError $ "unknown extension: " ++ ext
×
154

155
-- | Parse a file containing LP file data.
156
readLPFile :: FileOptions -> FilePath -> IO (Problem Scientific)
157
#ifndef WITH_ZLIB
158
readLPFile = LPFile.parseFile
159
#else
160
readLPFile opt fname = do
1✔
161
  s <- readTextFile opt fname
1✔
162
  let ret = LPFile.parseString opt fname s
×
163
  case ret of
1✔
164
    Left e -> throw e
×
165
    Right a -> return a
1✔
166
#endif
167

168
-- | Parse a file containing MPS file data.
169
readMPSFile :: FileOptions -> FilePath -> IO (Problem Scientific)
170
#ifndef WITH_ZLIB
171
readMPSFile = MPSFile.parseFile
172
#else
173
readMPSFile opt fname = do
1✔
174
  s <- readTextFile opt fname
1✔
175
  let ret = MPSFile.parseString opt fname s
×
176
  case ret of
1✔
177
    Left e -> throw e
×
178
    Right a -> return a
1✔
179
#endif
180

181
readTextFile :: FileOptions -> FilePath -> IO TL.Text
182
#ifndef WITH_ZLIB
183
readTextFile opt fname = do
184
  h <- openFile fname ReadMode
185
  case optFileEncoding opt of
186
    Nothing -> return ()
187
    Just enc -> hSetEncoding h enc
188
  TLIO.hGetContents h
189
#else
190
readTextFile opt fname = do
1✔
191
  enc <- case optFileEncoding opt of
1✔
192
         Nothing -> getLocaleEncoding
1✔
193
         Just enc -> return enc
1✔
194
  let f = if CI.mk (takeExtension fname) == ".gz" then GZip.decompress else id
1✔
195
  s <- BL.readFile fname
1✔
196
  return $ decode enc $ f s
1✔
197
#endif
198

199
-- | Parse a string containing LP file data.
200
parseLPString :: (Stream s, Token s ~ Char, IsString (Tokens s)) => FileOptions -> String -> s -> Either (ParseError s) (Problem Scientific)
201
parseLPString = LPFile.parseString
×
202

203
-- | Parse a string containing MPS file data.
204
parseMPSString :: (Stream s, Token s ~ Char, IsString (Tokens s)) => FileOptions -> String -> s -> Either (ParseError s) (Problem Scientific)
205
parseMPSString = MPSFile.parseString
×
206

207
-- | Generate LP file or MPS file based on file extension.
208
writeFile :: FileOptions -> FilePath -> Problem Scientific -> IO ()
209
writeFile opt fname prob =
1✔
210
  case getExt fname of
1✔
211
    ".lp"  -> writeLPFile opt fname prob
1✔
212
    ".mps" -> writeMPSFile opt fname prob
1✔
213
    ext -> ioError $ userError $ "unknown extension: " ++ ext
×
214

215
getExt :: String -> String
216
getExt fname | (base, ext) <- splitExtension fname =
1✔
217
  case map toLower ext of
1✔
218
#ifdef WITH_ZLIB
219
    ".gz" -> getExt base
1✔
220
#endif
221
    s -> s
1✔
222

223
-- | Generate LP file.
224
writeLPFile :: FileOptions -> FilePath -> Problem Scientific -> IO ()
225
writeLPFile opt fname prob =
1✔
226
  case LPFile.render opt prob of
×
227
    Left err -> ioError $ userError err
×
228
    Right s -> writeTextFile opt fname s
1✔
229

230
-- | Generate MPS file.
231
writeMPSFile :: FileOptions -> FilePath -> Problem Scientific -> IO ()
232
writeMPSFile opt fname prob =
1✔
233
  case MPSFile.render opt prob of
1✔
234
    Left err -> ioError $ userError err
×
235
    Right s -> writeTextFile opt fname s
1✔
236

237
writeTextFile :: FileOptions -> FilePath -> TL.Text -> IO ()
238
writeTextFile opt fname s = do
1✔
239
  let writeSimple = do
1✔
240
        withFile fname WriteMode $ \h -> do
1✔
241
          case optFileEncoding opt of
1✔
242
            Nothing -> return ()
×
243
            Just enc -> hSetEncoding h enc
1✔
244
          TLIO.hPutStr h s
1✔
245
#ifdef WITH_ZLIB
246
  if CI.mk (takeExtension fname) /= ".gz" then do
1✔
247
    writeSimple
1✔
248
  else do
1✔
249
    enc <- case optFileEncoding opt of
1✔
250
             Nothing -> getLocaleEncoding
×
251
             Just enc -> return enc
1✔
252
    BL.writeFile fname $ GZip.compress $ encode enc s
1✔
253
#else
254
  writeSimple
255
#endif
256

257
-- | Generate a 'TL.Text' containing LP file data.
258
toLPString :: FileOptions -> Problem Scientific -> Either String TL.Text
259
toLPString = LPFile.render
×
260

261
-- | Generate a 'TL.Text' containing MPS file data.
262
toMPSString :: FileOptions -> Problem Scientific -> Either String TL.Text
263
toMPSString = MPSFile.render
×
264

265
-- $IO
266
-- If this library is built with @WithZlib@ flag (enabled by default), 
267
-- reading/writing gzipped file (@.gz@) are also supported.
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc