From 4f188800ab88da00a403e61352cb8c43b1081dc3 Mon Sep 17 00:00:00 2001
From: Joris ten Tusscher <joristt@gmail.com>
Date: Tue, 16 Jan 2018 12:21:03 +0100
Subject: [PATCH] =?UTF-8?q?-=20Fixed=20QuickCheck=20bugs,=20it=20works=20o?=
 =?UTF-8?q?n=2015/16=20tests=20now.=20-=20Added=20correct=20handling=20of?=
 =?UTF-8?q?=20LIsnull=20in=20QuickCheck.=20-=20Fixed=20a=20bug=20in=20Rewr?=
 =?UTF-8?q?ite.hs=20that=20wasn=E2=80=99t=20causing=20issues=20yet,=20but?=
 =?UTF-8?q?=20was=20a=20bug=20nonetheless.=20-=20Sped=20up=20QuickCheck=20?=
 =?UTF-8?q?tests=20by=20making=20the=20number=20of=20iterations=20dependen?=
 =?UTF-8?q?t=20on=20the=20specific=20test.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/LogicIR/Backend/QuickCheck.hs | 22 +++++++++-------
 src/LogicIR/Backend/Rewrite.hs    |  4 +--
 src/LogicIR/Eval.hs               | 23 +++++++++-------
 src/SimpleFormulaChecker.hs       |  5 ++++
 test/TIRQuickCheck.hs             | 44 +++++++++++++++----------------
 5 files changed, 55 insertions(+), 43 deletions(-)

diff --git a/src/LogicIR/Backend/QuickCheck.hs b/src/LogicIR/Backend/QuickCheck.hs
index ffe475b..8fa73fa 100644
--- a/src/LogicIR/Backend/QuickCheck.hs
+++ b/src/LogicIR/Backend/QuickCheck.hs
@@ -62,17 +62,14 @@ check e1 e2 = do
 -- be evaluated - i.e. there's still a variable in the LExpr - an error will be thrown.
 checkLExpr :: LExpr -> IO (LConst, Model)
 checkLExpr e = do 
-    primitivesModel      <- generateModel $ primitives
+    --putStrLn $ (show $ findPrimitives quantFreeE)
+    primitivesModel      <- generateModel $ findPrimitives quantFreeE
     let primFreeE         = applyModel primitivesModel quantFreeE
     (finalE, arrayModel) <- repeatedApplyAndExpandModel (primFreeE, empty)
     let model             = arrayModel ++ primitivesModel
     let result            = eval finalE
     return $ (result, model)
-    where quantFreeE                     = replaceQuantifiers e
-          vars                           = findPrimitives quantFreeE
-          primitives                     = filter sPrim vars
-          sPrim (LVar (Var (TPrim _) _)) = True
-          sPrim _                        = False
+    where quantFreeE = replaceQuantifiers e
 
 -- applies substitution of arrays until a "pure" LExpr is the result, or no
 -- more substitutions can be applied. If the latter is the case, an error
@@ -114,7 +111,7 @@ applyModel model = foldLExpr algebra
           var v           = substitute (LVar v) model
           quant _ _ e1 e2 = error "applyModel expects a quantifier-free LExpr."
           arr v e         = substitute (LArray v e) model
-          snull v         = LIsnull v
+          snull v         = substitute (LIsnull v) model
           len v           = LLen v
 
 -- Substitutes an LExpr if a valid substitute can be found in the given list.
@@ -131,6 +128,11 @@ generateModelEntry e@(LVar (Var (TPrim t) _)) = do
     generateValue t >>= \v -> return (e, v)
 generateModelEntry e@(LArray (Var (TArray (TPrim t)) _) _) = do
     generateValue t >>= \v -> return (e, v)
+generateModelEntry e@(LIsnull (Var (TArray _) _)) = do
+    generateValue PBool >>= \v -> return (e, v)
+generateModelEntry e = do
+    error $ "Cannot generate model entry for " ++ show e
+    return (e, e)
 
 -- Generates a random LExpr of a certain Primitive type.
 generateValue :: Primitive -> IO LExpr
@@ -151,7 +153,7 @@ toLExpr PInt32 v = LConst $ CInt  $ v
 
 -- Returns a list with all Vars in the LExpr.
 findPrimitives :: LExpr -> [LExpr]
-findPrimitives expr = nub $ foldLExpr algebra expr
+findPrimitives expr = filter isPrim $ nub $ foldLExpr algebra expr
     where algebra :: LExprAlgebra [LExpr]
           algebra = (cnst, var, uni, bin, iff, quant, arr, snull, len)
           cnst _          = []
@@ -161,8 +163,10 @@ findPrimitives expr = nub $ foldLExpr algebra expr
           var v           = [LVar v]
           quant _ _ e1 e2 = error "findPrimitives expects a quantifier-free LExpr."
           arr v e         = e
-          snull v         = [LVar v]
+          snull v         = [LIsnull v]
           len v           = [LVar v]
+          isPrim (LVar (Var (TArray _) _)) = False
+          isPrim _                         = True
 
 -- Returns a list with all LArrays in the LExpr. 
 findArrays :: LExpr -> [LExpr]
diff --git a/src/LogicIR/Backend/Rewrite.hs b/src/LogicIR/Backend/Rewrite.hs
index e426f9a..7762ed5 100644
--- a/src/LogicIR/Backend/Rewrite.hs
+++ b/src/LogicIR/Backend/Rewrite.hs
@@ -29,8 +29,8 @@ replaceQuantifiersAlgebra = (cnst, var, uni, bin, iff, quant, arr, snull, len)
 replaceQuantifier :: QOp -> Var -> LExpr -> LExpr -> LExpr
 replaceQuantifier op var domain e = LBinop e1 combiner e2
     where prime (Var t name) = Var t (name ++ "'")
-          e1                 = LBinop domain LAnd e
-          e2                 = replace var (prime var) (LBinop domain LAnd e)
+          e1                 = LBinop domain LImpl e
+          e2                 = replace var (prime var) (LBinop domain LImpl e)
           combiner           = if op == QAll then LAnd else LOr
 
 -- Returns an LExpr where all occurences of vOld in the given LExpr are
diff --git a/src/LogicIR/Eval.hs b/src/LogicIR/Eval.hs
index d274afa..a60393b 100644
--- a/src/LogicIR/Eval.hs
+++ b/src/LogicIR/Eval.hs
@@ -19,15 +19,16 @@ evalPossible = foldLExpr evalPossibleAlgebra
 
 evalPossibleAlgebra :: LExprAlgebra Bool
 evalPossibleAlgebra = (cnst, var, uni, bin, iff, quant, arr, snull, len)
-    where cnst _          = True
-          uni _ c         = c
-          bin le _ re     = le && re
-          iff ge e1 e2    = ge && e1 && e2
-          var v           = False
-          quant _ _ a1 a2 = a1 && a2
-          arr v a         = False
-          snull v         = True -- This possibly needs to be changed. See evalAlgebra
-          len v           = True -- This possibly needs to be changed. See evalAlgebra
+    where cnst _                   = True
+          uni _ c                  = c
+          bin le _ re              = le && re
+          iff ge e1 e2             = ge && e1 && e2
+          var v                    = False
+          quant _ _ a1 a2          = a1 && a2
+          arr v a                  = False
+          snull (Var (TPrim _) _)  = True -- Primitive type is never null.
+          snull (Var (TArray _) _) = False
+          len v                    = True -- This possibly needs to be changed. See evalAlgebra
 
 evalAlgebra :: LExprAlgebra LConst
 evalAlgebra = (cnst, var, uni, bin, iff, quant, arr, snull, len)
@@ -43,9 +44,11 @@ evalAlgebra = (cnst, var, uni, bin, iff, quant, arr, snull, len)
           iff ge e1 e2    = if ge == (CBool True) then e1 else e2
           
           -- This possibly needs to be changed.
-          snull v         = CBool False  -- error "Null checks cannot yet be evaluated."
           len v           = CInt  10 -- error "Array length cannot yet be evaluated."
 
+          snull (Var (TPrim _) _)  = CBool False -- Primitive type is never null.
+          snull (Var (TArray _) _) = error "You can't call eval on an LExpr that has an (LIsnull someArrayVar) that wasn't converted to a boolean first."
+
           -- Things that should never happen.
           quant _ _ e1 e2 = error "Quantifiers cannot be evaluated and should be replaced using LogicIR.Rewrite.replaceQuantifiers."
           arr v a         = error "You can't call eval on an LExpr that contains uninstantiated arrays."
diff --git a/src/SimpleFormulaChecker.hs b/src/SimpleFormulaChecker.hs
index 535992e..4582599 100644
--- a/src/SimpleFormulaChecker.hs
+++ b/src/SimpleFormulaChecker.hs
@@ -245,3 +245,8 @@ testSpec method1@(_, name1) method2@(_, name2) n = do
     let (lExpr1, lExpr2) = methodDefToLExpr m1 m2 "post"
     postAns <- testEquality n lExpr1 lExpr2
     return $ preAns && postAns
+
+-- The legendary 16th test that causes an endless loop in Z3 and that gives
+-- incorrect test results in the case of QuickCheck.
+test16 = testSpec (edslSrc, "sorted1") (edslSrc, "sorted4") 10000
+    where edslSrc = "examples/javawlp_edsl/src/nl/uu/javawlp_edsl/Main.java"
diff --git a/test/TIRQuickCheck.hs b/test/TIRQuickCheck.hs
index 5336c43..da62964 100644
--- a/test/TIRQuickCheck.hs
+++ b/test/TIRQuickCheck.hs
@@ -8,27 +8,27 @@ import SimpleFormulaChecker
 
 edslSrc = "examples/javawlp_edsl/src/nl/uu/javawlp_edsl/Main.java"
 
-testEquiv :: Bool -> String -> String -> Assertion
-testEquiv b s s' =
-  unsafePerformIO (silence $ testSpec (edslSrc, s) (edslSrc, s') 100000) @?= b
-(.==) = testEquiv True
-(.!=) = testEquiv False
+testEquiv :: Bool -> String -> String -> Int -> Assertion
+testEquiv b s s' n =
+  unsafePerformIO (silence $ testSpec (edslSrc, s) (edslSrc, s') n) @?= b
+eq  s s' n = testEquiv True s s' n
+neq s s' n = testEquiv False s s' n
 
 quickCheckTests =
-  [ "swap_spec1" .== "swap_spec1"
-  , "swap_spec1" .!= "swap_spec2"
-  , "getMax_spec1" .!= "getMax_spec2"
-  , "test1" .!= "test2"
-  , "blob1" .== "blob1"
-  , "test1_" .!= "test2"
-  , "null1" .!= "null2"
-  , "swap_spec1" .!= "swap_spec3"
-  , "swap_spec1" .!= "swap_spec4"
-  , "null3" .!= "test2"
-  , "sorted1" .!= "test2"
-  , "sorted1" .!= "sorted2"
-  , "sorted1".!= "sorted3"
-  , "test2" .!= "sorted3"
-  , "sorted3" .!= "sorted4"
-  , "sorted1" .== "sorted4"
-  ]
+  [ (eq  "swap_spec1" "swap_spec1" 10)
+  , (neq "swap_spec1" "swap_spec2" 10)
+  , (neq "getMax_spec1" "getMax_spec2" 1000)
+  , (neq "test1" "test2" 10)
+  , (eq  "blob1" "blob1" 10)
+  , (neq "test1_" "test2" 10)
+  , (neq "null1" "null2" 10)
+  , (neq "swap_spec1" "swap_spec3" 10)
+  , (neq "swap_spec1" "swap_spec4" 100)
+  , (neq "null3" "test2" 10)
+  , (neq "sorted1" "test2" 10)
+  , (neq "sorted1" "sorted2" 1000)
+  , (neq "sorted1" "sorted3" 1000)
+  , (neq "test2" "sorted3" 10)
+  , (neq "sorted3" "sorted4" 1000)
+  , (eq  "sorted1" "sorted4" 1000)
+  ]
\ No newline at end of file
-- 
GitLab