{-# OPTIONS_GHC -Wall #-}
{-# OPTIONS_HADDOCK show-extensions #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
module Numeric.Optimization.MIP.Solution.CPLEX
( Solution (..)
, parse
, readFile
) where
import Prelude hiding (readFile)
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative
#endif
import Data.Default.Class
import Data.Interned
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 =
Solution :: forall r. Status -> Maybe r -> Map Var r -> Solution r
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]
&| (String -> Scientific
forall a. Read a => String -> a
read (String -> Scientific) -> (Text -> String) -> Text -> Scientific
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
T.unpack)
status :: MIP.Status
status :: Status
status = [Status] -> Status
forall a. [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
. String -> Key
forall a. Read a => String -> a
read (String -> Key) -> (Text -> String) -> Text -> Key
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
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 <- String -> Scientific
forall a. Read a => String -> a
read (String -> Scientific) -> (Text -> String) -> Text -> Scientific
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
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 (m :: * -> *) a. Monad m => a -> m a
return (Uninterned Var -> Var
forall t. Interned t => Uninterned t -> t
intern Text
Uninterned Var
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 :: String -> IO (Solution Scientific)
readFile String
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 -> String -> IO Document
XML.readFile ParseSettings
forall a. Default a => a
def (String -> String
forall a. IsString a => String -> a
fromString String
fname)