{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
module ToySolver.Data.MIP.Solution.CPLEX
( Solution (..)
, parse
, readFile
) where
import Prelude hiding (readFile)
import Control.Applicative
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 ToySolver.Data.MIP (Solution)
import qualified ToySolver.Data.MIP.Base as MIP
parseDoc :: XML.Document -> MIP.Solution Scientific
parseDoc doc =
MIP.Solution
{ MIP.solStatus = status
, MIP.solObjectiveValue = obj
, MIP.solVariables = Map.fromList vs
}
where
obj :: Maybe Scientific
obj = listToMaybe
$ fromDocument doc
$| element "CPLEXSolution"
&/ element "header"
>=> attribute "objectiveValue"
&| (read . T.unpack)
status :: MIP.Status
status = head
$ fromDocument doc
$| element "CPLEXSolution"
&/ element "header"
>=> attribute "solutionStatusValue"
&| (flip (IntMap.findWithDefault MIP.StatusUnknown) table . read . T.unpack)
f :: Cursor -> [(MIP.Var, Scientific)]
f x
| XML.NodeElement e <- node x = maybeToList $ do
let m = XML.elementAttributes e
name <- Map.lookup "name" m
value <- read . T.unpack <$> Map.lookup "value" m
return (intern name, value)
| otherwise = []
vs = fromDocument doc
$| element "CPLEXSolution"
&/ element "variables"
&/ element "variable"
>=> f
table :: IntMap MIP.Status
table = IntMap.fromList
[ (1, MIP.StatusOptimal)
, (2, MIP.StatusUnbounded)
, (3, MIP.StatusInfeasible)
, (4, MIP.StatusInfeasibleOrUnbounded)
, (5, MIP.StatusOptimal)
, (24, MIP.StatusFeasible)
, (40, MIP.StatusInfeasibleOrUnbounded)
, (101, MIP.StatusOptimal)
, (102, MIP.StatusOptimal)
, (103, MIP.StatusInfeasible)
, (105, MIP.StatusFeasible)
, (107, MIP.StatusFeasible)
, (109, MIP.StatusFeasible)
, (111, MIP.StatusFeasible)
, (113, MIP.StatusFeasible)
, (115, MIP.StatusOptimal)
, (116, MIP.StatusFeasible)
, (118, MIP.StatusUnbounded)
, (119, MIP.StatusInfeasibleOrUnbounded)
, (127, MIP.StatusFeasible)
, (129, MIP.StatusOptimal)
, (130, MIP.StatusOptimal)
, (131, MIP.StatusFeasible)
, (133, MIP.StatusInfeasibleOrUnbounded)
]
parse :: TL.Text -> MIP.Solution Scientific
parse t = parseDoc $ XML.parseText_ def t
readFile :: FilePath -> IO (MIP.Solution Scientific)
readFile fname = parseDoc <$> XML.readFile def (fromString fname)