src/HOL/Tools/Quickcheck/Narrowing_Engine.hs
author bulwahn
Wed Nov 30 09:21:11 2011 +0100 (2011-11-30)
changeset 45685 e2e928af750b
parent 45081 f00e52acbd42
child 45725 2987b29518aa
permissions -rw-r--r--
quickcheck narrowing also shows potential counterexamples
bulwahn@41933
     1
module Narrowing_Engine where {
bulwahn@41905
     2
bulwahn@41905
     3
import Monad;
bulwahn@41905
     4
import Control.Exception;
bulwahn@41905
     5
import System.IO;
bulwahn@41905
     6
import System.Exit;
bulwahn@45081
     7
import qualified Generated_Code;
bulwahn@41905
     8
bulwahn@41908
     9
type Pos = [Int];
bulwahn@41905
    10
bulwahn@41905
    11
-- Term refinement
bulwahn@41905
    12
bulwahn@45081
    13
new :: Pos -> [[Generated_Code.Narrowing_type]] -> [Generated_Code.Narrowing_term];
bulwahn@45081
    14
new p ps = [ Generated_Code.Ctr c (zipWith (\i t -> Generated_Code.Var (p++[i]) t) [0..] ts)
bulwahn@41905
    15
           | (c, ts) <- zip [0..] ps ];
bulwahn@41905
    16
bulwahn@45081
    17
refine :: Generated_Code.Narrowing_term -> Pos -> [Generated_Code.Narrowing_term];
bulwahn@45081
    18
refine (Generated_Code.Var p (Generated_Code.SumOfProd ss)) [] = new p ss;
bulwahn@45081
    19
refine (Generated_Code.Ctr c xs) p = map (Generated_Code.Ctr c) (refineList xs p);
bulwahn@41905
    20
bulwahn@45081
    21
refineList :: [Generated_Code.Narrowing_term] -> Pos -> [[Generated_Code.Narrowing_term]];
bulwahn@41908
    22
refineList xs (i:is) = let (ls, x:rs) = splitAt i xs in [ls ++ y:rs | y <- refine x is];
bulwahn@41905
    23
bulwahn@41905
    24
-- Find total instantiations of a partial value
bulwahn@41905
    25
bulwahn@45081
    26
total :: Generated_Code.Narrowing_term -> [Generated_Code.Narrowing_term];
bulwahn@45081
    27
total (Generated_Code.Ctr c xs) = [Generated_Code.Ctr c ys | ys <- mapM total xs];
bulwahn@45081
    28
total (Generated_Code.Var p (Generated_Code.SumOfProd ss)) = [y | x <- new p ss, y <- total x];
bulwahn@41905
    29
bulwahn@41905
    30
-- Answers
bulwahn@41905
    31
bulwahn@45003
    32
answeri :: a -> (a -> IO b) -> (Pos -> IO b) -> IO b;
bulwahn@45003
    33
answeri a known unknown =
bulwahn@41905
    34
  try (evaluate a) >>= (\res ->
bulwahn@41905
    35
     case res of
bulwahn@41905
    36
       Right b -> known b
bulwahn@41908
    37
       Left (ErrorCall ('\0':p)) -> unknown (map fromEnum p)
bulwahn@41905
    38
       Left e -> throw e);
bulwahn@41905
    39
bulwahn@45685
    40
answer :: Bool -> Bool -> (Bool -> IO b) -> (Pos -> IO b) -> IO b;
bulwahn@45685
    41
answer potential a known unknown =
bulwahn@45003
    42
  Control.Exception.catch (answeri a known unknown) 
bulwahn@45685
    43
    (\ (PatternMatchFail _) -> known (not potential));
bulwahn@45003
    44
bulwahn@41905
    45
-- Refute
bulwahn@41905
    46
bulwahn@41905
    47
str_of_list [] = "[]";
bulwahn@41905
    48
str_of_list (x:xs) = "(" ++ x ++ " :: " ++ str_of_list xs ++ ")";
bulwahn@41905
    49
bulwahn@45081
    50
report :: Result -> [Generated_Code.Narrowing_term] -> IO Int;
bulwahn@43079
    51
report r xs = putStrLn ("SOME (" ++ (str_of_list $ zipWith ($) (showArgs r) xs) ++ ")") >> hFlush stdout >> exitWith ExitSuccess;
bulwahn@41905
    52
bulwahn@45685
    53
eval :: Bool -> Bool -> (Bool -> IO a) -> (Pos -> IO a) -> IO a;
bulwahn@45685
    54
eval potential p k u = answer potential p (\p -> answer potential p k u) u;
bulwahn@41905
    55
bulwahn@45685
    56
ref :: Bool -> Result -> [Generated_Code.Narrowing_term] -> IO Int;
bulwahn@45685
    57
ref potential r xs = eval potential (apply_fun r xs) (\res -> if res then return 1 else report r xs)
bulwahn@45685
    58
  (\p -> sumMapM (ref potential r) 1 (refineList xs p));
bulwahn@41905
    59
          
bulwahn@45685
    60
refute :: Bool -> Result -> IO Int;
bulwahn@45685
    61
refute potential r = ref potential r (args r);
bulwahn@41905
    62
bulwahn@41908
    63
sumMapM :: (a -> IO Int) -> Int -> [a] -> IO Int;
bulwahn@41905
    64
sumMapM f n [] = return n;
bulwahn@41905
    65
sumMapM f n (a:as) = seq n (do m <- f a ; sumMapM f (n+m) as);
bulwahn@41905
    66
bulwahn@41905
    67
-- Testable
bulwahn@41905
    68
bulwahn@45081
    69
instance Show Generated_Code.Typerep where {
bulwahn@45081
    70
  show (Generated_Code.Typerep c ts) = "Type (\"" ++ c ++ "\", " ++ show ts ++ ")";
bulwahn@41905
    71
};
bulwahn@41905
    72
bulwahn@45081
    73
instance Show Generated_Code.Term where {
bulwahn@45081
    74
  show (Generated_Code.Const c t) = "Const (\"" ++ c ++ "\", " ++ show t ++ ")";
bulwahn@45081
    75
  show (Generated_Code.App s t) = "(" ++ show s ++ ") $ (" ++ show t ++ ")";
bulwahn@45081
    76
  show (Generated_Code.Abs s ty t) = "Abs (\"" ++ s ++ "\", " ++ show ty ++ ", " ++ show t ++ ")";
bulwahn@45081
    77
  show (Generated_Code.Free s ty) = "Free (\"" ++ s ++  "\", " ++ show ty ++ ")";
bulwahn@41905
    78
};
bulwahn@41905
    79
bulwahn@41905
    80
data Result =
bulwahn@45081
    81
  Result { args     :: [Generated_Code.Narrowing_term]
bulwahn@45081
    82
         , showArgs :: [Generated_Code.Narrowing_term -> String]
bulwahn@45081
    83
         , apply_fun    :: [Generated_Code.Narrowing_term] -> Bool
bulwahn@41905
    84
         };
bulwahn@41905
    85
bulwahn@41908
    86
data P = P (Int -> Int -> Result);
bulwahn@41905
    87
bulwahn@45081
    88
run :: Testable a => ([Generated_Code.Narrowing_term] -> a) -> Int -> Int -> Result;
bulwahn@41905
    89
run a = let P f = property a in f;
bulwahn@41905
    90
bulwahn@41905
    91
class Testable a where {
bulwahn@45081
    92
  property :: ([Generated_Code.Narrowing_term] -> a) -> P;
bulwahn@41905
    93
};
bulwahn@41905
    94
bulwahn@41905
    95
instance Testable Bool where {
bulwahn@41905
    96
  property app = P $ \n d -> Result [] [] (app . reverse);
bulwahn@41905
    97
};
bulwahn@41905
    98
bulwahn@45081
    99
instance (Generated_Code.Partial_term_of a, Generated_Code.Narrowing a, Testable b) => Testable (a -> b) where {
bulwahn@41905
   100
  property f = P $ \n d ->
bulwahn@45081
   101
    let Generated_Code.C t c = Generated_Code.narrowing d
bulwahn@45081
   102
        c' = Generated_Code.conv c
bulwahn@41905
   103
        r = run (\(x:xs) -> f xs (c' x)) (n+1) d
bulwahn@45081
   104
    in  r { args = Generated_Code.Var [n] t : args r,
bulwahn@45081
   105
      showArgs = (show . Generated_Code.partial_term_of (Generated_Code.Type :: Generated_Code.Itself a)) : showArgs r };
bulwahn@41905
   106
};
bulwahn@41905
   107
bulwahn@41905
   108
-- Top-level interface
bulwahn@41905
   109
bulwahn@45685
   110
depthCheck :: Testable a => Bool -> Int -> a -> IO ();
bulwahn@45685
   111
depthCheck potential d p =
bulwahn@45685
   112
  (refute potential $ run (const p) 0 d) >> putStrLn ("NONE") >> hFlush stdout;
bulwahn@41905
   113
bulwahn@45685
   114
smallCheck :: Testable a => Bool -> Int -> a -> IO ();
bulwahn@45685
   115
smallCheck potential d p = mapM_ (\d -> depthCheck potential d p) [0..d] >> putStrLn ("NONE") >> hFlush stdout;
bulwahn@41905
   116
bulwahn@41905
   117
}
bulwahn@41905
   118