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

msakai / haskell-MIP / 222

22 Jan 2025 12:52AM UTC coverage: 76.28%. Remained the same
222

push

github

web-flow
Merge pull request #48 from msakai/improve-doc

Add some haddock

1460 of 1914 relevant lines covered (76.28%)

0.76 hits per line

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

55.37
/MIP/src/Numeric/Optimization/MIP/Base.hs
1
{-# OPTIONS_GHC -Wall #-}
2
{-# OPTIONS_HADDOCK show-extensions #-}
3
{-# LANGUAGE CPP #-}
4
{-# LANGUAGE FlexibleInstances #-}
5
{-# LANGUAGE MultiParamTypeClasses #-}
6
{-# LANGUAGE PatternSynonyms #-}
7
{-# LANGUAGE TypeFamilies #-}
8
{-# LANGUAGE ViewPatterns #-}
9
-----------------------------------------------------------------------------
10
-- |
11
-- Module      :  Numeric.Optimization.MIP.Base
12
-- Copyright   :  (c) Masahiro Sakai 2011-2019
13
-- License     :  BSD-style
14
--
15
-- Maintainer  :  masahiro.sakai@gmail.com
16
-- Stability   :  provisional
17
-- Portability :  non-portable
18
--
19
-- Mixed-Integer Programming Problems with some commmonly used extensions
20
--
21
-----------------------------------------------------------------------------
22
module Numeric.Optimization.MIP.Base
23
  (
24
  -- * The MIP Problem type
25
    Problem (..)
26
  , Label
27

28
  -- * Variables
29
  , Var (Var)
30
  , varName
31
  , toVar
32
  , fromVar
33

34
  -- ** Variable types
35
  , VarType (..)
36
  , getVarType
37

38
  -- ** Variable bounds
39
  , BoundExpr
40
  , Extended (..)
41
  , Bounds
42
  , defaultBounds
43
  , defaultLB
44
  , defaultUB
45
  , getBounds
46

47
  -- ** Variable getters
48
  , variables
49
  , integerVariables
50
  , semiContinuousVariables
51
  , semiIntegerVariables
52

53
  -- * Expressions
54
  , Expr (Expr)
55
  , varExpr
56
  , constExpr
57
  , terms
58
  , Term (..)
59

60
  -- * Objective function
61
  , OptDir (..)
62
  , ObjectiveFunction (..)
63

64
  -- * Constraints
65

66
  -- ** Linear (or Quadratic or Polynomial) constraints
67
  , Constraint (..)
68
  , (.==.)
69
  , (.<=.)
70
  , (.>=.)
71
  , RelOp (..)
72

73
  -- ** SOS constraints
74
  , SOSType (..)
75
  , SOSConstraint (..)
76

77
  -- * Solutions
78
  , Solution (..)
79
  , Status (..)
80
  , meetStatus
81

82
  -- * Evaluation
83
  , Tol (..)
84
  , zeroTol
85
  , Eval (..)
86

87
  -- * File I/O options
88
  , FileOptions (..)
89
  , WriteSetting (..)
90

91
  -- * Utilities
92
  , Default (..)
93
  , Variables (..)
94
  , intersectBounds
95
  ) where
96

97
#if !MIN_VERSION_lattices(2,0,0)
98
import Algebra.Lattice
99
#endif
100
import Algebra.PartialOrd
101
import Control.Arrow ((***))
102
import Control.Monad
103
import Data.Default.Class
104
import Data.Foldable (toList)
105
import Data.Hashable
106
import Data.List (sortBy)
107
import Data.Map (Map)
108
import qualified Data.Map as Map
109
import Data.Ord (comparing)
110
import Data.Sequence (Seq)
111
import qualified Data.Sequence as Seq
112
import Data.Set (Set)
113
import qualified Data.Set as Set
114
import Data.Interned (intern, unintern)
115
import Data.Interned.Text
116
import Data.ExtendedReal
117
import Data.OptDir
118
import Data.String
119
import qualified Data.Text as T
120
import System.IO (TextEncoding)
121

122
infix 4 .<=., .>=., .==.
123

124
-- ---------------------------------------------------------------------------
125

126
-- | A problem instance
127
data Problem c
128
  = Problem
129
  { name :: Maybe T.Text
1✔
130
    -- ^ Problem name
131
  , objectiveFunction :: ObjectiveFunction c
1✔
132
    -- ^ Objective functions of the problem
133
  , constraints :: [Constraint c]
1✔
134
    -- ^ Constraints of the problem
135
    --
136
    -- Indicator constraints and lazy constraints are included in this list.
137
  , sosConstraints :: [SOSConstraint c]
1✔
138
    -- ^ Special ordered sets
139
  , userCuts :: [Constraint c]
1✔
140
    -- ^ User cuts
141
  , varType :: Map Var VarType
1✔
142
    -- ^ Types of variables
143
  , varBounds :: Map Var (Bounds c)
1✔
144
    -- ^ Bounds of variables
145
  }
146
  deriving (Show, Eq, Ord)
×
147

148
instance Default (Problem c) where
149
  def = Problem
1✔
150
        { name = Nothing
×
151
        , objectiveFunction = def
1✔
152
        , constraints = []
1✔
153
        , sosConstraints = []
1✔
154
        , userCuts = []
×
155
        , varType = Map.empty
×
156
        , varBounds = Map.empty
×
157
        }
158

159
instance Functor Problem where
×
160
  fmap f prob =
×
161
    prob
×
162
    { objectiveFunction = fmap f (objectiveFunction prob)
×
163
    , constraints       = map (fmap f) (constraints prob)
×
164
    , sosConstraints    = map (fmap f) (sosConstraints prob)
×
165
    , userCuts          = map (fmap f) (userCuts prob)
×
166
    , varBounds         = fmap (fmap f *** fmap f) (varBounds prob)
×
167
    }
168

169
-- | Label used for naming various elements of t'Problem'
170
type Label = T.Text
171

172
-- ---------------------------------------------------------------------------
173

174
-- | variables
175
newtype Var = Var' InternedText
176
  deriving Eq
1✔
177

178
pattern Var :: T.Text -> Var
179
pattern Var s <- Var' (unintern -> s) where
1✔
180
  Var s = Var' (intern s)
1✔
181

182
{-# COMPLETE Var #-}
183

184
instance IsString Var where
185
  fromString = Var' . fromString
1✔
186

187
instance Ord Var where
×
188
  compare (Var' a) (Var' b)
1✔
189
    | a == b = EQ
1✔
190
    | otherwise = compare (unintern a) (unintern b)
×
191

192
instance Show Var where
×
193
  showsPrec d (Var x) = showsPrec d x
×
194

195
instance Hashable Var where
×
196
#if MIN_VERSION_intern(0,9,3)
197
  hashWithSalt salt (Var' x) = hashWithSalt salt x
×
198
#else
199
  hashWithSalt salt (Var' x) = hashWithSalt salt (internedTextId x)
200
#endif
201

202
-- | Variable's name
203
varName :: Var -> T.Text
204
varName (Var s) = s
1✔
205

206
{-# DEPRECATED toVar "Use fromString function or Var pattern instead" #-}
207
-- | convert a string into a variable
208
toVar :: String -> Var
209
toVar = fromString
×
210

211
{-# DEPRECATED fromVar "Use varName function or Var pattern instead" #-}
212
-- | convert a variable into a string
213
fromVar :: Var -> String
214
fromVar (Var s) = T.unpack s
×
215

216
-- | Type of variables
217
--
218
-- Variables can take values depending on their types and their bounds ('Bounds').
219
data VarType
220
  = ContinuousVariable     -- ^ can take values from \(\{x \in \mathbb{R} \mid L \le x \le U\}\)
221
  | IntegerVariable        -- ^ can take values from \(\{x \in \mathbb{Z} \mid L \le x \le U\}\)
222
  | SemiContinuousVariable -- ^ can take values from \(\{0\} \cup \{x \in \mathbb{R} \mid L \le x \le U\}\)
223
  | SemiIntegerVariable    -- ^ can take values from \(\{0\} \cup \{x \in \mathbb{Z} \mid L \le x \le U\}\)
224
  deriving (Eq, Ord, Show)
×
225

226
instance Default VarType where
227
  def = ContinuousVariable
×
228

229
-- | looking up bounds for a variable
230
getVarType :: Problem c -> Var -> VarType
231
getVarType mip v = Map.findWithDefault def v (varType mip)
×
232

233
-- | type for representing lower/upper bound of variables
234
type BoundExpr c = Extended c
235

236
-- | type for representing lower/upper bound of variables
237
type Bounds c = (BoundExpr c, BoundExpr c)
238

239
-- | default bounds
240
defaultBounds :: Num c => Bounds c
241
defaultBounds = (defaultLB, defaultUB)
1✔
242

243
-- | default lower bound (0)
244
defaultLB :: Num c => BoundExpr c
245
defaultLB = Finite 0
1✔
246

247
-- | default upper bound (+∞)
248
defaultUB :: BoundExpr c
249
defaultUB = PosInf
1✔
250

251
-- | looking up bounds for a variable
252
getBounds :: Num c => Problem c -> Var -> Bounds c
253
getBounds mip v = Map.findWithDefault defaultBounds v (varBounds mip)
×
254

255
-- | Intersection of two 'Bounds'
256
intersectBounds :: Ord c => Bounds c -> Bounds c -> Bounds c
257
intersectBounds (lb1,ub1) (lb2,ub2) = (max lb1 lb2, min ub1 ub2)
×
258

259
-- ---------------------------------------------------------------------------
260

261
-- | Arithmetic expressions
262
--
263
-- Essentialy an expression is a sequence of t'Term's.
264
newtype Expr c = Expr' (Seq (Term c))
265
  deriving (Eq, Ord)
×
266

267
pattern Expr :: [Term c] -> Expr c
268
pattern Expr ts <- Expr' (toList -> ts) where
1✔
269
  Expr ts = Expr' (Seq.fromList ts)
1✔
270

271
{-# COMPLETE Expr #-}
272

273
instance Show c => Show (Expr c) where
×
274
  showsPrec d (Expr ts) = showParen (d > app_prec) $
×
275
    showString "Expr " . showsPrec (app_prec+1) ts
×
276
    where
277
      app_prec = 10
×
278

279
-- | Variable expression
280
varExpr :: Num c => Var -> Expr c
281
varExpr v = Expr' $ Seq.singleton $ Term 1 [v]
1✔
282

283
-- | Constant expression
284
constExpr :: (Eq c, Num c) => c -> Expr c
285
constExpr 0 = Expr' Seq.empty
1✔
286
constExpr c = Expr' $ Seq.singleton $ Term c []
1✔
287

288
-- | Terms of an expression
289
terms :: Expr c -> [Term c]
290
terms (Expr ts) = ts
1✔
291

292
instance Num c => Num (Expr c) where
1✔
293
  Expr' e1 + Expr' e2 = Expr' (e1 <> e2)
1✔
294
  Expr e1 * Expr e2 = Expr [Term (c1*c2) (vs1 ++ vs2) | Term c1 vs1 <- e1, Term c2 vs2 <- e2]
1✔
295
  negate (Expr' e) = Expr' $ fmap (\(Term c vs) -> Term (-c) vs) e
1✔
296
  abs = id
×
297
  signum _ = 1
×
298
  fromInteger 0 = Expr []
1✔
299
  fromInteger c = Expr [Term (fromInteger c) []]
1✔
300

301
instance Functor Expr where
×
302
  fmap f (Expr' ts) = Expr' $ fmap (fmap f) ts
×
303

304
-- | Split an expression into an expression without constant term and a constant
305
splitConst :: Num c => Expr c -> (Expr c, c)
306
splitConst (Expr' ts) = (e2, c2)
1✔
307
  where
308
    p (Term _ (_:_)) = True
1✔
309
    p _ = False
×
310
    e2 = Expr' $ Seq.filter p ts
1✔
311
    c2 = sum [c | Term c [] <- toList ts]
×
312

313
-- | terms
314
data Term c = Term c [Var]
315
  deriving (Eq, Ord, Show)
×
316

317
instance Functor Term where
×
318
  fmap f (Term c vs) = Term (f c) vs
×
319

320
-- ---------------------------------------------------------------------------
321

322
-- | objective function
323
data ObjectiveFunction c
324
  = ObjectiveFunction
325
  { objLabel :: Maybe Label
1✔
326
  , objDir :: OptDir
1✔
327
  , objExpr :: Expr c
1✔
328
  }
329
  deriving (Eq, Ord, Show)
×
330

331
instance Default (ObjectiveFunction c) where
332
  def =
1✔
333
    ObjectiveFunction
1✔
334
    { objLabel = Nothing
×
335
    , objDir = OptMin
×
336
    , objExpr = Expr []
1✔
337
    }
338

339
instance Functor ObjectiveFunction where
×
340
  fmap f obj = obj{ objExpr = fmap f (objExpr obj) }
×
341

342
-- ---------------------------------------------------------------------------
343

344
-- | Constraint
345
--
346
-- In the most general case, of the form @x = v → L ≤ e ≤ U@.
347
data Constraint c
348
  = Constraint
349
  { constrLabel     :: Maybe Label
1✔
350
    -- ^ name of the constraint
351
  , constrIndicator :: Maybe (Var, c)
1✔
352
    -- ^ @x = v@ (v is 0 or 1)
353
  , constrExpr      :: Expr c
1✔
354
    -- ^ @e@
355
  , constrLB        :: BoundExpr c
1✔
356
    -- ^ @L@
357
  , constrUB        :: BoundExpr c
1✔
358
    -- ^ @U@
359
  , constrIsLazy    :: Bool
1✔
360
  }
361
  deriving (Eq, Ord, Show)
×
362

363
-- | Equality constraint.
364
(.==.) :: Num c => Expr c -> Expr c -> Constraint c
365
lhs .==. rhs =
×
366
  case splitConst (lhs - rhs) of
×
367
    (e, c) -> def{ constrExpr = e, constrLB = Finite (- c), constrUB = Finite (- c) }
×
368

369
-- | Inequality constraint (≤).
370
(.<=.) :: Num c => Expr c -> Expr c -> Constraint c
371
lhs .<=. rhs =
1✔
372
  case splitConst (lhs - rhs) of
1✔
373
    (e, c) -> def{ constrExpr = e, constrUB = Finite (- c) }
1✔
374

375
-- | Inequality constraint (≥).
376
(.>=.) :: Num c => Expr c -> Expr c -> Constraint c
377
lhs .>=. rhs =
×
378
  case splitConst (lhs - rhs) of
×
379
    (e, c) -> def{ constrExpr = e, constrLB = Finite (- c) }
×
380

381
instance Default (Constraint c) where
382
  def = Constraint
1✔
383
        { constrLabel = Nothing
×
384
        , constrIndicator = Nothing
1✔
385
        , constrExpr = Expr []
×
386
        , constrLB = NegInf
1✔
387
        , constrUB = PosInf
×
388
        , constrIsLazy = False
×
389
        }
390

391
instance Functor Constraint where
×
392
  fmap f c =
×
393
    c
×
394
    { constrIndicator = fmap (id *** f) (constrIndicator c)
×
395
    , constrExpr = fmap f (constrExpr c)
×
396
    , constrLB = fmap f (constrLB c)
×
397
    , constrUB = fmap f (constrUB c)
×
398
    }
399

400
-- | relational operators
401
data RelOp
402
  = Le  -- ^ (≤)
403
  | Ge  -- ^ (≥)
404
  | Eql -- ^ (=)
405
  deriving (Eq, Ord, Enum, Show)
×
406

407
-- ---------------------------------------------------------------------------
408

409
-- | types of SOS (special ordered sets) constraints
410
data SOSType
411
  = S1 -- ^ Type 1 SOS constraint
412
  | S2 -- ^ Type 2 SOS constraint
413
  deriving (Eq, Ord, Enum, Show, Read)
×
414

415
-- | SOS (special ordered sets) constraints
416
data SOSConstraint c
417
  = SOSConstraint
418
  { sosLabel :: Maybe Label
1✔
419
  , sosType  :: SOSType
1✔
420
  , sosBody  :: [(Var, c)]
1✔
421
  }
422
  deriving (Eq, Ord, Show)
×
423

424
instance Functor SOSConstraint where
×
425
  fmap f c = c{ sosBody = map (id *** f) (sosBody c) }
×
426

427
-- ---------------------------------------------------------------------------
428

429
-- | MIP status with the following partial order:
430
--
431
-- <<doc-images/MIP-Status-diagram.png>>
432
data Status
433
  = StatusUnknown
434
  | StatusFeasible
435
  | StatusOptimal
436
  | StatusInfeasibleOrUnbounded
437
  | StatusInfeasible
438
  | StatusUnbounded
439
  deriving (Eq, Ord, Enum, Bounded, Show)
×
440

441
instance PartialOrd Status where
×
442
  leq a b = (a,b) `Set.member` rel
1✔
443
    where
444
      rel = unsafeLfpFrom rel0 $ \r ->
1✔
445
        Set.union r (Set.fromList [(x,z) | (x,y) <- Set.toList r, (y',z) <- Set.toList r, y == y'])
1✔
446
      rel0 = Set.fromList $
1✔
447
        [(x,x) | x <- [minBound .. maxBound]] ++
1✔
448
        [ (StatusUnknown, StatusFeasible)
1✔
449
        , (StatusUnknown, StatusInfeasibleOrUnbounded)
1✔
450
        , (StatusFeasible, StatusOptimal)
1✔
451
        , (StatusFeasible, StatusUnbounded)
1✔
452
        , (StatusInfeasibleOrUnbounded, StatusUnbounded)
1✔
453
        , (StatusInfeasibleOrUnbounded, StatusInfeasible)
1✔
454
        ]
455

456
-- | /meet/ (greatest lower bound) operator of the partial order of 'Status' type.
457
--
458
-- If the version of @lattices@ is \<2, then @MeetSemiLattice@ instance can also be used.
459
meetStatus :: Status -> Status -> Status
460
StatusUnknown `meetStatus` _b = StatusUnknown
1✔
461
StatusFeasible `meetStatus` b
462
  | StatusFeasible `leq` b = StatusFeasible
1✔
463
  | otherwise = StatusUnknown
×
464
StatusOptimal `meetStatus` StatusOptimal = StatusOptimal
1✔
465
StatusOptimal `meetStatus` b
466
  | StatusFeasible `leq` b = StatusFeasible
1✔
467
  | otherwise = StatusUnknown
×
468
StatusInfeasibleOrUnbounded `meetStatus` b
469
  | StatusInfeasibleOrUnbounded `leq` b = StatusInfeasibleOrUnbounded
1✔
470
  | otherwise = StatusUnknown
×
471
StatusInfeasible `meetStatus` StatusInfeasible = StatusInfeasible
1✔
472
StatusInfeasible `meetStatus` b
473
  | StatusInfeasibleOrUnbounded `leq` b = StatusInfeasibleOrUnbounded
1✔
474
  | otherwise = StatusUnknown
×
475
StatusUnbounded `meetStatus` StatusUnbounded = StatusUnbounded
1✔
476
StatusUnbounded `meetStatus` b
477
  | StatusFeasible `leq` b = StatusFeasible
1✔
478
  | StatusInfeasibleOrUnbounded `leq` b = StatusInfeasibleOrUnbounded
1✔
479
  | otherwise = StatusUnknown
×
480

481
#if !MIN_VERSION_lattices(2,0,0)
482

483
instance MeetSemiLattice Status where
484
  meet = meetStatus
485

486
#endif
487

488

489
-- | Type for representing a solution of MIP problem.
490
data Solution r
491
  = Solution
492
  { solStatus :: Status
1✔
493
    -- ^ status
494
  , solObjectiveValue :: Maybe r
1✔
495
    -- ^ value of the objective function
496
  , solVariables :: Map Var r
1✔
497
    -- ^ variable assignments
498
  }
499
  deriving (Eq, Ord, Show)
×
500

501
instance Functor Solution where
×
502
  fmap f (Solution status obj vs) = Solution status (fmap f obj) (fmap f vs)
1✔
503

504
instance Default (Solution r) where
505
  def = Solution
1✔
506
        { solStatus = StatusUnknown
×
507
        , solObjectiveValue = Nothing
×
508
        , solVariables = Map.empty
×
509
        }
510

511
-- ---------------------------------------------------------------------------
512

513
-- | Tolerance for evaluating solutions against t'Problem'.
514
data Tol r
515
  = Tol
516
  { integralityTol :: r
1✔
517
    -- ^ If a value of integer variable is within this amount from its nearest
518
    -- integer, it is considered feasible.
519
  , feasibilityTol :: r
1✔
520
    -- ^ If the amount of violation of constraints is within this amount, it is
521
    -- considered feasible.
522
  , optimalityTol :: r
×
523
    -- ^ Feasiblity tolerance of dual constraints.
524
  }
525

526
-- | Defautl is @1e-6@ for the feasibility and optimality tolerances, and @1e-5@ for the integrality tolerance.
527
instance Fractional r => Default (Tol r) where
528
  def =
1✔
529
    Tol
1✔
530
    { integralityTol = 1e-5
1✔
531
    , feasibilityTol = 1e-6
1✔
532
    , optimalityTol = 1e-6
×
533
    }
534

535
-- | t'Tol' value with all tolerances are zero
536
zeroTol :: Fractional r => Tol r
537
zeroTol =
×
538
  Tol
×
539
  { integralityTol = 1e-5
×
540
  , feasibilityTol = 1e-6
×
541
  , optimalityTol = 1e-6
×
542
  }
543

544
-- | Type class for evaluation various elements of t'Problem' under
545
-- the given variable assignments.
546
class Eval r a where
547
  -- | Result type of 'eval'
548
  type Evaluated r a
549

550
  -- | Evaluate a value of type @a@ under given assignments and the tolerance
551
  eval :: Tol r -> Map Var r -> a -> Evaluated r a
552

553
instance Num r => Eval r Var where
554
  type Evaluated r Var = r
555
  eval _tol sol v =
1✔
556
    case Map.lookup v sol of
1✔
557
      Just val -> val
1✔
558
      Nothing -> 0
×
559

560
instance Num r => Eval r (Term r) where
561
  type Evaluated r (Term r) = r
562
  eval tol sol (Term c vs) = product (c : [eval tol sol v | v <- vs])
×
563

564
instance Num r => Eval r (Expr r) where
565
  type Evaluated r (Expr r) = r
566
  eval tol sol expr = sum [eval tol sol t | t <- terms expr]
×
567

568
instance Num r => Eval r (ObjectiveFunction r) where
569
  type Evaluated r (ObjectiveFunction r) = r
570
  eval tol sol obj = eval tol sol (objExpr obj)
×
571

572
instance (Num r, Ord r) => Eval r (Constraint r) where
573
  type Evaluated r (Constraint r) = Bool
574
  eval tol sol constr =
1✔
575
    not (evalIndicator (constrIndicator constr)) ||
1✔
576
    isInBounds tol (constrLB constr, constrUB constr) (eval tol sol (constrExpr constr))
×
577
    where
578
      evalIndicator Nothing = True
1✔
579
      evalIndicator (Just (v, val')) = isInBounds tol (Finite val', Finite val') (eval tol sol v)
×
580

581
instance (Num r, Ord r) => Eval r (SOSConstraint r) where
582
  type Evaluated r (SOSConstraint r) = Bool
583
  eval tol sol sos =
1✔
584
    case sosType sos of
1✔
585
      S1 -> length [() | val <- body, val] <= 1
×
586
      S2 -> f body
1✔
587
    where
588
      body = map (not . isInBounds tol (0, 0) . eval tol sol . fst) $ sortBy (comparing snd) $ (sosBody sos)
×
589
      f [] = True
×
590
      f [_] = True
1✔
591
      f (x1 : x2 : xs)
592
        | x1 = all not xs
1✔
593
        | otherwise = f (x2 : xs)
×
594

595
instance (RealFrac r) => Eval r (Problem r) where
596
  type Evaluated r (Problem r) = Maybe r
597
  eval tol sol prob = do
1✔
598
    forM_ (Map.toList (Map.intersectionWith (,) (varType prob) (varBounds prob))) $ \(v, (vt, bounds)) -> do
1✔
599
      let val = eval tol sol v
×
600
      case vt of
1✔
601
        ContinuousVariable -> return ()
×
602
        SemiContinuousVariable -> return ()
×
603
        IntegerVariable -> guard $ isIntegral tol val
1✔
604
        SemiIntegerVariable -> guard $ isIntegral tol val
1✔
605
      case vt of
1✔
606
        ContinuousVariable -> guard $ isInBounds tol bounds val
1✔
607
        IntegerVariable -> guard $ isInBounds tol bounds val
1✔
608
        SemiIntegerVariable -> guard $ isInBounds tol (0,0) val || isInBounds tol bounds val
1✔
609
        SemiContinuousVariable -> guard $ isInBounds tol (0,0) val || isInBounds tol bounds val
1✔
610
    forM_ (constraints prob) $ \constr -> do
×
611
      guard $ eval tol sol constr
×
612
    forM_ (sosConstraints prob) $ \constr -> do
×
613
      guard $ eval tol sol constr
×
614
    return $ eval tol sol (objectiveFunction prob)
×
615

616
isIntegral :: RealFrac r => Tol r -> r -> Bool
617
isIntegral tol x = abs (x - fromIntegral (floor (x + 0.5) :: Integer)) <= integralityTol tol
1✔
618

619
isInBounds :: (Num r, Ord r) => Tol r -> Bounds r -> r -> Bool
620
isInBounds tol (lb, ub) x =
1✔
621
  lb - Finite (feasibilityTol tol) <= Finite x &&
1✔
622
  Finite x <= ub + Finite (feasibilityTol tol)
1✔
623

624
-- ---------------------------------------------------------------------------
625

626
-- | Type class for types that contain variables.
627
class Variables a where
628
  vars :: a -> Set Var
629

630
instance Variables a => Variables [a] where
631
  vars = Set.unions . map vars
1✔
632

633
instance (Variables a, Variables b) => Variables (Either a b) where
634
  vars (Left a)  = vars a
1✔
635
  vars (Right b) = vars b
1✔
636

637
instance Variables (Problem c) where
638
  vars = variables
1✔
639

640
instance Variables (Expr c) where
641
  vars (Expr e) = vars e
1✔
642

643
instance Variables (Term c) where
644
  vars (Term _ xs) = Set.fromList xs
1✔
645

646
instance Variables Var where
647
  vars v = Set.singleton v
×
648

649
instance Variables (ObjectiveFunction c) where
650
  vars ObjectiveFunction{ objExpr = e } = vars e
1✔
651

652
instance Variables (Constraint c) where
653
  vars Constraint{ constrIndicator = ind, constrExpr = e } = Set.union (vars e) vs2
1✔
654
    where
655
      vs2 = maybe Set.empty (Set.singleton . fst) ind
1✔
656

657
instance Variables (SOSConstraint c) where
658
  vars SOSConstraint{ sosBody = xs } = Set.fromList (map fst xs)
1✔
659

660
-- ---------------------------------------------------------------------------
661

662
-- | Set of variables of a t'Problem'
663
variables :: Problem c -> Set Var
664
variables mip = Map.keysSet $ varType mip
1✔
665

666
-- | Set of integer variables of a t'Problem'
667
integerVariables :: Problem c -> Set Var
668
integerVariables mip = Map.keysSet $ Map.filter (IntegerVariable ==) (varType mip)
1✔
669

670
-- | Set of semi-continuous variables of a t'Problem'
671
semiContinuousVariables :: Problem c -> Set Var
672
semiContinuousVariables mip = Map.keysSet $ Map.filter (SemiContinuousVariable ==) (varType mip)
1✔
673

674
-- | Set of semi-integer variables of a t'Problem'
675
semiIntegerVariables :: Problem c -> Set Var
676
semiIntegerVariables mip = Map.keysSet $ Map.filter (SemiIntegerVariable ==) (varType mip)
1✔
677

678
-- ---------------------------------------------------------------------------
679

680
-- | Options for reading/writing problem files
681
data FileOptions
682
  = FileOptions
683
  { optFileEncoding :: Maybe TextEncoding
1✔
684
    -- ^ Text encoding used for file input/output
685
  , optMPSWriteObjSense :: WriteSetting
1✔
686
    -- ^ The original MPS file format does not have information about the direction of the objective function.
687
    -- The @OBJSENSE@ section is added as an extention, but not all solvers support it.
688
    -- This option controls whether the @OBJSENSE@ sections are output.
689
  } deriving (Show)
×
690

691
instance Default FileOptions where
692
  def =
1✔
693
    FileOptions
1✔
694
    { optFileEncoding = Nothing
1✔
695
    , optMPSWriteObjSense = WriteIfNotDefault
1✔
696
    }
697

698
-- | Options for writing something of not
699
data WriteSetting
700
  = WriteAlways
701
  | WriteIfNotDefault
702
  | WriteNever
703
  deriving (Eq, Ord, Enum, Bounded, Show, Read)
×
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