{-# OPTIONS_GHC -Wall #-}
{-# OPTIONS_HADDOCK show-extensions #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
module Numeric.Optimization.MIP.Solution.CPLEX
( Solution (..)
, parse
, readFile
) where
import Prelude hiding (readFile)
import Data.Default.Class
import Data.IntMap (IntMap)
import qualified Data.IntMap as IntMap
import qualified Data.Map as Map
import Data.Maybe
import Data.Scientific (Scientific)
import Data.String
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import qualified Text.XML as XML
import Text.XML.Cursor
import Numeric.Optimization.MIP (Solution)
import qualified Numeric.Optimization.MIP.Base as MIP
parseDoc :: XML.Document -> MIP.Solution Scientific
parseDoc :: Document -> Solution Scientific
parseDoc Document
doc =
MIP.Solution
{ solStatus :: Status
MIP.solStatus = Status
status
, solObjectiveValue :: Maybe Scientific
MIP.solObjectiveValue = Maybe Scientific
obj
, solVariables :: Map Var Scientific
MIP.solVariables = [(Var, Scientific)] -> Map Var Scientific
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [(Var, Scientific)]
vs
}
where
obj :: Maybe Scientific
obj :: Maybe Scientific
obj = [Scientific] -> Maybe Scientific
forall a. [a] -> Maybe a
listToMaybe
([Scientific] -> Maybe Scientific)
-> [Scientific] -> Maybe Scientific
forall a b. (a -> b) -> a -> b
$ Document -> Cursor
fromDocument Document
doc
Cursor -> (Cursor -> [Scientific]) -> [Scientific]
forall node a. Cursor node -> (Cursor node -> a) -> a
$| Name -> Axis
element Name
"CPLEXSolution"
Axis -> (Cursor -> [Scientific]) -> Cursor -> [Scientific]
forall node a.
Axis node -> (Cursor node -> [a]) -> Cursor node -> [a]
&/ Name -> Axis
element Name
"header"
Axis -> (Cursor -> [Scientific]) -> Cursor -> [Scientific]
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> Name -> Cursor -> [Text]
attribute Name
"objectiveValue"
(Cursor -> [Text])
-> (Text -> Scientific) -> Cursor -> [Scientific]
forall node a b.
(Cursor node -> [a]) -> (a -> b) -> Cursor node -> [b]
&| (FilePath -> Scientific
forall a. Read a => FilePath -> a
read (FilePath -> Scientific)
-> (Text -> FilePath) -> Text -> Scientific
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> FilePath
T.unpack)
status :: MIP.Status
status :: Status
status = [Status] -> Status
forall a. HasCallStack => [a] -> a
head
([Status] -> Status) -> [Status] -> Status
forall a b. (a -> b) -> a -> b
$ Document -> Cursor
fromDocument Document
doc
Cursor -> (Cursor -> [Status]) -> [Status]
forall node a. Cursor node -> (Cursor node -> a) -> a
$| Name -> Axis
element Name
"CPLEXSolution"
Axis -> (Cursor -> [Status]) -> Cursor -> [Status]
forall node a.
Axis node -> (Cursor node -> [a]) -> Cursor node -> [a]
&/ Name -> Axis
element Name
"header"
Axis -> (Cursor -> [Status]) -> Cursor -> [Status]
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> Name -> Cursor -> [Text]
attribute Name
"solutionStatusValue"
(Cursor -> [Text]) -> (Text -> Status) -> Cursor -> [Status]
forall node a b.
(Cursor node -> [a]) -> (a -> b) -> Cursor node -> [b]
&| ((Key -> IntMap Status -> Status) -> IntMap Status -> Key -> Status
forall a b c. (a -> b -> c) -> b -> a -> c
flip (Status -> Key -> IntMap Status -> Status
forall a. a -> Key -> IntMap a -> a
IntMap.findWithDefault Status
MIP.StatusUnknown) IntMap Status
table (Key -> Status) -> (Text -> Key) -> Text -> Status
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> Key
forall a. Read a => FilePath -> a
read (FilePath -> Key) -> (Text -> FilePath) -> Text -> Key
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> FilePath
T.unpack)
f :: Cursor -> [(MIP.Var, Scientific)]
f :: Cursor -> [(Var, Scientific)]
f Cursor
x
| XML.NodeElement Element
e <- Cursor -> Node
forall node. Cursor node -> node
node Cursor
x = Maybe (Var, Scientific) -> [(Var, Scientific)]
forall a. Maybe a -> [a]
maybeToList (Maybe (Var, Scientific) -> [(Var, Scientific)])
-> Maybe (Var, Scientific) -> [(Var, Scientific)]
forall a b. (a -> b) -> a -> b
$ do
let m :: Map Name Text
m = Element -> Map Name Text
XML.elementAttributes Element
e
Text
name <- Name -> Map Name Text -> Maybe Text
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Name
"name" Map Name Text
m
Scientific
value <- FilePath -> Scientific
forall a. Read a => FilePath -> a
read (FilePath -> Scientific)
-> (Text -> FilePath) -> Text -> Scientific
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> FilePath
T.unpack (Text -> Scientific) -> Maybe Text -> Maybe Scientific
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Name -> Map Name Text -> Maybe Text
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Name
"value" Map Name Text
m
(Var, Scientific) -> Maybe (Var, Scientific)
forall a. a -> Maybe a
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> Var
MIP.Var Text
name, Scientific
value)
| Bool
otherwise = []
vs :: [(Var, Scientific)]
vs = Document -> Cursor
fromDocument Document
doc
Cursor -> (Cursor -> [(Var, Scientific)]) -> [(Var, Scientific)]
forall node a. Cursor node -> (Cursor node -> a) -> a
$| Name -> Axis
element Name
"CPLEXSolution"
Axis
-> (Cursor -> [(Var, Scientific)]) -> Cursor -> [(Var, Scientific)]
forall node a.
Axis node -> (Cursor node -> [a]) -> Cursor node -> [a]
&/ Name -> Axis
element Name
"variables"
Axis
-> (Cursor -> [(Var, Scientific)]) -> Cursor -> [(Var, Scientific)]
forall node a.
Axis node -> (Cursor node -> [a]) -> Cursor node -> [a]
&/ Name -> Axis
element Name
"variable"
Axis
-> (Cursor -> [(Var, Scientific)]) -> Cursor -> [(Var, Scientific)]
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> Cursor -> [(Var, Scientific)]
f
table :: IntMap MIP.Status
table :: IntMap Status
table = [(Key, Status)] -> IntMap Status
forall a. [(Key, a)] -> IntMap a
IntMap.fromList
[ (Key
1, Status
MIP.StatusOptimal)
, (Key
2, Status
MIP.StatusUnbounded)
, (Key
3, Status
MIP.StatusInfeasible)
, (Key
4, Status
MIP.StatusInfeasibleOrUnbounded)
, (Key
5, Status
MIP.StatusOptimal)
, (Key
24, Status
MIP.StatusFeasible)
, (Key
40, Status
MIP.StatusInfeasibleOrUnbounded)
, (Key
101, Status
MIP.StatusOptimal)
, (Key
102, Status
MIP.StatusOptimal)
, (Key
103, Status
MIP.StatusInfeasible)
, (Key
105, Status
MIP.StatusFeasible)
, (Key
107, Status
MIP.StatusFeasible)
, (Key
109, Status
MIP.StatusFeasible)
, (Key
111, Status
MIP.StatusFeasible)
, (Key
113, Status
MIP.StatusFeasible)
, (Key
115, Status
MIP.StatusOptimal)
, (Key
116, Status
MIP.StatusFeasible)
, (Key
118, Status
MIP.StatusUnbounded)
, (Key
119, Status
MIP.StatusInfeasibleOrUnbounded)
, (Key
127, Status
MIP.StatusFeasible)
, (Key
129, Status
MIP.StatusOptimal)
, (Key
130, Status
MIP.StatusOptimal)
, (Key
131, Status
MIP.StatusFeasible)
, (Key
133, Status
MIP.StatusInfeasibleOrUnbounded)
]
parse :: TL.Text -> MIP.Solution Scientific
parse :: Text -> Solution Scientific
parse Text
t = Document -> Solution Scientific
parseDoc (Document -> Solution Scientific)
-> Document -> Solution Scientific
forall a b. (a -> b) -> a -> b
$ ParseSettings -> Text -> Document
XML.parseText_ ParseSettings
forall a. Default a => a
def Text
t
readFile :: FilePath -> IO (MIP.Solution Scientific)
readFile :: FilePath -> IO (Solution Scientific)
readFile FilePath
fname = Document -> Solution Scientific
parseDoc (Document -> Solution Scientific)
-> IO Document -> IO (Solution Scientific)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParseSettings -> FilePath -> IO Document
XML.readFile ParseSettings
forall a. Default a => a
def (FilePath -> FilePath
forall a. IsString a => FilePath -> a
fromString FilePath
fname)