packages feed

grisette-0.1.0.0: test/Grisette/Backend/SBV/Data/SMT/TermRewritingTests.hs

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE UndecidableInstances #-}

module Grisette.Backend.SBV.Data.SMT.TermRewritingTests where

import Data.Foldable
import qualified Data.SBV as SBV
import Grisette.Backend.SBV.Data.SMT.Solving
import Grisette.Backend.SBV.Data.SMT.TermRewritingGen
import Grisette.Core.Data.Class.Solver
import Grisette.IR.SymPrim.Data.BV
import Grisette.IR.SymPrim.Data.Prim.InternedTerm.Term
import Grisette.IR.SymPrim.Data.Prim.InternedTerm.TermUtils
import Grisette.IR.SymPrim.Data.SymPrim
import Test.Tasty
import Test.Tasty.HUnit
import Test.Tasty.QuickCheck

validateSpec :: (TermRewritingSpec a av, Show a, SupportedPrim av) => GrisetteSMTConfig n -> a -> Assertion
validateSpec config a = do
  r <- solve config (Sym $ counterExample a)
  rs <- solve config (Sym $ same a)
  case (r, rs) of
    (Left _, Right _) -> do
      return ()
    (Left _, Left _) -> do
      assertFailure $ "Bad rewriting with unsolvable formula: " ++ pformat (norewriteVer a) ++ " was rewritten to " ++ pformat (rewriteVer a)
    (Right m, _) -> do
      assertFailure $ "With model" ++ show m ++ "Bad rewriting: " ++ pformat (norewriteVer a) ++ " was rewritten to " ++ pformat (rewriteVer a)

termRewritingTests :: TestTree
termRewritingTests =
  let unboundedConfig = UnboundedReasoning SBV.z3 -- {SBV.verbose=True}
   in testGroup
        "TermRewritingTests"
        [ testGroup
            "Bool only"
            [ testProperty "Bool only random test" $
                mapSize (`min` 10) $
                  ioProperty . \(x :: BoolOnlySpec) -> do
                    validateSpec unboundedConfig x,
              testCase "Regression nested ite with (ite a (ite b c d) e) with b is true" $ do
                validateSpec @BoolOnlySpec
                  unboundedConfig
                  ( iteSpec
                      (symSpec "a" :: BoolOnlySpec)
                      ( iteSpec
                          (orSpec (notSpec (andSpec (symSpec "b1") (symSpec "b2"))) (symSpec "b2") :: BoolOnlySpec)
                          (symSpec "c")
                          (symSpec "d")
                      )
                      (symSpec "e")
                  ),
              testCase "Regression for pevalImpliesTerm _ false should be false" $ do
                validateSpec @BoolOnlySpec
                  unboundedConfig
                  ( iteSpec
                      (symSpec "fbool" :: BoolOnlySpec)
                      ( notSpec
                          ( orSpec
                              (orSpec (notSpec (andSpec (symSpec "gbool" :: BoolOnlySpec) (symSpec "fbool" :: BoolOnlySpec))) (symSpec "gbool" :: BoolOnlySpec))
                              (orSpec (symSpec "abool" :: BoolOnlySpec) (notSpec (andSpec (symSpec "gbool" :: BoolOnlySpec) (symSpec "bbool" :: BoolOnlySpec))))
                          )
                      )
                      (symSpec "xxx" :: BoolOnlySpec)
                  )
            ],
          testGroup
            "LIA"
            [ testProperty "LIA random test" $
                mapSize (`min` 10) $
                  ioProperty . \(x :: LIAWithBoolSpec) -> do
                    validateSpec unboundedConfig x,
              testCase "Regression nested ite with (ite a b (ite c d e)) with c implies a" $ do
                validateSpec @LIAWithBoolSpec
                  unboundedConfig
                  ( iteSpec
                      (notSpec (eqvSpec (symSpec "v" :: LIAWithBoolSpec) (conSpec 1 :: LIAWithBoolSpec) :: BoolWithLIASpec))
                      (symSpec "b")
                      ( iteSpec
                          (eqvSpec (symSpec "v" :: LIAWithBoolSpec) (conSpec 2 :: LIAWithBoolSpec) :: BoolWithLIASpec)
                          (symSpec "d")
                          (symSpec "d")
                      )
                  )
            ],
          testGroup
            "Different sized SignedBV"
            [ testProperty "Fixed Sized SignedBV random test" $
                mapSize (`min` 10) $
                  ioProperty . \(x :: (DifferentSizeBVSpec IntN 4)) -> do
                    validateSpec unboundedConfig x
            ],
          testGroup
            "Fixed sized SignedBV"
            [ testProperty "Fixed Sized SignedBV random test" $
                mapSize (`min` 10) $
                  ioProperty . \(x :: (FixedSizedBVWithBoolSpec IntN)) -> do
                    validateSpec unboundedConfig x
            ],
          testGroup
            "timesNumSpec on integer"
            [ testCase "times on both concrete" $ do
                traverse_
                  (\(x, y) -> validateSpec @(GeneralSpec Integer) unboundedConfig $ timesNumSpec (conSpec x) (conSpec y))
                  [(i, j) | i <- [-3 .. 3], j <- [-3 .. 3]],
              testCase "times on single concrete" $ do
                traverse_
                  ( \x -> do
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ timesNumSpec (conSpec x) (symSpec "a")
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ timesNumSpec (symSpec "a") (conSpec x)
                  )
                  [-3 .. 3],
              testCase "Two times with two concrete combined" $ do
                traverse_
                  ( \(x, y) -> do
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ timesNumSpec (conSpec x) $ timesNumSpec (conSpec y) (symSpec "a")
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ timesNumSpec (conSpec x) $ timesNumSpec (symSpec "a") (conSpec y)
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ timesNumSpec (timesNumSpec (conSpec x) (symSpec "a")) (conSpec y)
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ timesNumSpec (timesNumSpec (symSpec "a") (conSpec x)) (conSpec y)
                  )
                  [(i, j) | i <- [-3 .. 3], j <- [-3 .. 3]],
              testCase "Two times with one concrete" $ do
                traverse_
                  ( \x -> do
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ timesNumSpec (conSpec x) $ timesNumSpec (symSpec "b") (symSpec "a")
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ timesNumSpec (symSpec "b") $ timesNumSpec (symSpec "a") (conSpec x)
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ timesNumSpec (symSpec "b") $ timesNumSpec (conSpec x) (symSpec "a")
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ timesNumSpec (timesNumSpec (conSpec x) (symSpec "a")) (symSpec "b")
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ timesNumSpec (timesNumSpec (symSpec "a") (conSpec x)) (symSpec "b")
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ timesNumSpec (timesNumSpec (symSpec "a") (symSpec "b")) (conSpec x)
                  )
                  [-3 .. 3],
              testCase "times and add with two concretes combined" $ do
                traverse_
                  ( \(x, y) -> do
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ timesNumSpec (conSpec x) $ addNumSpec (conSpec y) (symSpec "a")
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ timesNumSpec (conSpec x) $ addNumSpec (symSpec "a") (conSpec y)
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ timesNumSpec (addNumSpec (conSpec x) (symSpec "a")) (conSpec y)
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ timesNumSpec (addNumSpec (symSpec "a") (conSpec x)) (conSpec y)
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ addNumSpec (conSpec x) $ timesNumSpec (conSpec y) (symSpec "a")
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ addNumSpec (conSpec x) $ timesNumSpec (symSpec "a") (conSpec y)
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ addNumSpec (timesNumSpec (conSpec x) (symSpec "a")) (conSpec y)
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ addNumSpec (timesNumSpec (symSpec "a") (conSpec x)) (conSpec y)
                  )
                  [(i, j) | i <- [-3 .. 3], j <- [-3 .. 3]],
              testCase "times concrete with uminusNumSpec symbolic" $ do
                traverse_
                  ( \x -> do
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ timesNumSpec (conSpec x) (uminusNumSpec $ symSpec "a")
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ timesNumSpec (uminusNumSpec $ symSpec "a") (conSpec x)
                  )
                  [-3 .. 3]
            ],
          testGroup
            "DivI"
            [ testCase "DivI on concrete" $ do
                traverse_
                  ( \(x, y) -> do
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ divIntegerSpec (conSpec x) (conSpec y)
                  )
                  [(i, j) | i <- [-3 .. 3], j <- [-3 .. 3]],
              testCase "DivI on single concrete" $ do
                traverse_
                  ( \x -> do
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ divIntegerSpec (conSpec x) (symSpec "a")
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ divIntegerSpec (symSpec "a") (conSpec x)
                  )
                  [-3 .. 3]
            ],
          testGroup
            "ModI"
            [ testCase "ModI on concrete" $ do
                traverse_
                  ( \(x, y) -> do
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ modIntegerSpec (conSpec x) (conSpec y)
                  )
                  [(i, j) | i <- [-3 .. 3], j <- [-3 .. 3]],
              testCase "ModI on single concrete" $ do
                traverse_
                  ( \x -> do
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ modIntegerSpec (conSpec x) (symSpec "a")
                      validateSpec @(GeneralSpec Integer) unboundedConfig $ modIntegerSpec (symSpec "a") (conSpec x)
                  )
                  [-3 .. 3]
            ]
        ]