packages feed

speculate-0.4.0: tests/test-order.hs

{-# Language DeriveDataTypeable, StandaloneDeriving #-} -- Travis
import Test
import Test.Speculate.Utils
import qualified Test.LeanCheck.Utils as LC (comparison)

import Test.Speculate.Expr
import Test.Speculate.Reason (emptyThy)
import Test.Speculate.Reason.Order

import Data.Monoid ((<>))

-- for Travis:
deriving instance Typeable Thyght
deriving instance Typeable Equation

main :: IO ()
main = mainTest tests 10000

tests :: Int -> [Bool]
tests n =
  [ True -- see test-expr.hs for general Expr orders

  , holds n $ compare ==== (compareComplexity <> lexicompare)
  , holds n $ LC.comparison lexicompare
  , holds n $ LC.comparison compareComplexity

  , holds n $ \(IntToIntE e1) (IntToIntE e2) (IntE e3) -> let cmp = lexicompare in
                e1 `cmp` e2 == (e1 :$ e3) `cmp` (e2 :$ e3)
  , holds n $ \(IntToIntE e1) (IntToIntE e2) (IntE e3) -> let cmp = lexicompareBy (flip compare) in
                e1 `cmp` e2 == (e1 :$ e3) `cmp` (e2 :$ e3)
  , holds n $ \(BoolToBoolE e1) (BoolToBoolE e2) (BoolE e3) -> let cmp = lexicompare in
                e1 `cmp` e2 == (e1 :$ e3) `cmp` (e2 :$ e3)
  , holds n $ \(BoolToBoolE e1) (BoolToBoolE e2) (BoolE e3) -> let cmp = lexicompareBy (flip compare) in
                e1 `cmp` e2 == (e1 :$ e3) `cmp` (e2 :$ e3)

  -- some tests of order
  , value "xx" xx < zero
  , value "xxeqxx" (Equation xx xx) < value "xx" xx
  , value "xx" xx < value "emptyThyght" (Thyght emptyThy)

  , holds n $ simplificationOrder (|>|)
  , fails n $ simplificationOrder ( >|) -- TODO: make this pass (holds)
  , fails n $ closedUnderSub ( >|) -- reason for the above, I believe this is an actual bug in >|
-- > > checkFor 5040 $ closedUnderSub ( >|)
-- > *** Failed! Falsifiable (after 3707 tests):
-- > (id _ :: Int) (id 0 :: Int) (0 :: Int)
-- > > closedUnderSub (>|) (id' xx) (id' zero) zero
-- > False
--
-- The above bug did exist before the introduction of Express and probably
-- since the creation of (>|).

-- TODO: fix the following two tests
-- > > checkFor 10080 $ simplificationOrder (dwoBy (<))
-- > *** Failed! Falsifiable (after 6901 tests):
-- > (f _ :: Int) (id _ :: Int) (_ :: Int)
-- > > checkFor 10080 $ simplificationOrder (|> )
-- > *** Failed! Falsifiable (after 6901 tests):
-- > (f _ :: Int) (id _ :: Int) (_ :: Int)

  -- TODO: fix the following two tests with 10000 tests:
  , holds 5040 $ simplificationOrder (|> )
  , holds 5040 $ simplificationOrder (dwoBy (<))
  , fails 10080 $ compatible (|>)
-- TODO: fix the following two tests
-- > > checkFor 10080 $ compatible    (|>)
-- > *** Failed! Falsifiable (after 6901 tests):
-- > (f _ :: Int) (id _ :: Int) (_ :: Int)
-- Like the one above


  , fails n $ \e1 e2 -> (e1 |>| e2) == (e1 |>  e2)
  , fails n $ \e1 e2 -> (e1 |>| e2) == (e1  >| e2)
  , fails n $ \e1 e2 -> (e1 |>  e2) == (e1  >| e2)

  , not $ zero |> xx
  , not $ xx |> zero
  , negate' xx |> zero
  , negate' xx -+- xx |> zero
  , zero > xx
  , negateE > zero

  , weight xx                            == 1
  , weight zero                          == 1
  , weight (xx -+- zero)                 == 2
  , weight (one -+- yy)                  == 2
  , weight (xx -*- (yy -+- zz))          == 3
  , weight ((xx -*- yy) -+- (xx -*- zz)) == 4
  , holds n $ \e1 e2 -> weight (e1 -+- e2)  == weight e1 + weight e2
  , holds n $ \e     -> weight (e -+- zero) == 1 + weight e
  , holds n $ \e     -> weight (abs' e)     == 1 + weight e
  , holds n $ \e     -> weightExcept absE (abs' e)    <= weight e
  , holds n $ \e     -> weightExcept absE (negate' e) <= weight e + 1
  , holds n $ \e     -> weightExcept absE (abs' e)    == weightExcept absE e
  , holds n $ \e     -> weightExcept absE (negate' e) == weightExcept absE e + 1

  -- lexicompare is compatible (almost as if by coincidence)
  , fails n $ simplificationOrder lgt
  , holds n $ compatible          lgt
  , fails n $ closedUnderSub      lgt
  , fails n $ subtermProperty     lgt

  -- compare has the subtermProperty (Expr)
  , fails n $ simplificationOrder cgt
  , fails n $ compatible          cgt
  , fails n $ closedUnderSub      cgt
  , holds n $ subtermProperty     cgt
  ]
  where
  e1 `lgt` e2 = e1 `lexicompare` e2 == GT
  e1 `cgt` e2 = e1 `compare` e2 == GT

simplificationOrder :: (Expr -> Expr -> Bool) -> Expr -> Expr -> Expr -> Bool
simplificationOrder (>) = \e1 e2 e3 -> reductionOrder  (>) e1 e2 e3
                                    && subtermProperty (>) e1

subtermProperty :: (Expr -> Expr -> Bool) -> Expr -> Bool
subtermProperty (>) = \e -> all (e >)
                          . filter (\e' -> e' /= e && typ e' == typ e)
                          $ subexprs e -- isn't this subexprsV? I don't think so

reductionOrder :: (Expr -> Expr -> Bool) -> Expr -> Expr -> Expr -> Bool
reductionOrder (>) = \e1 e2 e3 -> strictPartialOrder (>) e1 e2 e3
                               && compatible         (>) e1 e2 e3
                               && closedUnderSub     (>) e1 e2 e3

compatible :: (Expr -> Expr -> Bool) -> Expr -> Expr -> Expr -> Bool
compatible (>) = \e e1 e2 -> e1 > e2 && typ e1 == typ e2
                         ==> and [ (e //- [(v,e1)]) > (e //- [(v,e2)])
                                 | v <- vars e
                                 , typ v == typ e1
                                 , typ v == typ e2 ]

-- The formal definition contains multiple assignments,
-- here, just a single variable is assigned.
closedUnderSub :: (Expr -> Expr -> Bool) -> Expr -> Expr -> Expr -> Bool
closedUnderSub (>) = \e1 e2 e -> e1 > e2
                             ==> and [ (e1 //- [(v,e)]) > (e2 //- [(v,e)])
                                     | v <- vars e1 `nubMerge` vars e2
                                     , typ v == typ e ]