{-# LANGUAGE TemplateHaskell, Rank2Types #-} module Main where import Control.Monad import Control.Applicative import Data.List import Data.Ord import System.Exit (exitFailure) import Test.QuickCheck import Test.QuickCheck.Test import Test.Feat.Access import Language.Haskell.Extract import Induction.Structural -- import Unsound import Trace import Env import EnvTypes import Walk import Util -- | Structural Induction Instatiator type SII = TyEnv Con' Ty' -> [(String,Ty')] -> [Int] -> [TaggedObligation Con' String Ty'] -- | Do induction on a test case ind :: SII -> TestCase -> [Oblig] ind sii (TestCase types coords) = unTag (\ (x :~ i) -> x ++ show i) $ sii testEnv' args coords where args = zip vars types vars :: [String] vars = concat [ replicateM n ['a'..'z'] | n <- [1..] ] data TestCase = TestCase [Ty'] [Int] deriving Show unitTc :: Int -> [Int] -> TestCase unitTc n = TestCase (replicate n (Si Unit)) boolTc :: Int -> [Int] -> TestCase boolTc x = TestCase (replicate x (Si Bool)) natTc :: Int -> TestCase natTc x = TestCase [Si Nat] (replicate x 0) maybeTc :: Ty' -> Int -> Int -> TestCase maybeTc t d i = TestCase [repeatMaybe t d] (replicate i 0) repeatMaybe :: Ty' -> Int -> Ty' repeatMaybe t = go where go n | n <= 0 = t | otherwise = case go (n - 1) of Si t' -> Si (Maybe t') mods :: Int -> [Int] -> [Int] mods 0 _ = [] mods x xs = map (`mod` x) xs -- | Linear prop_units :: SII -> NonNegative Int -> [Int] -> Property prop_units sii (NonNegative x) xs = mkProp sii (unitTc x' (mods x' xs)) where x' = min 5000 x -- | Can't try this too far because of exponential explosion prop_bools :: SII -> NonNegative Int -> [Int] -> Property prop_bools sii (NonNegative x) xs = mkProp sii (boolTc x' (mods x' xs)) where x' = min 10 x -- | Linear prop_maybe :: SII -> NonNegative Int -> NonNegative Int -> Property prop_maybe sii (NonNegative d) (NonNegative i) = mkProp sii (maybeTc (Si Unit) d' i') where d' = min 100 d i' = min 100 i mkPropTy :: SII -> Ty' -> Int -> Property mkPropTy sii ty n = mkProp sii (TestCase [ty] (replicate n 0)) mkProp :: SII -> TestCase -> Property mkProp sii tc@(TestCase tys _) = forAllShrink (startFromTypes tys) (mapM shrinkRepr') $ \ start -> forAll (makeTracer start parts) $ \ trace -> case loop trace of Just _ -> printTestCase (showOblig parts) False Nothing -> property True where parts = ind sii tc makeTestCases :: Integer -> IO [TestCase] makeTestCases tests = concat <$> forM [0..tests] (\ ix -> do let tys = indexWith enumTy's ix all_coordss = concat [ coordss (length tys - 1) d | d <- [0..4] ] coordss' <- head <$> sample' (shuffle all_coordss) let css = nub . sortBy (comparing length) . sort . take 10 $ coordss' return $ map (TestCase tys) css ) main :: IO () main = do let tests = -- [("structuralInductionUnsound",structuralInductionUnsound)] ++ [("subtermInduction",subtermInduction,96) ,("caseAnalysis",caseAnalysis,15) ] oks <- forM tests $ \ (name_sii,sii,test_depth) -> do putStrLn $ "== " ++ name_sii ++ " ==" testcases <- makeTestCases test_depth let num_tests = length testcases ok_feat <- forM (zip testcases ([0..] :: [Integer])) $ \ (tc@(TestCase tys cs),i) -> do putStrLn $ "(" ++ show i ++ "/" ++ show num_tests ++ ") " ++ name_sii ++ ": " ++ show tys ++ " coords: " ++ show cs quickCheckResult (mkProp sii tc) ok_manual <- sequence $(functionExtractorMap "^prop_" [| \ name_prop prop -> do putStrLn $ name_sii ++ ": " ++ name_prop quickCheckResult (prop sii) |]) return $ all isSuccess (ok_manual ++ ok_feat) unless (and oks) exitFailure