Skip to content
Snippets Groups Projects
Commit e9a758d6 authored by Orestis Melkonian's avatar Orestis Melkonian
Browse files

Z3: feedback (4 combinations)

parent 330ab75f
No related branches found
No related tags found
No related merge requests found
module LogicIR.Backend.QuickCheck.API (equivalentTo) where module LogicIR.Backend.QuickCheck.API (equivalentTo) where
import Control.Arrow ((***)) import Control.Arrow ((***))
import Data.Map (Map) import qualified Data.Map.Lazy as M
import qualified Data.Map.Lazy as M
import Data.Maybe (fromJust, fromMaybe, isNothing)
import qualified LogicIR.Backend.QuickCheck.ModelGenerator as QC import qualified LogicIR.Backend.QuickCheck.ModelGenerator as QC
import LogicIR.Backend.QuickCheck.Test import LogicIR.Backend.QuickCheck.Test
import LogicIR.Expr import LogicIR.Expr hiding (b, r)
import LogicIR.Pretty (prettyLExpr) import LogicIR.Pretty (prettyLExpr)
import Model import Model
-- | Determine the equality of two method's pre/post conditions. -- | Determine the equality of two method's pre/post conditions.
equivalentTo :: LExpr -> LExpr -> IO Response equivalentTo :: LExpr -> LExpr -> IO Response
equivalentTo lexpr lexpr' = do equivalentTo lexpr lexpr' = do
(eq, testModel) <- testEquality 1000 lexpr lexpr' (eq, testModel) <- testEquality 1000 lexpr lexpr'
let feedback = NoFeedback -- TODO check implication (stronger + weaker) let feedback = Feedback { pre = defFeedback -- TODO check which combinations are possible
, post = defFeedback -- leave as is
}
if eq if eq
then return Equivalent then return Equivalent
else return $ NotEquivalent (toZ3Model testModel) (feedback, NoFeedback) else return $ NotEquivalent (toZ3Model testModel) feedback
toZ3Model :: (QC.Model, QC.ArrayModel) -> Model toZ3Model :: (QC.Model, QC.ArrayModel) -> Model
toZ3Model (m, arrayM) = toZ3Model (m, arrayM) =
...@@ -29,6 +29,7 @@ toModelVal :: LExpr -> ModelVal ...@@ -29,6 +29,7 @@ toModelVal :: LExpr -> ModelVal
toModelVal (LConst (CBool b)) = BoolVal b toModelVal (LConst (CBool b)) = BoolVal b
toModelVal (LConst (CInt i)) = IntVal $ toInteger i toModelVal (LConst (CInt i)) = IntVal $ toInteger i
toModelVal (LConst (CReal r)) = RealVal r toModelVal (LConst (CReal r)) = RealVal r
toModelVal _ = error "toModelVal: invalid LExpr"
toModelVals :: [LExpr] -> ModelVal toModelVals :: [LExpr] -> ModelVal
toModelVals = ManyVal . map toModelVal toModelVals = ManyVal . map toModelVal
...@@ -8,14 +8,13 @@ import qualified Z3.Base as Z3 ...@@ -8,14 +8,13 @@ import qualified Z3.Base as Z3
import Z3.Monad hiding (Model) import Z3.Monad hiding (Model)
import Control.Exception.Base (tryJust) import Control.Exception.Base (tryJust)
import Control.Monad (forM, when) import Control.Monad (forM)
import qualified Data.Map as M import qualified Data.Map as M
import Data.Maybe (fromJust) import Data.Maybe (fromJust)
import Data.String import Data.String
import Control.Monad.Trans (liftIO)
import LogicIR.Backend.Z3.Z3 import LogicIR.Backend.Z3.Z3
import LogicIR.Expr (LExpr, lnot, (.<==>), (.==>)) import LogicIR.Expr (LExpr, lnot, (.&&), (.<==>))
import Model import Model
data Z3Response = Satisfiable Model | Unsatisfiable | Undecidable data Z3Response = Satisfiable Model | Unsatisfiable | Undecidable
...@@ -27,18 +26,19 @@ equivalentTo l l' = do ...@@ -27,18 +26,19 @@ equivalentTo l l' = do
equiv <- checkZ3 $ lnot (l .<==> l') equiv <- checkZ3 $ lnot (l .<==> l')
case equiv of case equiv of
Satisfiable m -> do Satisfiable m -> do
feedback <- do res <- sequence $ checkZ3 <$>
stronger <- checkZ3 $ lnot (l .==> l') [l .&& l', l .&& lnot l', lnot l .&& l', lnot l .&& lnot l']
case stronger of let feedback = mkFeedback $ toBool <$> res
Unsatisfiable -> return Stronger return $ NotEquivalent m Feedback {pre = feedback, post = defFeedback}
_ -> do
weaker <- checkZ3 $ lnot (l' .==> l)
case weaker of
Unsatisfiable -> return Weaker
_ -> return NoFeedback
return $ NotEquivalent m (feedback, NoFeedback)
Unsatisfiable -> return Equivalent Unsatisfiable -> return Equivalent
Undecidable -> return Undefined Undecidable -> return Undefined
where
mkFeedback :: [Bool] -> SingleFeedback
mkFeedback [b1, b2, b3, b4] = (b1, b2, b3, b4)
mkFeedback _ = defFeedback
toBool :: Z3Response -> Bool
toBool (Satisfiable _) = True
toBool _ = False
-- | Checks the validity of a logical statement. -- | Checks the validity of a logical statement.
checkZ3 :: LExpr -> IO Z3Response checkZ3 :: LExpr -> IO Z3Response
......
...@@ -16,18 +16,30 @@ import qualified Text.Parsec.Token as Tokens ...@@ -16,18 +16,30 @@ import qualified Text.Parsec.Token as Tokens
import LogicIR.ParserUtils import LogicIR.ParserUtils
-- | Feedback type. -- | Feedback type.
data Feedback = Stronger -- A ==> B type SingleFeedback = ( Bool -- T-T
| Weaker -- A <== B , Bool -- T-F
| NoFeedback -- A ??? B , Bool -- F-T
deriving (Eq, Show, Generic) , Bool -- F-F
)
defFeedback :: SingleFeedback
defFeedback = (False, False, False, False)
data Feedback = Feedback
{ pre :: SingleFeedback
, post :: SingleFeedback
} deriving (Eq, Show, Generic)
defFeedback' :: Feedback
defFeedback' = Feedback { pre = defFeedback, post = defFeedback }
-- | Response type. -- | Response type.
data Response = Equivalent data Response = Equivalent
| NotEquivalent Model (Feedback, Feedback) | NotEquivalent Model Feedback
| ErrorResponse String | ErrorResponse String
| Undefined | Undefined
| Timeout | Timeout
deriving (Eq, Show) deriving (Eq, Show)
(<>) :: Response -> Response -> Response (<>) :: Response -> Response -> Response
ErrorResponse e <> _ = ErrorResponse e ErrorResponse e <> _ = ErrorResponse e
...@@ -35,7 +47,7 @@ _ <> ErrorResponse e = ErrorResponse e ...@@ -35,7 +47,7 @@ _ <> ErrorResponse e = ErrorResponse e
Timeout <> _ = Timeout Timeout <> _ = Timeout
Undefined <> _ = Undefined Undefined <> _ = Undefined
Equivalent <> r = r Equivalent <> r = r
NotEquivalent s (f, _) <> NotEquivalent _ (f', _) = NotEquivalent s (f, f') NotEquivalent s (Feedback pre' _) <> NotEquivalent _ (Feedback _ post') = NotEquivalent s (Feedback pre' post')
r <> _ = r r <> _ = r
-- | Model type. -- | Model type.
...@@ -49,8 +61,8 @@ type Model = M.Map String ModelVal ...@@ -49,8 +61,8 @@ type Model = M.Map String ModelVal
emptyModel :: Model emptyModel :: Model
emptyModel = M.empty emptyModel = M.empty
emptyFeedback :: (Feedback, Feedback) -- emptyFeedback :: (Feedback, Feedback)
emptyFeedback = (NoFeedback, NoFeedback) -- emptyFeedback = (NoFeedback, NoFeedback)
-- | Pretty-printing. -- | Pretty-printing.
instance Show ModelVal where instance Show ModelVal where
......
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE DataKinds #-} {-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleInstances #-}
...@@ -8,18 +9,17 @@ ...@@ -8,18 +9,17 @@
{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Server (runApi) where module Server (runApi) where
import Control.Monad.Trans (liftIO) import Control.Monad.Trans (liftIO)
import Data.Aeson import Data.Aeson
import Data.ByteString.Lazy (ByteString) import Data.ByteString.Lazy (ByteString)
import Data.List.Split (splitOn) import Data.List.Split (splitOn)
import qualified Data.Map as Map import qualified Data.Map as Map
import Data.Proxy import Data.Proxy
import Data.Text.Lazy (pack) import Data.Text.Lazy (pack)
import Data.Text.Lazy.Encoding (encodeUtf8) import Data.Text.Lazy.Encoding (encodeUtf8)
import Data.Vector (fromList) import Data.Vector (fromList)
import GHC.Generics import GHC.Generics
import System.IO import System.IO
...@@ -30,11 +30,11 @@ import Network.Wai.Handler.Warp ...@@ -30,11 +30,11 @@ import Network.Wai.Handler.Warp
import Servant import Servant
import Servant.Docs import Servant.Docs
import Data.Swagger hiding (port) import Data.Swagger hiding (port)
import Servant.Swagger import Servant.Swagger
import Servant.Swagger.UI import Servant.Swagger.UI
import API (Mode (..), ParseMode (..), compareSpec) import API (Mode (..), ParseMode (..), compareSpec)
import Model import Model
-- | Data types. -- | Data types.
...@@ -52,7 +52,7 @@ data ApiResponse = ApiResponse ...@@ -52,7 +52,7 @@ data ApiResponse = ApiResponse
{ responseType :: ApiResponseType { responseType :: ApiResponseType
, model :: Maybe Model , model :: Maybe Model
, err :: Maybe String , err :: Maybe String
, feedback :: Maybe (Feedback, Feedback) , feedback :: Maybe Feedback
} }
deriving (Eq, Show, Generic) deriving (Eq, Show, Generic)
instance ToJSON Feedback instance ToJSON Feedback
...@@ -65,6 +65,7 @@ instance ToJSON ModelVal where ...@@ -65,6 +65,7 @@ instance ToJSON ModelVal where
toJSON (ManyVal vs) = Array $ fromList $ map toJSON vs toJSON (ManyVal vs) = Array $ fromList $ map toJSON vs
-- | Default API response. -- | Default API response.
defResp :: ApiResponse
defResp = ApiResponse { responseType = Undef defResp = ApiResponse { responseType = Undef
, model = Nothing , model = Nothing
, err = Nothing , err = Nothing
...@@ -118,7 +119,7 @@ instance ToSample ApiResponse where ...@@ -118,7 +119,7 @@ instance ToSample ApiResponse where
, ("i", IntVal 10) , ("i", IntVal 10)
] ]
, err = Nothing , err = Nothing
, feedback = Just (NoFeedback, Stronger) , feedback = Just $ Feedback (True, True, False, True) (False, True, True, False)
} }
docsBS :: ByteString docsBS :: ByteString
......
...@@ -17,10 +17,10 @@ testEquiv :: Response -> String -> String -> String -> Assertion ...@@ -17,10 +17,10 @@ testEquiv :: Response -> String -> String -> String -> Assertion
testEquiv b src s s' = do testEquiv b src s s' = do
res <- hSilence [stdout, stderr] $ compareSpec Debug File (src, s) (src, s') res <- hSilence [stdout, stderr] $ compareSpec Debug File (src, s) (src, s')
(case res of (case res of
NotEquivalent _ _ -> NotEquivalent emptyModel emptyFeedback NotEquivalent _ _ -> NotEquivalent emptyModel defFeedback'
x -> x) @?= b x -> x) @?= b
(.==) = testEquiv Equivalent (.==) = testEquiv Equivalent
(.!=) = testEquiv $ NotEquivalent emptyModel emptyFeedback (.!=) = testEquiv $ NotEquivalent emptyModel defFeedback'
genEquivTests edslSrc = genEquivTests edslSrc =
let methodIds = unsafePerformIO (hSilence [stdout, stderr] $ parseMethodIds edslSrc) let methodIds = unsafePerformIO (hSilence [stdout, stderr] $ parseMethodIds edslSrc)
......
...@@ -13,10 +13,10 @@ testEquiv :: Response -> String -> String -> Assertion ...@@ -13,10 +13,10 @@ testEquiv :: Response -> String -> String -> Assertion
testEquiv b s s' = do testEquiv b s s' = do
res <- hSilence [stdout, stderr] $ compareSpec Release File (src, s) (src, s') res <- hSilence [stdout, stderr] $ compareSpec Release File (src, s) (src, s')
(case res of (case res of
NotEquivalent _ _ -> NotEquivalent emptyModel emptyFeedback NotEquivalent _ _ -> NotEquivalent emptyModel defFeedback'
x -> x) @?= b x -> x) @?= b
(.==) = testEquiv Equivalent (.==) = testEquiv Equivalent
(.!=) = testEquiv $ NotEquivalent emptyModel emptyFeedback (.!=) = testEquiv $ NotEquivalent emptyModel defFeedback'
(.??) = testEquiv Timeout (.??) = testEquiv Timeout
examples = examples =
......
...@@ -16,12 +16,13 @@ testEquiv b s s' = do ...@@ -16,12 +16,13 @@ testEquiv b s s' = do
(case res of (case res of
NotEquivalent _ f -> NotEquivalent emptyModel f NotEquivalent _ f -> NotEquivalent emptyModel f
x -> x) @?= b x -> x) @?= b
(!!=) s s' f = testEquiv (NotEquivalent emptyModel (f, NoFeedback)) s s' (!!=) s s' f = testEquiv (NotEquivalent emptyModel (Feedback f defFeedback)) s s'
feedbackTests = feedbackTests =
[ ("true /\\ x:int == 1" !!= "false \\/ x:int >= 1") Stronger [ ("true /\\ x:int == 1" !!= "false \\/ x:int >= 1") (True, False, True, True)
, ("true /\\ x:int >= 1" !!= "false \\/ x:int == 1") Weaker , ("true /\\ x:int >= 1" !!= "false \\/ x:int == 1") (True, True, False, True)
, ("x:int == 1 /\\ y:int == 1" !!= "x:int == 2 /\\ y:int == 1") NoFeedback , ("x:int == 1 /\\ y:int == 1" !!= "x:int == 2 /\\ y:int == 1")
, ("x:[int][0] != 0 /\\ x:[int][1] != 0" (False, True, True, True)
!!= "x:[int][0] != 0 \\/ x:[int][1] != 0") Stronger , ("x:[int][0] != 0 /\\ x:[int][1] != 0" !!= "x:[int][0] != 0 \\/ x:[int][1] != 0")
(True, False, True, True)
] ]
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment