-
Orestis Melkonian authoredOrestis Melkonian authored
Model.hs 2.93 KiB
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeSynonymInstances #-}
module Model where
import Data.List (isSuffixOf)
import qualified Data.Map as M
import Data.String
import GHC.Generics
import Text.Parsec hiding (runP)
import Text.Parsec.Language
import Text.Parsec.String
import qualified Text.Parsec.Token as Tokens
import LogicIR.ParserUtils
-- | Response type.
data Response = Equivalent | NotEquivalent Model | ErrorResponse String | Undefined | Timeout
deriving (Eq)
(<>) :: Response -> Response -> Response
ErrorResponse e <> _ = ErrorResponse e
_ <> ErrorResponse e = ErrorResponse e
Equivalent <> r = r
NotEquivalent s <> _ = NotEquivalent s
Timeout <> _ = Timeout
Undefined <> _ = Undefined
instance Show Response where
show Equivalent = "Formulas are equivalent"
show (NotEquivalent model) = "Not equivalent: " ++ show model
show (ErrorResponse e) = "*** Error: " ++ show e
show Undefined = "Oops... could not determine if formulas are equivalent"
show Timeout = "Timeout occured"
-- | Model type.
data ModelVal = BoolVal Bool
| IntVal Integer
| RealVal Double
| ManyVal [ModelVal]
deriving (Eq, Generic)
type Model = M.Map String ModelVal
emptyModel :: Model
emptyModel = M.empty
-- | Pretty-printing.
instance Show ModelVal where
show (BoolVal b) = show b
show (IntVal i) = show i
show (RealVal i) = show i
show (ManyVal vs) = show vs
-- | Crop arrays until their specified length.
sanitize :: Model -> Model
sanitize model =
M.filterWithKey isNotLen $ M.filterWithKey isNotNull $ M.mapWithKey f model
where f k (ManyVal array) = ManyVal $ take (counts k) array
f _ x = x
counts k = fromInteger $
case model M.! (k ++ "?length") of
(IntVal i) -> i
_ -> error "non-int length"
isNotNull k _ =
((k ++ "?null") `M.notMember` model) ||
case model M.! (k ++ "?null") of
(BoolVal b) -> not b
_ -> error "non-bool null"
isNotLen k _ = not $ "?length" `isSuffixOf` k
-- | Parsers.
modelP :: Parser ModelVal
modelP = try (BoolVal <$> boolP)
<|> try (RealVal <$> realP)
<|> (IntVal <$> intP)
realP :: Parser Double
realP = try negRealP <|> try divRealP <|> Tokens.float haskell
where divRealP = do
v <- "(/" ~> realP
v' <- realP <~ ")"
return $ v / v'
negRealP = do
v <- "(-" ~> realP <~ ")"
return $ -v
intP :: Parser Integer
intP = try negIntP <|> Tokens.integer haskell
where negIntP = do v <- "(-" ~> intP <~ ")"
return $ -v
indexP :: Parser Integer
indexP = Tokens.natural haskell
boolP :: Parser Bool
boolP = (True <$ str "true") <|> (False <$ str "false")
-- | Implicit conversion from strings.
instance IsString ModelVal where
fromString = runP modelP