module Test.QuickSpec.Main where
#include "errors.h"
import Test.QuickSpec.Generate
import Test.QuickSpec.Reasoning.NaiveEquationalReasoning hiding (universe, maxDepth)
import Test.QuickSpec.Utils.Typed
import qualified Test.QuickSpec.Utils.TypeMap as TypeMap
import qualified Test.QuickSpec.Utils.TypeRel as TypeRel
import Test.QuickSpec.Signature hiding (vars)
import Test.QuickSpec.Term hiding (symbols)
import Control.Monad
import Text.Printf
import Data.Monoid
import Test.QuickSpec.TestTree(TestResults, classes, reps)
import Data.List
import System.Random
import Data.Monoid
import Data.Maybe
import Test.QuickSpec.Utils
import Test.QuickSpec.Equation
undefinedsSig :: Sig -> Sig
undefinedsSig sig =
background
[ undefinedSig "undefined" (undefined `asTypeOf` witness x)
| Some x <- saturatedTypes sig ]
universe :: [[Tagged Term]] -> [Tagged Term]
universe css = filter (not . isUndefined . erase) (concat css)
prune :: Context -> [Term] -> (a -> Equation) -> [a] -> [a]
prune ctx reps erase eqs = evalEQ ctx (filterM (fmap not . provable . erase) eqs)
where
provable (t :=: u) = do
res <- t =?= u
if res then return True else do
state <- get
t =:= u
reps' <- mapM rep reps
if sort reps' == usort reps' then return False else do
put state
return True
defines :: Equation -> Maybe Symbol
defines (t :=: u) = do
let isVar Var{} = True
isVar _ = False
acyclic t =
all acyclic (args t) &&
case functor t == functor u of
True -> usort (map Var (vars t)) `isProperSubsetOf` args u
False -> True
xs `isProperSubsetOf` ys = xs `isSubsetOf` ys && sort xs /= sort ys
xs `isSubsetOf` ys = sort xs `isSublistOf` sort ys
[] `isSublistOf` _ = True
(x:xs) `isSublistOf` [] = False
(x:xs) `isSublistOf` (y:ys)
| x == y = xs `isSublistOf` ys
| otherwise = (x:xs) `isSublistOf` ys
guard (all isVar (args u) && usort (args u) == args u &&
acyclic t && vars t `isSubsetOf` vars u)
return (functor u)
definitions :: [Equation] -> [Equation]
definitions es = [ e | e <- es, defines e /= Nothing ]
runTool :: Signature a => (Sig -> IO ()) -> a -> IO ()
runTool tool sig_ = do
putStrLn "== API =="
putStr (show (signature sig_))
let sig = signature sig_ `mappend` undefinedsSig (signature sig_)
tool sig
data Target = Target Symbol | NoTarget deriving (Eq, Ord)
target :: Equation -> Target
target (t :=: u) =
case usort (filter p (funs t ++ funs u)) of
[f] -> Target f
_ -> NoTarget
where p x = not (silent x) && symbolArity x > 0
innerZip :: [a] -> [[b]] -> [[(a,b)]]
innerZip [] _ = []
innerZip _ [] = []
innerZip xs ([]:yss) = []:innerZip xs yss
innerZip (x:xs) ((y:ys):yss) =
let (zs:zss) = innerZip xs (ys:yss)
in ((x,y):zs):zss
quickSpec :: Signature a => a -> IO ()
quickSpec = runTool $ \sig -> do
putStrLn "== Testing =="
r <- generate False (const partialGen) sig
let clss = concatMap (some2 (map (Some . O) . classes)) (TypeMap.toList r)
univ = concatMap (some2 (map (tagged term))) clss
reps = map (some2 (tagged term . head)) clss
eqs = equations clss
printf "%d raw equations; %d terms in universe.\n\n"
(length eqs)
(length reps)
let ctx = initial (maxDepth sig) (symbols sig) univ
allEqs = map (some eraseEquation) eqs
isBackground = all silent . eqnFuns
keep eq = not (isBackground eq) || absurd eq
absurd (t :=: u) = absurd1 t u || absurd1 u t
absurd1 (Var x) t = x `notElem` vars t
absurd1 _ _ = False
(background, foreground) =
partition isBackground allEqs
pruned = filter keep
(prune ctx (filter (not . isUndefined) (map erase reps)) id
(background ++ foreground))
eqnFuns (t :=: u) = funs t ++ funs u
isGround (t :=: u) = null (vars t) && null (vars u)
byTarget = innerZip [1 :: Int ..] (partitionBy target pruned)
forM_ byTarget $ \eqs@((_,eq):_) -> do
case target eq of
NoTarget -> putStrLn "== Equations about several functions =="
Target f -> printf "== Equations about %s ==\n" (show f)
forM_ eqs $ \(i, eq) ->
printf "%3d: %s\n" i (showEquation sig eq)
putStrLn ""
sampleList :: StdGen -> Int -> [a] -> [a]
sampleList g n xs | n >= length xs = xs
| otherwise = aux g n (length xs) xs
where
aux g 0 _ _ = []
aux g _ _ [] = ERROR "sampleList: bug in sampling"
aux g size len (x:xs)
| i <= size = x:aux g' (size1) (len1) xs
| otherwise = aux g' size (len1) xs
where (i, g') = randomR (1, len) g
sampleTerms :: Signature a => a -> IO ()
sampleTerms = runTool $ \sig -> do
putStrLn "== Testing =="
r <- generate False (const partialGen) (updateDepth (maxDepth sig 1) sig)
let univ = sort . concatMap (some2 (map term)) . TypeMap.toList . terms sig .
TypeMap.mapValues2 reps $ r
printf "Universe contains %d terms.\n\n" (length univ)
let numTerms = 100
printf "== Here are %d terms out of a total of %d ==\n" numTerms (length univ)
g <- newStdGen
forM_ (zip [1 :: Int ..] (sampleList g numTerms univ)) $ \(i, t) ->
printf "%d: %s\n" i (show (mapVars (disambiguate sig (vars t)) t))
putStrLn ""