{-# LANGUAGE DataKinds , FlexibleContexts , GADTs , KindSignatures , OverloadedStrings , RankNTypes , TypeOperators #-} import Control.Applicative import Control.Monad import Control.Monad.Trans.Class import Control.Monad.Trans.Maybe import Data.Singletons import Prelude hiding (and, not) import Z3.Monad hiding (Sort, eval) import qualified Prelude as P import Data.Expression import Data.Expression.Z3 data Test where ShouldBe :: forall f. ( IToZ3 f, IShow f ) => IFix f 'BooleanSort -> Result -> Test HasModel :: forall f (s :: Sort). ( IToZ3 f , IFromZ3 f , IEq1 f , IShow f , EqualityF :<: f , NegationF :<: f , SingI s ) => IFix f 'BooleanSort -> (IFix f s, IFix f s) -> Test test :: Test -> (String, IO Bool) test (ShouldBe a r) = ( "Test " ++ show a ++ " is " ++ show r , evalZ3 $ do assert =<< toZ3 a liftA (r ==) check ) test (HasModel a (ex, ev)) = ( "Test " ++ show a ++ " has model with " ++ show ex ++ " = " ++ show ev , evalZ3 $ do assert =<< toZ3 a go ) where go = do _ <- check zx <- toZ3 ex mw <- runMaybeT $ do m <- MaybeT $ snd <$> getModel zv <- MaybeT $ modelEval m zx True lift $ fromZ3 zv case mw of Nothing -> return False Just ew -> if ev == ew then return True else do assert =<< toZ3 (ex ./=. ew) go main :: IO () main = do putStrLn "" guard . P.and =<< traverse eval props where props = [ p1, p2, p3, p4, p5, p6 ] tests = map test props column = maximum $ map (length . fst) tests eval t = do let (n, a) = test t putStr $ n ++ take (column - length n) (repeat ' ') ++ " " r <- a if r then putStrLn "passed" else putStrLn "failed" return r p1 = f `ShouldBe` Sat p2 = not f `ShouldBe` Unsat p3 = g `ShouldBe` Sat p4 = not g `ShouldBe` Unsat p5 = h `HasModel` (x, c5) p6 = i `HasModel` (x, c5) f, g, h, i :: Lia 'BooleanSort f = forall [x] (exists [y] (x .+. y .=. c0)) g = forall [x, y] (x .=. y .->. (x .+. c1) .=. (y .+. c1)) h = (x .+. m1 .=. y .+. c1) .&. (y .+. m1 .=. z .+. c1) .&. (z .=. c1) i = x .>. c0 x, y, z :: forall f. VarF :<: f => IFix f 'IntegralSort x = var "x" y = var "y" z = var "z" c0, c1, c5, m1 :: forall f. ArithmeticF :<: f => IFix f 'IntegralSort c0 = cnst 0 c1 = cnst 1 c5 = cnst 5 m1 = cnst (-1)