twee-2.7.1: test/Nest.hs
-- Tests for the 'nests' function.
module Nest(tests) where
import Common
import Data.Intern
import Twee.Base
import Test.Tasty
import Test.Tasty.QuickCheck
import qualified Data.IntMap as M
-- Define 'nest' from Fuchs "The application of goal-oriented heuristics...",
-- then refine it to a more efficient version
nestf :: Func -> Term Func -> Int
nestf f _ | arity f == 0 = 0
nestf f t = hnest (Sym f) t 0 0
where
hnest _ (Var _) c a = max c a
hnest _ (App _ Nil) c a = max c a
hnest f (App g ts) c a
| f == g = maximum [hnest f t (c+1) a | t <- unpack ts]
| otherwise = maximum [hnest f t 0 (max c a) | t <- unpack ts]
-- a simpler version, to illustrate the meaning
nestf1 :: Func -> Term Func -> Int
nestf1 f t = hnest (Sym f) t 0
where
hnest _ (Var _) c = c
hnest _ (App _ Nil) c = c
hnest f (App g ts) c
| f == g = maximum [hnest f t (c+1) | t <- unpack ts]
| otherwise = max c (maximum [hnest f t 0 | t <- unpack ts])
-- a more efficient version
nestf2 :: Func -> Term Func -> Int
nestf2 f t = hnest (Sym f) (singleton t) 0 0
where
hnest _ Nil c a = max c a
hnest f (Cons (Var _) ts) c a = hnest f ts c a
hnest f (Cons (App _ Nil) ts) c a = hnest f ts c a
hnest f (Cons (App g ts) us) c a
| f == g =
let a' = hnest f ts (c+1) a
in hnest f us c a'
| otherwise =
let a' = hnest f ts 0 a
in hnest f us c a'
-- a version that does all function symbols at once
nestf3 :: Term Func -> M.IntMap Int
nestf3 t = hnest 0 0 M.empty (singleton t)
where
hnest f c as Nil = M.insertWith max f c as
hnest f c as (Cons (Var _) ts) = hnest f c as ts
hnest f c as (Cons (App _ Nil) ts) = hnest f c as ts
hnest f c as (Cons (App g ts) us) =
let as' = hnest (symId g) (if f == symId g then c+1 else 1) as ts
in hnest f c as' us
prop_nest_1 :: Func -> Term Func -> Property
prop_nest_1 f t = nestf f t === nestf1 f t
prop_nest_2 :: Func -> Term Func -> Property
prop_nest_2 f t = nestf f t === nestf2 f t
prop_nest_3 :: Func -> Term Func -> Property
prop_nest_3 f t =
nestf f t === M.findWithDefault 0 (symId (Sym f)) (nestf3 t)
prop_nests :: Func -> TermList Func -> Property
prop_nests f ts =
maximum (0:map (nestf f) (unpack ts)) ===
M.findWithDefault 0 (symId (Sym f)) (nests ts)
tests :: TestTree
tests =
localOption (QuickCheckTests 100000) $
testGroup "Nest function" [
testProperty "nestf1 is correct" prop_nest_1,
testProperty "nestf2 is correct" prop_nest_2,
testProperty "nestf3 is correct" prop_nest_3,
testProperty "nests is correct" prop_nests]