minizinc-process-0.1.4.0: src/Process/Minizinc/Inspect.hs
{-# LANGUAGE OverloadedStrings #-}
-- | Provides primitives for inspecting the interface of a model.
module Process.Minizinc.Inspect
( inspect,
TypeInfo (..),
TypeDeclarations,
Method (..),
Interface (..),
)
where
import Control.Applicative ((<|>))
import Data.Aeson
import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Lazy as LByteString
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.List as List
import System.Process.ByteString (readProcessWithExitCode)
-- | Name of variables.
type Name = Text
-- | Information regarding one name.
data TypeInfo
= TypeInfo
{ _type :: Text,
_set :: Bool,
_dim :: Maybe Int
}
deriving (Eq, Ord, Show)
instance FromJSON TypeInfo where
parseJSON = withObject "TypeInfo" $ \v ->
TypeInfo
<$> v .: "type"
<*> v .:? "set" .!= False
<*> v .:? "dim"
-- | Type declarations of the minizinc model.
type TypeDeclarations = Map Name TypeInfo
haskellify :: TypeDeclarations -> Maybe Text
haskellify typedecls =
fmap Text.unlines $ sequence $ fmap property $ pairs
where
pairs :: [(Name, TypeInfo)]
pairs = List.sort $ Map.assocs typedecls
property :: (Name, TypeInfo) -> Maybe Text
property (name, TypeInfo "int" False Nothing) = Just $ mconcat [ name, "::", "Int" ]
property (name, TypeInfo "float" False Nothing) = Just $ mconcat [ name, "::", "Float" ]
property (name, TypeInfo "bool" False Nothing) = Just $ mconcat [ name, "::", "Bool" ]
property (name, TypeInfo "int" False (Just n)) = Just $ mconcat [ name, "::", wrapAry n "Int" ]
property (name, TypeInfo "float" False (Just n)) = Just $ mconcat [ name, "::", wrapAry n "Float" ]
property (name, TypeInfo "bool" False (Just n)) = Just $ mconcat [ name, "::", wrapAry n "Bool" ]
property _ = Nothing
wrapAry :: Int -> Text -> Text
wrapAry n str =
let lparens = Text.replicate n "["
rparens = Text.replicate n "]"
in lparens <> str <> rparens
-- | Optimization method.
data Method = Minimize | Maximize | Satisfy
deriving (Show)
instance FromJSON Method where
parseJSON = withText "Method" $ \s -> case s of
"max" -> pure Maximize
"min" -> pure Minimize
"sat" -> pure Satisfy
v -> fail $ "unsupported method: " ++ Text.unpack v
-- | A description of the model input/output.
data Interface
= Interface
{ _method :: Method,
_has_output_item :: Bool,
_input :: TypeDeclarations,
_output :: TypeDeclarations
}
deriving (Show)
instance FromJSON Interface where
parseJSON = withObject "Interface" $ \v ->
Interface
<$> v .: "method"
<*> (v .: "has_output_item" <|> v.: "has_outputItem")
<*> v .: "input"
<*> v .: "output"
-- | Calls the minizinc binary to output the model interface.
inspect :: FilePath -> IO (Maybe Interface)
inspect path = do
(_, out, err) <- readProcessWithExitCode "minizinc" args ""
seq (ByteString.length err) $ pure $ decode $ LByteString.fromStrict out
where
args = ["-c", "--model-interface-only", path]