{-# LANGUAGE GADTs,RebindableSyntax,CPP,FlexibleContexts,FlexibleInstances,ConstraintKinds #-}

{-# OPTIONS_GHC -dcore-lint #-}

{-
 - The idea of this test suite is that it should be compiled
 - with the -fplugin=Herbie and -dcore-lint flags.
 - Then we check to make sure GHC didn't throw any errors during
 - the core type checking process.
 -}
module Main
    where

import SubHask

--------------------------------------------------------------------------------

-- This section tests that Herbie obeys the code annotations

{-# ANN ann "NoHerbie" #-}
ann :: Float -> Float
ann x = x+x+x*x*x*x

noann :: Float -> Float
noann x = x+x+x*x*x*x

--------------------------------------------------------------------------------

-- This section tests that Herbie gets run on the correct types.
-- Herbie should be run on all the functions below.

#define f1(x) (sqrt ((x)+1) - sqrt (x))

herbie1 :: Real a => a -> a
herbie1 x = f1(x)

herbie2 :: Real a => a -> a -> a -> a -> a
herbie2 a b c d = f1(a)+f1(b)+f1(c)+f1(d)

herbie3 :: Float -> Float
herbie3 x = f1(x)

herbie4 :: String -> String
herbie4 str = show $ f1(x1)
      where
          x1 = fromIntegral (length str) :: Float

herbie5 :: (Show a, Real a) => String -> a -> String
herbie5 str x1 = show $ f1(x1)

herbie6 :: (Show a, Real a) => a -> String -> String
herbie6 x1 str = show $ f1(x1)

herbie7 :: Semigroup a => a -> a
herbie7 x1 = x1+x1+x1+x1+x1

herbie8 :: Float -> Float
herbie8 x1 = case x1 of
      1.0 -> f1(x1)
      2.0 -> x1

herbie9 :: Float -> Float
herbie9 x1 = go 4 x1
    where
        go :: Float -> Float -> Float
        go 0 b = b
        go a b = go (a-1) (sqrt (b-1))

herbie10 :: String -> String
herbie10 str = show ( sqrt (1+fromIntegral (length str))
                    - sqrt (fromIntegral (length str))
                    :: Float
                    )

-- Herbie should not get run on any of the functions in this section.

#define f2(a,b) a+b*(a+b*a)+a*b

noherbie1 :: String -> String
noherbie1 x = x++"hello world"

noherbie2 :: Rational -> Rational -> Rational
noherbie2 a b = f2(a,b)

noherbie3 :: Int -> Int -> Int
noherbie3 a b = f2(a,b)

noherbie4 :: x -> Int -> Int -> Int
noherbie4 x a b = f2(a,b)

--------------------------------------------------------------------------------

-- Herbie shouldn't process these because the expression size is too small.
-- We're unlikely to get any benefit, and it might take a long time.

toosmall1 :: Float -> Float
toosmall1 a = a+a

toosmall2 :: Float -> Float -> Float -> Float
toosmall2 a b c = a+b*c

-- These are big enough and should get processed

bigenough1 :: Float -> Float
bigenough1 a = a+a*a

bigenough2 :: Float -> Float -> Float -> Float
bigenough2 a b c = a+b*(c+a)

bigenough3 :: Float -> Float -> Float -> Float
bigenough3 a b c = f1(c)

--------------------------------------------------------------------------------

-- This section contains lots of examples of expressions that the Herbie plugin can parse
-- and find improved versions.

example1 x1 x2 = sqrt (x1*x1 + x2*x2)

example2 x = exp(log(x)+8)

example3 x = sqrt(x*x +1) -1

example4 x = exp(x)-1

example5 x = log(1+x)

example6 x y = sqrt(x+ y) - sqrt(y)

example7 k r a = k*(r-a)^3

example8 k r a = k*(r-a)^2

example9 x y = sin(x - y)

example10 p1x p2x p1y p2y = sqrt((p1x - p2x) * (p1x - p2x) + (p1y - p2y) * (p1y - p2y))

example11 x = sin(x)-x

example12 x = 1-cos(x)

example13 x1 x2 = sqrt((x1 - x2) * (x1 - x2))

example14 x y z = sqrt(x*x + y*y + z*z)

example15 x y z c = sqrt(x*x + y*y + z*z)/c

example16 tdx dx tdy dy = (tdx * dx + tdy * dy) / (dx * dx + dy * dy)

example17 tdx dx tdy dy sl2 = (tdx * dx + tdy * dy) / sl2

example18 x = (x + 0.1)-x

example19 x = log(x) - sin(x+1)

example20 a b = exp(1+log(a) + log(b))

example21 x = (1+sqrt(x-1))/(x-1)^2

example22 x = (1+sqrt(x))/(x-1)^2

example23 a b c d e f = a+b+(((d-c)*(d-c))*e*f/(e+f))

example24 q = sqrt(q*(q-1))

example25 a = sqrt(a^2-1)

example26 a b c d = ((a*b)+(c*d))/(a+c)

example27 x = sqrt(x^2)

example28 x y = sqrt(x) * y * y

example29 x y z = sqrt(x*x+y*y+z*z)

example30 x y = 1.75 * x * y*y + sqrt(x/y)

example31 x = exp(3*log(x)+2)

example32 x = exp(2*log(x))

example33 x = sqrt(1/x + 1) - sqrt(1/x)

example34 left i right count = left + i * ((left - right) / count)

example35 left right count = left + count * ((left - right) / count)

example36 x y = sqrt(x*x) - sqrt(y*y)

example37 x = log(x+1)-log(x)

example38 x = log(x+1)^x

example39 minval minstep val = (minval/minstep + val) * minstep

example40 x = x*x*cos(x/2 - sqrt(x))

example41 x = sqrt(4+x^2+x)

example42 x y z = x / sqrt(x*x + y*y + z*z)

example43 x = sin(sqrt(x+1))

example44 x = sqrt(x-2)-sqrt(x*x-3)

example45 x = (sin(x) - tan(x)) / x

example46 x y = 1 / sqrt(x^2 - y^2)

example47 x1 x2 = sqrt((x1 - x2)^2)

example48 x = x - sin(x)

example49 x = sqrt(x + 1) - 1 + x

example50 a b c = (a*a - c*c)/b

example51 x y = sin(x+y)-cos(x+y)

example52 x = (x + 1)^2 - 1

example53 x = sqrt(1+x) - sqrt(x)

example54 x = sqrt(x + 1) / (x*x)

example55 x = sqrt(x^2 / 3)

example56 a b = 100*(a-b)/a

example57 x = abs(x^3)-x^3

example58 x = log(x) - log(x+1)

example59 x = 1/x - 1/(x+1)

example60 a b c = -b + sqrt(b*b-4*a*c)/(2*a)

example61 a c an cn = log(exp(a)*an + exp(c)*cn) - log(an+cn)

example62 x = sqrt(sin(x)) - sqrt(x)

example63 x = log(1+x)

example64 a b = a * b / (1 - b + a * b)

example65 a b = b*sqrt(a * a + 1.0)

example65' a = sqrt(a * a + 1.0)

example66 x y = x * y * x*pi/y

example67 x = sqrt(x + 1) - sqrt(x - 1)

example68 x = cos(x + 1) * x^2

example69 a b = b*(a/b - log(1 + a/b))

example70 a b = b*(a/b - 1 - log(a/b))

example71 x = (6/(x^99))*(x^101)

example72 x = (1/(x^99))*(x^101)

example73 x = (1/(x^100))*(x^100)

example74 x y z = cos(sqrt(x*x+y*y+z*z))

example75 x = sqrt(sqrt(x*x+1)+1)

example76 a k = a + sqrt(a*a-k)

example77 a k = -a - sqrt(a*a-k)

example78 a b x = x*x*a+x*(a+b) +x*b

example79 x = (x + x) ^ 3 / x

example80 x = sqrt(x+1)-sqrt 1

example81 x = (x+1)-x

example82 x = sqrt(x+100)-sqrt(x)

example83 x = 1-cos(x)

example84 u v = sqrt(sqrt(u^2 + v^2) - u)

example85 x = exp(log(x))

example86 x = sqrt(x + 1) - sqrt x + sin(x - 1)

example87 x = exp x / sqrt(exp x - 1) * sqrt x

example88 x = (exp(x) - 1) / x

example89 x = sqrt(x + 2) - sqrt(x)

--------------------------------------------------------------------------------

-- The main function does nothing
main = return ()
