{-|
    Module      :  Numeric.MixedType.Elementary
    Description :  Bottom-up typed pi, sqrt, cos, etc
    Copyright   :  (c) Michal Konecny
    License     :  BSD3

    Maintainer  :  mikkonecny@gmail.com
    Stability   :  experimental
    Portability :  portable

-}

module Numeric.MixedTypes.Elementary
(
  -- * Square root
  CanSqrt(..), CanSqrtSameType, CanSqrtCNSameType, specCanSqrtReal
  -- * Exp
  , CanExp(..), CanExpSameType, specCanExpReal
  -- * Log
  , CanLog(..), CanLogSameType, CanLogCNSameType, specCanLogReal
  , powUsingExpLog
  -- * Sine and cosine
  , CanSinCos(..), CanSinCosSameType, specCanSinCosReal
  , approxPi
)
where

import Numeric.MixedTypes.PreludeHiding
import qualified Prelude as P
import Text.Printf

-- import qualified Data.List as List

import Test.Hspec
import Test.QuickCheck

import Numeric.CollectErrors
import Control.CollectErrors

import Numeric.MixedTypes.Literals
import Numeric.MixedTypes.Bool
import Numeric.MixedTypes.Eq
import Numeric.MixedTypes.Ord
-- import Numeric.MixedTypes.MinMaxAbs
import Numeric.MixedTypes.AddSub
import Numeric.MixedTypes.Ring
import Numeric.MixedTypes.Field
-- import Numeric.MixedTypes.Round

import Utils.Test.EnforceRange 

{----  sqrt -----}

{-|
  A replacement for Prelude's `P.sqrt`.  If @Floating t@,
  then one can use the default implementation to mirror Prelude's @sqrt@.
-}
class CanSqrt t where
  type SqrtType t
  type SqrtType t = t -- default
  sqrt :: t -> SqrtType t
  default sqrt :: (SqrtType t ~ t, P.Floating t) => t -> SqrtType t
  sqrt = t -> SqrtType t
forall a. Floating a => a -> a
P.sqrt

type CanSqrtSameType t = (CanSqrt t, SqrtType t ~ t)
type CanSqrtCNSameType t = (CanSqrt t, SqrtType t ~ EnsureCN t)

{-|
  HSpec properties that each implementation of CanSqrt should satisfy.
 -}
specCanSqrtReal ::
  (Show t, Show (SqrtType t), Show (PowType (SqrtType t) Integer),
    Arbitrary t,
    CanTestCertainly (OrderCompareType (SqrtType t) Integer),
    CanTestCertainly (EqCompareType (PowType (SqrtType t) Integer) t),
    HasEqAsymmetric (PowType (SqrtType t) Integer) t,
    HasOrderAsymmetric (SqrtType t) Integer, CanTestPosNeg t,
    CanPow (SqrtType t) Integer, CanSqrt t)
  =>
  T t -> Spec
specCanSqrtReal :: T t -> Spec
specCanSqrtReal (T String
typeName :: T t) =
  String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe (String -> String -> String
forall r. PrintfType r => String -> r
printf String
"CanSqrt %s" String
typeName) (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
    String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"sqrt(x) >= 0" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
      (t -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((t -> Property) -> Property) -> (t -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (t
x :: t) ->
        t -> Bool
forall t. CanTestPosNeg t => t -> Bool
isCertainlyNonNegative t
x Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
          (t -> SqrtType t
forall t. CanSqrt t => t -> SqrtType t
sqrt t
x) SqrtType t -> Integer -> Property
forall a b.
(HasOrderCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?>=?$ Integer
0
    String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"sqrt(x)^2 = x" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
      (t -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((t -> Property) -> Property) -> (t -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (t
x :: t) ->
        t -> Bool
forall t. CanTestPosNeg t => t -> Bool
isCertainlyNonNegative t
x Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
          (t -> SqrtType t
forall t. CanSqrt t => t -> SqrtType t
sqrt t
x)SqrtType t -> Integer -> PowType (SqrtType t) Integer
forall t1 t2. CanPow t1 t2 => t1 -> t2 -> PowType t1 t2
^Integer
2 PowType (SqrtType t) Integer -> t -> Property
forall a b.
(HasEqCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?==?$ t
x
  where
  infix 4 ?==?$
  (?==?$) :: (HasEqCertainlyAsymmetric a b, Show a, Show b) => a -> b -> Property
  ?==?$ :: a -> b -> Property
(?==?$) = String -> (a -> b -> Bool) -> a -> b -> Property
forall prop a b.
(Testable prop, Show a, Show b) =>
String -> (a -> b -> prop) -> a -> b -> Property
printArgsIfFails2 String
"?==?" a -> b -> Bool
forall a b. HasEqCertainlyAsymmetric a b => a -> b -> Bool
(?==?)
  infix 4 ?>=?$
  (?>=?$) :: (HasOrderCertainlyAsymmetric a b, Show a, Show b) => a -> b -> Property
  ?>=?$ :: a -> b -> Property
(?>=?$) = String -> (a -> b -> Bool) -> a -> b -> Property
forall prop a b.
(Testable prop, Show a, Show b) =>
String -> (a -> b -> prop) -> a -> b -> Property
printArgsIfFails2 String
"?>=?" a -> b -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
(?>=?)

{-
  Instances for Integer, Rational etc need an algebraic real or exact real type.
  Such type is not provided in this package. See eg aern2-real.
-}

instance CanSqrt Double -- not exact, will not pass the tests

instance
  (CanSqrt a
  , CanEnsureCE es a
  , CanEnsureCE es (SqrtType a)
  , SuitableForCE es)
  =>
  CanSqrt (CollectErrors es a)
  where
  type SqrtType (CollectErrors es a) = EnsureCE es (SqrtType a)
  sqrt :: CollectErrors es a -> SqrtType (CollectErrors es a)
sqrt = (a -> SqrtType a) -> CollectErrors es a -> EnsureCE es (SqrtType a)
forall es a c.
(SuitableForCE es, CanEnsureCE es a, CanEnsureCE es c) =>
(a -> c) -> CollectErrors es a -> EnsureCE es c
lift1CE a -> SqrtType a
forall t. CanSqrt t => t -> SqrtType t
sqrt


{----  exp -----}

{-|
  A replacement for Prelude's `P.exp`.  If @Floating t@,
  then one can use the default implementation to mirror Prelude's @exp@.
-}
class CanExp t where
  type ExpType t
  type ExpType t = t -- default
  exp :: t -> ExpType t
  default exp :: (ExpType t ~ t, P.Floating t) => t -> ExpType t
  exp = t -> ExpType t
forall a. Floating a => a -> a
P.exp

type CanExpSameType t = (CanExp t, ExpType t ~ t)

{-|
  HSpec properties that each implementation of CanExp should satisfy.
 -}
specCanExpReal ::
  (Show t, Show (ExpType t), Show (DivType Integer (ExpType t)),
   Show (ExpType (AddType t t)),
   Show (MulType (ExpType t) (ExpType t)),
   Show (EnsureCN (ExpType t)), Arbitrary t,
   CanEnsureCN (ExpType t),
   CanTestCertainly (OrderCompareType Integer t),
   CanTestCertainly (OrderCompareType t Integer),
   CanTestCertainly (OrderCompareType (ExpType t) Integer),
   CanTestCertainly
     (EqCompareType
        (EnsureCN (ExpType t)) (DivType Integer (ExpType t))),
   CanTestCertainly
     (EqCompareType
        (ExpType (AddType t t)) (MulType (ExpType t) (ExpType t))),
   CanNeg t,
   HasEqAsymmetric
     (ExpType (AddType t t)) (MulType (ExpType t) (ExpType t)),
   HasEqAsymmetric
     (EnsureCN (ExpType t)) (DivType Integer (ExpType t)),
   HasOrderAsymmetric t Integer,
   HasOrderAsymmetric (ExpType t) Integer,
   HasOrderAsymmetric Integer t, CanAddAsymmetric t t,
   CanMulAsymmetric (ExpType t) (ExpType t),
   CanDiv Integer (ExpType t), CanExp t, CanExp (AddType t t),
   NegType t ~ t, 
   CanEnforceRange t Integer) =>
   T t -> Spec
specCanExpReal :: T t -> Spec
specCanExpReal (T String
typeName :: T t) =
  String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe (String -> String -> String
forall r. PrintfType r => String -> r
printf String
"CanExp %s" String
typeName) (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
    String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"exp(x) >= 0" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
      (t -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((t -> Property) -> Property) -> (t -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (t
x_ :: t) ->
        let x :: t
x = (Maybe Integer, Maybe Integer) -> t -> t
forall t b. CanEnforceRange t b => (Maybe b, Maybe b) -> t -> t
enforceRange (Integer -> Maybe Integer
forall a. a -> Maybe a
Just (-Integer
100000), Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
100000) t
x_ in
          t -> ExpType t
forall t. CanExp t => t -> ExpType t
exp t
x ExpType t -> Integer -> Property
forall a b.
(HasOrderCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?>=?$ Integer
0
    String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"exp(-x) == 1/(exp x)" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
      (t -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((t -> Property) -> Property) -> (t -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (t
x_ :: t) ->
        let x :: t
x = (Maybe Integer, Maybe Integer) -> t -> t
forall t b. CanEnforceRange t b => (Maybe b, Maybe b) -> t -> t
enforceRange (Integer -> Maybe Integer
forall a. a -> Maybe a
Just (-Integer
100000), Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
100000) t
x_ in
        let ex :: ExpType t
ex = t -> ExpType t
forall t. CanExp t => t -> ExpType t
exp t
x in
          (ExpType t
ex ExpType t -> Integer -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
!>! Integer
0) Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
            (ExpType t -> EnsureCE NumErrors (ExpType t)
forall v. CanEnsureCN v => v -> EnsureCN v
ensureCN (ExpType t -> EnsureCE NumErrors (ExpType t))
-> ExpType t -> EnsureCE NumErrors (ExpType t)
forall a b. (a -> b) -> a -> b
$ t -> ExpType t
forall t. CanExp t => t -> ExpType t
exp (-t
x)) EnsureCE NumErrors (ExpType t)
-> DivType Integer (ExpType t) -> Property
forall a b.
(HasEqCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?==?$ Integer
1Integer -> ExpType t -> DivType Integer (ExpType t)
forall t1 t2. CanDiv t1 t2 => t1 -> t2 -> DivType t1 t2
/ExpType t
ex
    String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"exp(x+y) = exp(x)*exp(y)" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
      (t -> t -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((t -> t -> Property) -> Property)
-> (t -> t -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (t
x_ :: t)  (t
y_ :: t) ->
        let x :: t
x = (Maybe Integer, Maybe Integer) -> t -> t
forall t b. CanEnforceRange t b => (Maybe b, Maybe b) -> t -> t
enforceRange (Integer -> Maybe Integer
forall a. a -> Maybe a
Just (-Integer
100000), Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
100000) t
x_ in
        let y :: t
y = (Maybe Integer, Maybe Integer) -> t -> t
forall t b. CanEnforceRange t b => (Maybe b, Maybe b) -> t -> t
enforceRange (Integer -> Maybe Integer
forall a. a -> Maybe a
Just (-Integer
100000), Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
100000) t
y_ in
          (t -> ExpType t
forall t. CanExp t => t -> ExpType t
exp (t -> ExpType t) -> t -> ExpType t
forall a b. (a -> b) -> a -> b
$ t
x t -> t -> AddType t t
forall t1 t2. CanAddAsymmetric t1 t2 => t1 -> t2 -> AddType t1 t2
+ t
y) ExpType t -> MulType (ExpType t) (ExpType t) -> Property
forall a b.
(HasEqCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?==?$ (t -> ExpType t
forall t. CanExp t => t -> ExpType t
exp t
x) ExpType t -> ExpType t -> MulType (ExpType t) (ExpType t)
forall t1 t2. CanMulAsymmetric t1 t2 => t1 -> t2 -> MulType t1 t2
* (t -> ExpType t
forall t. CanExp t => t -> ExpType t
exp t
y)
  where
  infix 4 ?==?$
  (?==?$) :: (HasEqCertainlyAsymmetric a b, Show a, Show b) => a -> b -> Property
  ?==?$ :: a -> b -> Property
(?==?$) = String -> (a -> b -> Bool) -> a -> b -> Property
forall prop a b.
(Testable prop, Show a, Show b) =>
String -> (a -> b -> prop) -> a -> b -> Property
printArgsIfFails2 String
"?==?" a -> b -> Bool
forall a b. HasEqCertainlyAsymmetric a b => a -> b -> Bool
(?==?)
  infix 4 ?>=?$
  (?>=?$) :: (HasOrderCertainlyAsymmetric a b, Show a, Show b) => a -> b -> Property
  ?>=?$ :: a -> b -> Property
(?>=?$) = String -> (a -> b -> Bool) -> a -> b -> Property
forall prop a b.
(Testable prop, Show a, Show b) =>
String -> (a -> b -> prop) -> a -> b -> Property
printArgsIfFails2 String
"?>=?" a -> b -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
(?>=?)

{-
  Instances for Integer, Rational etc need an algebraic real or exact real type.
  Such type is not provided in this package. See eg aern2-real.
-}

instance CanExp Double -- not exact, will not pass the tests

instance
  (CanExp a
  , CanEnsureCE es a
  , CanEnsureCE es (ExpType a)
  , SuitableForCE es)
  =>
  CanExp (CollectErrors es a)
  where
  type ExpType (CollectErrors es a) = EnsureCE es (ExpType a)
  exp :: CollectErrors es a -> ExpType (CollectErrors es a)
exp = (a -> ExpType a) -> CollectErrors es a -> EnsureCE es (ExpType a)
forall es a c.
(SuitableForCE es, CanEnsureCE es a, CanEnsureCE es c) =>
(a -> c) -> CollectErrors es a -> EnsureCE es c
lift1CE a -> ExpType a
forall t. CanExp t => t -> ExpType t
exp

{----  log -----}

{-|
  A replacement for Prelude's `P.log`.  If @Floating t@,
  then one can use the default implementation to mirror Prelude's @log@.
-}
class CanLog t where
  type LogType t
  type LogType t = t -- default
  log :: t -> LogType t
  default log :: (LogType t ~ t, P.Floating t) => t -> LogType t
  log = t -> LogType t
forall a. Floating a => a -> a
P.log

type CanLogSameType t = (CanLog t, LogType t ~ t)
type CanLogCNSameType t = (CanLog t, LogType t ~ EnsureCN t)

{-|
  HSpec properties that each implementation of CanLog should satisfy.
 -}
specCanLogReal ::
  (Show t, Show (LogType t), Show (LogType (DivType Integer t)),
   Show (LogType (MulType t t)),
   Show (AddType (LogType t) (LogType t)), Show (LogType (ExpType t)),
   Arbitrary t, CanTestCertainly (OrderCompareType t Integer),
   CanTestCertainly (OrderCompareType (DivType Integer t) Integer),
   CanTestCertainly
     (EqCompareType (LogType (DivType Integer t)) (LogType t)),
   CanTestCertainly (OrderCompareType (MulType t t) Integer),
   CanTestCertainly (OrderCompareType (ExpType t) Integer),
   CanTestCertainly
     (EqCompareType
        (LogType (MulType t t)) (AddType (LogType t) (LogType t))),
   CanTestCertainly (OrderCompareType Integer t),
   CanTestCertainly (EqCompareType (LogType (ExpType t)) t),
   CanNeg (LogType t),
   HasEqAsymmetric (LogType (DivType Integer t)) (LogType t),
   HasEqAsymmetric
     (LogType (MulType t t)) (AddType (LogType t) (LogType t)),
   HasEqAsymmetric (LogType (ExpType t)) t,
   HasOrderAsymmetric t Integer,
   HasOrderAsymmetric (DivType Integer t) Integer,
   HasOrderAsymmetric (MulType t t) Integer,
   HasOrderAsymmetric (ExpType t) Integer,
   HasOrderAsymmetric Integer t,
   CanAddAsymmetric (LogType t) (LogType t), CanMulAsymmetric t t,
   CanDiv Integer t, CanExp t, CanLog t, CanLog (DivType Integer t),
   CanLog (MulType t t), CanLog (ExpType t),
   LogType t ~ NegType (LogType t),
   CanEnforceRange t Integer) =>
  T t -> Spec
specCanLogReal :: T t -> Spec
specCanLogReal (T String
typeName :: T t) =
  String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe (String -> String -> String
forall r. PrintfType r => String -> r
printf String
"CanLog %s" String
typeName) (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
    String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"log(1/x) == -(log x)" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
      (t -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((t -> Property) -> Property) -> (t -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (t
x_ :: t) ->
        let x :: t
x = (Maybe Integer, Maybe Integer) -> t -> t
forall t b. CanEnforceRange t b => (Maybe b, Maybe b) -> t -> t
enforceRange (Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
0, Maybe Integer
forall a. Maybe a
Nothing) t
x_ in
        t
x t -> Integer -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
!>! Integer
0 Bool -> Bool -> AndOrType Bool Bool
forall a b. CanAndOrAsymmetric a b => a -> b -> AndOrType a b
&& (Integer
1Integer -> t -> DivType Integer t
forall t1 t2. CanDiv t1 t2 => t1 -> t2 -> DivType t1 t2
/t
x) DivType Integer t -> Integer -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
!>! Integer
0  Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
          DivType Integer t -> LogType (DivType Integer t)
forall t. CanLog t => t -> LogType t
log (Integer
1Integer -> t -> DivType Integer t
forall t1 t2. CanDiv t1 t2 => t1 -> t2 -> DivType t1 t2
/t
x) LogType (DivType Integer t) -> NegType (LogType t) -> Property
forall a b.
(HasEqCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?==?$ -(t -> LogType t
forall t. CanLog t => t -> LogType t
log t
x)
    String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"log(x*y) = log(x)+log(y)" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
      (t -> t -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((t -> t -> Property) -> Property)
-> (t -> t -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (t
x_ :: t)  (t
y_ :: t) ->
        let x :: t
x = (Maybe Integer, Maybe Integer) -> t -> t
forall t b. CanEnforceRange t b => (Maybe b, Maybe b) -> t -> t
enforceRange (Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
0, Maybe Integer
forall a. Maybe a
Nothing) t
x_ in
        let y :: t
y = (Maybe Integer, Maybe Integer) -> t -> t
forall t b. CanEnforceRange t b => (Maybe b, Maybe b) -> t -> t
enforceRange (Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
0, Maybe Integer
forall a. Maybe a
Nothing) t
y_ in
        t
x t -> Integer -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
!>! Integer
0 Bool -> Bool -> AndOrType Bool Bool
forall a b. CanAndOrAsymmetric a b => a -> b -> AndOrType a b
&& t
y t -> Integer -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
!>! Integer
0 Bool -> Bool -> AndOrType Bool Bool
forall a b. CanAndOrAsymmetric a b => a -> b -> AndOrType a b
&& t
xt -> t -> MulType t t
forall t1 t2. CanMulAsymmetric t1 t2 => t1 -> t2 -> MulType t1 t2
*t
y MulType t t -> Integer -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
!>! Integer
0  Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
          (MulType t t -> LogType (MulType t t)
forall t. CanLog t => t -> LogType t
log (MulType t t -> LogType (MulType t t))
-> MulType t t -> LogType (MulType t t)
forall a b. (a -> b) -> a -> b
$ t
x t -> t -> MulType t t
forall t1 t2. CanMulAsymmetric t1 t2 => t1 -> t2 -> MulType t1 t2
* t
y) LogType (MulType t t)
-> AddType (NegType (LogType t)) (NegType (LogType t)) -> Property
forall a b.
(HasEqCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?==?$ (t -> LogType t
forall t. CanLog t => t -> LogType t
log t
x) NegType (LogType t)
-> NegType (LogType t)
-> AddType (NegType (LogType t)) (NegType (LogType t))
forall t1 t2. CanAddAsymmetric t1 t2 => t1 -> t2 -> AddType t1 t2
+ (t -> LogType t
forall t. CanLog t => t -> LogType t
log t
y)
    String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"log(exp x) == x" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
      (t -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((t -> Property) -> Property) -> (t -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (t
x_ :: t) ->
        let x :: t
x = (Maybe Integer, Maybe Integer) -> t -> t
forall t b. CanEnforceRange t b => (Maybe b, Maybe b) -> t -> t
enforceRange (Integer -> Maybe Integer
forall a. a -> Maybe a
Just (-Integer
1000), Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
10000) t
x_ in
        let ex :: ExpType t
ex = t -> ExpType t
forall t. CanExp t => t -> ExpType t
exp t
x in
          (ExpType t
ex ExpType t -> Integer -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
!>! Integer
0) Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
            ExpType t -> LogType (ExpType t)
forall t. CanLog t => t -> LogType t
log ExpType t
ex LogType (ExpType t) -> t -> Property
forall a b.
(HasEqCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?==?$ t
x
  where
  infix 4 ?==?$
  (?==?$) :: (HasEqCertainlyAsymmetric a b, Show a, Show b) => a -> b -> Property
  ?==?$ :: a -> b -> Property
(?==?$) = String -> (a -> b -> Bool) -> a -> b -> Property
forall prop a b.
(Testable prop, Show a, Show b) =>
String -> (a -> b -> prop) -> a -> b -> Property
printArgsIfFails2 String
"?==?" a -> b -> Bool
forall a b. HasEqCertainlyAsymmetric a b => a -> b -> Bool
(?==?)

{-
  Instances for Integer, Rational etc need an algebraic real or exact real type.
  Such type is not provided in this package. See eg aern2-real.
-}

instance CanLog Double -- not exact, will not pass the tests

instance
  (CanLog a
  , CanEnsureCE es a
  , CanEnsureCE es (LogType a)
  , SuitableForCE es)
  =>
  CanLog (CollectErrors es a)
  where
  type LogType (CollectErrors es a) = EnsureCE es (LogType a)
  log :: CollectErrors es a -> LogType (CollectErrors es a)
log = (a -> LogType a) -> CollectErrors es a -> EnsureCE es (LogType a)
forall es a c.
(SuitableForCE es, CanEnsureCE es a, CanEnsureCE es c) =>
(a -> c) -> CollectErrors es a -> EnsureCE es c
lift1CE a -> LogType a
forall t. CanLog t => t -> LogType t
log

instance CanPow Double Double where
  powNoCN :: Double -> Double -> PowTypeNoCN Double Double
powNoCN = Double -> Double -> PowTypeNoCN Double Double
forall a. Floating a => a -> a -> a
(P.**)
  type PowType Double Double = Double
  pow :: Double -> Double -> PowType Double Double
pow = Double -> Double -> PowType Double Double
forall a. Floating a => a -> a -> a
(P.**)
instance CanPow Double Rational where
  powNoCN :: Double -> Rational -> PowTypeNoCN Double Rational
powNoCN Double
b Rational
e = Double
b Double -> Double -> PowTypeNoCN Double Double
forall t1 t2. CanPow t1 t2 => t1 -> t2 -> PowTypeNoCN t1 t2
^! (Rational -> Double
forall t. CanBeDouble t => t -> Double
double Rational
e)
  type PowType Double Rational = Double
  pow :: Double -> Rational -> PowType Double Rational
pow Double
b Rational
e = Double
b Double -> Double -> PowType Double Double
forall t1 t2. CanPow t1 t2 => t1 -> t2 -> PowType t1 t2
^ (Rational -> Double
forall t. CanBeDouble t => t -> Double
double Rational
e)
instance CanPow Rational Double where
  type PowTypeNoCN Rational Double = Double
  powNoCN :: Rational -> Double -> PowTypeNoCN Rational Double
powNoCN Rational
b Double
e = (Rational -> Double
forall t. CanBeDouble t => t -> Double
double Rational
b) Double -> Double -> PowTypeNoCN Double Double
forall t1 t2. CanPow t1 t2 => t1 -> t2 -> PowTypeNoCN t1 t2
^! Double
e
  type PowType Rational Double = Double
  pow :: Rational -> Double -> PowType Rational Double
pow Rational
b Double
e = (Rational -> Double
forall t. CanBeDouble t => t -> Double
double Rational
b) Double -> Double -> PowType Double Double
forall t1 t2. CanPow t1 t2 => t1 -> t2 -> PowType t1 t2
^ Double
e
instance CanPow Integer Double where
  type PowTypeNoCN Integer Double = Double
  powNoCN :: Integer -> Double -> PowTypeNoCN Integer Double
powNoCN Integer
b Double
e = (Integer -> Double
forall t. CanBeDouble t => t -> Double
double Integer
b) Double -> Double -> PowTypeNoCN Double Double
forall t1 t2. CanPow t1 t2 => t1 -> t2 -> PowTypeNoCN t1 t2
^! Double
e
  type PowType Integer Double = Double
  pow :: Integer -> Double -> PowType Integer Double
pow Integer
b Double
e = (Integer -> Double
forall t. CanBeDouble t => t -> Double
double Integer
b) Double -> Double -> PowType Double Double
forall t1 t2. CanPow t1 t2 => t1 -> t2 -> PowType t1 t2
^ Double
e
instance CanPow Int Double where
  type PowTypeNoCN Int Double = Double
  powNoCN :: Int -> Double -> PowTypeNoCN Int Double
powNoCN Int
b Double
e = (Int -> Double
forall t. CanBeDouble t => t -> Double
double Int
b) Double -> Double -> PowTypeNoCN Double Double
forall t1 t2. CanPow t1 t2 => t1 -> t2 -> PowTypeNoCN t1 t2
^! Double
e
  type PowType Int Double = Double
  pow :: Int -> Double -> PowType Int Double
pow Int
b Double
e = (Int -> Double
forall t. CanBeDouble t => t -> Double
double Int
b) Double -> Double -> PowType Double Double
forall t1 t2. CanPow t1 t2 => t1 -> t2 -> PowType t1 t2
^ Double
e

powUsingExpLog ::
  (CanTestPosNeg t,
   CanEnsureCN t,
   CanEnsureCN (EnsureCN t),
   EnsureCN t ~ EnsureCN (EnsureCN t),
   CanLogCNSameType t,
   CanMulSameType t,
   CanMulSameType (EnsureCN t),
   CanExpSameType (EnsureCN t),
   CanTestInteger t,
   CanTestZero t,
   CanRecipCNSameType t)
  =>
  t -> t -> t -> t -> EnsureCN t
powUsingExpLog :: t -> t -> t -> t -> EnsureCN t
powUsingExpLog t
zero t
one t
b t
e =
  case t -> Maybe Integer
forall t. CanTestInteger t => t -> Maybe Integer
certainlyIntegerGetIt t
e of
    Just Integer
n ->
      t -> t -> Integer -> EnsureCN t
forall e t.
(CanBeInteger e, CanRecipCNSameType t, CanMulSameType t,
 CanEnsureCN t) =>
t -> t -> e -> EnsureCN t
powUsingMulRecip t
one t
b Integer
n
    Maybe Integer
Nothing
      | t -> Bool
forall t. CanTestZero t => t -> Bool
isCertainlyZero t
b Bool -> Bool -> AndOrType Bool Bool
forall a b. CanAndOrAsymmetric a b => a -> b -> AndOrType a b
&& t -> Bool
forall t. CanTestPosNeg t => t -> Bool
isCertainlyPositive t
e -> t -> EnsureCN t
forall v. CanEnsureCN v => v -> EnsureCN v
cn t
zero
      | t -> Bool
forall t. CanTestPosNeg t => t -> Bool
isCertainlyNonNegative t
b -> EnsureCE NumErrors (EnsureCN t)
-> ExpType (EnsureCE NumErrors (EnsureCN t))
forall t. CanExp t => t -> ExpType t
exp ((t -> LogType t
forall t. CanLog t => t -> LogType t
log t
b) EnsureCE NumErrors (EnsureCN t)
-> EnsureCE NumErrors (EnsureCN t)
-> MulType
     (EnsureCE NumErrors (EnsureCN t)) (EnsureCE NumErrors (EnsureCN t))
forall t1 t2. CanMulAsymmetric t1 t2 => t1 -> t2 -> MulType t1 t2
* (t -> EnsureCN t
forall v. CanEnsureCN v => v -> EnsureCN v
ensureCN t
e))
      | t -> Bool
forall t. CanTestPosNeg t => t -> Bool
isCertainlyNegative t
b Bool -> Bool -> AndOrType Bool Bool
forall a b. CanAndOrAsymmetric a b => a -> b -> AndOrType a b
&& t -> Bool
forall t. CanTestInteger t => t -> Bool
certainlyNotInteger t
e -> Maybe t -> NumError -> EnsureCN t
forall v. CanEnsureCN v => Maybe v -> NumError -> EnsureCN v
noValueNumErrorCertainECN (t -> Maybe t
forall a. a -> Maybe a
Just t
b) NumError
err
      | Bool
otherwise -> Maybe t -> NumError -> EnsureCN t
forall v. CanEnsureCN v => Maybe v -> NumError -> EnsureCN v
noValueNumErrorPotentialECN (t -> Maybe t
forall a. a -> Maybe a
Just t
b) NumError
err
  where
  err :: NumError
err = String -> NumError
NumError String
"powUsingExpLog: illegal power a^b with negative a and non-integer b"

{----  sine and cosine -----}

{-|
  A replacement for Prelude's `P.cos` and `P.sin`.  If @Floating t@,
  then one can use the default implementation to mirror Prelude's @sin@, @cos@.
-}
class CanSinCos t where
  type SinCosType t
  type SinCosType t = t -- default
  cos :: t -> SinCosType t
  default cos :: (SinCosType t ~ t, P.Floating t) => t -> SinCosType t
  cos = t -> SinCosType t
forall a. Floating a => a -> a
P.cos
  sin :: t -> SinCosType t
  default sin :: (SinCosType t ~ t, P.Floating t) => t -> SinCosType t
  sin = t -> SinCosType t
forall a. Floating a => a -> a
P.sin

type CanSinCosSameType t = (CanSinCos t, SinCosType t ~ t)

{-|
  HSpec properties that each implementation of CanSinCos should satisfy.

  Derived partially from
  http://math.stackexchange.com/questions/1303044/axiomatic-definition-of-sin-and-cos
 -}
specCanSinCosReal ::
 (Show t, Show (SinCosType t),
  Show
    (AddType
       (PowType (SinCosType t) Integer) (PowType (SinCosType t) Integer)),
  Show (SinCosType (SubType t t)),
  Show
    (SubType
       (MulType (SinCosType t) (SinCosType t))
       (MulType (SinCosType t) (SinCosType t))),
  Show
    (AddType
       (MulType (SinCosType t) (SinCosType t))
       (MulType (SinCosType t) (SinCosType t))),
  Show (DivType (SinCosType t) (SinCosType t)),
  Show (EnsureCN t), Arbitrary t, CanEnsureCN t,
  CanTestCertainly (OrderCompareType Integer (SinCosType t)),
  CanTestCertainly (OrderCompareType (SinCosType t) Integer),
  CanTestCertainly
    (EqCompareType
       (AddType
          (PowType (SinCosType t) Integer)
          (PowType (SinCosType t) Integer))
       Integer),
  CanTestCertainly
    (EqCompareType
       (SinCosType (SubType t t))
       (SubType
          (MulType (SinCosType t) (SinCosType t))
          (MulType (SinCosType t) (SinCosType t)))),
  CanTestCertainly
    (EqCompareType
       (SinCosType (SubType t t))
       (AddType
          (MulType (SinCosType t) (SinCosType t))
          (MulType (SinCosType t) (SinCosType t)))),
  CanTestCertainly (OrderCompareType t Integer),
  CanTestCertainly (OrderCompareType t Rational),
  CanTestCertainly (OrderCompareType (SinCosType t) t),
  CanTestCertainly
    (OrderCompareType
       (EnsureCN t) (DivType (SinCosType t) (SinCosType t))),
  HasEqAsymmetric
    (AddType
       (PowType (SinCosType t) Integer) (PowType (SinCosType t) Integer))
    Integer,
  HasEqAsymmetric
    (SinCosType (SubType t t))
    (SubType
       (MulType (SinCosType t) (SinCosType t))
       (MulType (SinCosType t) (SinCosType t))),
  HasEqAsymmetric
    (SinCosType (SubType t t))
    (AddType
       (MulType (SinCosType t) (SinCosType t))
       (MulType (SinCosType t) (SinCosType t))),
  HasOrderAsymmetric t Integer, HasOrderAsymmetric t Rational,
  HasOrderAsymmetric (SinCosType t) t,
  HasOrderAsymmetric (SinCosType t) Integer,
  HasOrderAsymmetric
    (EnsureCN t) (DivType (SinCosType t) (SinCosType t)),
  HasOrderAsymmetric Integer (SinCosType t), CanSub t t,
  CanSub
    (MulType (SinCosType t) (SinCosType t))
    (MulType (SinCosType t) (SinCosType t)),
  CanAddAsymmetric
    (PowType (SinCosType t) Integer) (PowType (SinCosType t) Integer),
  CanAddAsymmetric
    (MulType (SinCosType t) (SinCosType t))
    (MulType (SinCosType t) (SinCosType t)),
  CanPow (SinCosType t) Integer,
  CanMulAsymmetric (SinCosType t) (SinCosType t),
  CanDiv (SinCosType t) (SinCosType t), CanSinCos t,
  CanSinCos (SubType t t))
  =>
  T t -> Spec
specCanSinCosReal :: T t -> Spec
specCanSinCosReal (T String
typeName :: T t) =
  String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe (String -> String -> String
forall r. PrintfType r => String -> r
printf String
"CanSinCos %s" String
typeName) (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
    String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"-1 <= sin(x) <= 1" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
      (t -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((t -> Property) -> Property) -> (t -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (t
x :: t) ->
          (-Integer
1) Integer -> SinCosType t -> Property
forall a b.
(HasOrderCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?<=?$ (t -> SinCosType t
forall t. CanSinCos t => t -> SinCosType t
sin t
x) Property -> Property -> Property
forall prop1 prop2.
(Testable prop1, Testable prop2) =>
prop1 -> prop2 -> Property
.&&. (t -> SinCosType t
forall t. CanSinCos t => t -> SinCosType t
sin t
x) SinCosType t -> Integer -> Property
forall a b.
(HasOrderCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?<=?$ Integer
1
    String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"-1 <= cos(x) <= 1" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
      (t -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((t -> Property) -> Property) -> (t -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (t
x :: t) ->
          (-Integer
1) Integer -> SinCosType t -> Property
forall a b.
(HasOrderCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?<=?$ (t -> SinCosType t
forall t. CanSinCos t => t -> SinCosType t
cos t
x) Property -> Property -> Property
forall prop1 prop2.
(Testable prop1, Testable prop2) =>
prop1 -> prop2 -> Property
.&&. (t -> SinCosType t
forall t. CanSinCos t => t -> SinCosType t
cos t
x) SinCosType t -> Integer -> Property
forall a b.
(HasOrderCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?<=?$ Integer
1
    String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"cos(x)^2 + sin(x)^2 = 1" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
      (t -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((t -> Property) -> Property) -> (t -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (t
x :: t) ->
          (t -> SinCosType t
forall t. CanSinCos t => t -> SinCosType t
sin t
x)SinCosType t -> Integer -> PowType (SinCosType t) Integer
forall t1 t2. CanPow t1 t2 => t1 -> t2 -> PowType t1 t2
^Integer
2 PowType (SinCosType t) Integer
-> PowType (SinCosType t) Integer
-> AddType
     (PowType (SinCosType t) Integer) (PowType (SinCosType t) Integer)
forall t1 t2. CanAddAsymmetric t1 t2 => t1 -> t2 -> AddType t1 t2
+ (t -> SinCosType t
forall t. CanSinCos t => t -> SinCosType t
cos t
x)SinCosType t -> Integer -> PowType (SinCosType t) Integer
forall t1 t2. CanPow t1 t2 => t1 -> t2 -> PowType t1 t2
^Integer
2 AddType
  (PowType (SinCosType t) Integer) (PowType (SinCosType t) Integer)
-> Integer -> Property
forall a b.
(HasEqCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?==?$ Integer
1
    String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"sin(x-y) = sin(x)cos(y) - cos(x)sin(y)" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
      (t -> t -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((t -> t -> Property) -> Property)
-> (t -> t -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (t
x :: t) (t
y :: t) ->
          (SubType t t -> SinCosType (SubType t t)
forall t. CanSinCos t => t -> SinCosType t
sin (SubType t t -> SinCosType (SubType t t))
-> SubType t t -> SinCosType (SubType t t)
forall a b. (a -> b) -> a -> b
$ t
x t -> t -> SubType t t
forall t1 t2. CanSub t1 t2 => t1 -> t2 -> SubType t1 t2
- t
y) SinCosType (SubType t t)
-> SubType
     (MulType (SinCosType t) (SinCosType t))
     (MulType (SinCosType t) (SinCosType t))
-> Property
forall a b.
(HasEqCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?==?$ (t -> SinCosType t
forall t. CanSinCos t => t -> SinCosType t
sin t
x)SinCosType t
-> SinCosType t -> MulType (SinCosType t) (SinCosType t)
forall t1 t2. CanMulAsymmetric t1 t2 => t1 -> t2 -> MulType t1 t2
*(t -> SinCosType t
forall t. CanSinCos t => t -> SinCosType t
cos t
y) MulType (SinCosType t) (SinCosType t)
-> MulType (SinCosType t) (SinCosType t)
-> SubType
     (MulType (SinCosType t) (SinCosType t))
     (MulType (SinCosType t) (SinCosType t))
forall t1 t2. CanSub t1 t2 => t1 -> t2 -> SubType t1 t2
- (t -> SinCosType t
forall t. CanSinCos t => t -> SinCosType t
cos t
x)SinCosType t
-> SinCosType t -> MulType (SinCosType t) (SinCosType t)
forall t1 t2. CanMulAsymmetric t1 t2 => t1 -> t2 -> MulType t1 t2
*(t -> SinCosType t
forall t. CanSinCos t => t -> SinCosType t
sin t
y)
    String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"cos(x-y) = cos(x)cos(y) + sin(x)sin(y)" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
      (t -> t -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((t -> t -> Property) -> Property)
-> (t -> t -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (t
x :: t) (t
y :: t) ->
          (SubType t t -> SinCosType (SubType t t)
forall t. CanSinCos t => t -> SinCosType t
cos (SubType t t -> SinCosType (SubType t t))
-> SubType t t -> SinCosType (SubType t t)
forall a b. (a -> b) -> a -> b
$ t
x t -> t -> SubType t t
forall t1 t2. CanSub t1 t2 => t1 -> t2 -> SubType t1 t2
- t
y) SinCosType (SubType t t)
-> AddType
     (MulType (SinCosType t) (SinCosType t))
     (MulType (SinCosType t) (SinCosType t))
-> Property
forall a b.
(HasEqCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?==?$ (t -> SinCosType t
forall t. CanSinCos t => t -> SinCosType t
cos t
x)SinCosType t
-> SinCosType t -> MulType (SinCosType t) (SinCosType t)
forall t1 t2. CanMulAsymmetric t1 t2 => t1 -> t2 -> MulType t1 t2
*(t -> SinCosType t
forall t. CanSinCos t => t -> SinCosType t
cos t
y) MulType (SinCosType t) (SinCosType t)
-> MulType (SinCosType t) (SinCosType t)
-> AddType
     (MulType (SinCosType t) (SinCosType t))
     (MulType (SinCosType t) (SinCosType t))
forall t1 t2. CanAddAsymmetric t1 t2 => t1 -> t2 -> AddType t1 t2
+ (t -> SinCosType t
forall t. CanSinCos t => t -> SinCosType t
sin t
x)SinCosType t
-> SinCosType t -> MulType (SinCosType t) (SinCosType t)
forall t1 t2. CanMulAsymmetric t1 t2 => t1 -> t2 -> MulType t1 t2
*(t -> SinCosType t
forall t. CanSinCos t => t -> SinCosType t
sin t
y)
    String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"sin(x) < x < tan(x) for x in [0,pi/2]" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
      (t -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((t -> Property) -> Property) -> (t -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (t
x :: t) ->
        t
x t -> Integer -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
!>=! Integer
0 Bool -> Bool -> AndOrType Bool Bool
forall a b. CanAndOrAsymmetric a b => a -> b -> AndOrType a b
&& t
x t -> Rational -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
!<=! Rational
1.57 Bool -> Bool -> AndOrType Bool Bool
forall a b. CanAndOrAsymmetric a b => a -> b -> AndOrType a b
&& (t -> SinCosType t
forall t. CanSinCos t => t -> SinCosType t
cos t
x) SinCosType t -> Integer -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
!>! Integer
0 Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
          (t -> SinCosType t
forall t. CanSinCos t => t -> SinCosType t
sin t
x) SinCosType t -> t -> Property
forall a b.
(HasOrderCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?<=?$ t
x Property -> Property -> Property
forall prop1 prop2.
(Testable prop1, Testable prop2) =>
prop1 -> prop2 -> Property
.&&. (t -> EnsureCE NumErrors t
forall v. CanEnsureCN v => v -> EnsureCN v
ensureCN t
x) EnsureCE NumErrors t
-> DivType (SinCosType t) (SinCosType t) -> Property
forall a b.
(HasOrderCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?<=?$ (t -> SinCosType t
forall t. CanSinCos t => t -> SinCosType t
sin t
x)SinCosType t
-> SinCosType t -> DivType (SinCosType t) (SinCosType t)
forall t1 t2. CanDiv t1 t2 => t1 -> t2 -> DivType t1 t2
/(t -> SinCosType t
forall t. CanSinCos t => t -> SinCosType t
cos t
x)
  where
  infix 4 ?==?$
  (?==?$) :: (HasEqCertainlyAsymmetric a b, Show a, Show b) => a -> b -> Property
  ?==?$ :: a -> b -> Property
(?==?$) = String -> (a -> b -> Bool) -> a -> b -> Property
forall prop a b.
(Testable prop, Show a, Show b) =>
String -> (a -> b -> prop) -> a -> b -> Property
printArgsIfFails2 String
"?==?" a -> b -> Bool
forall a b. HasEqCertainlyAsymmetric a b => a -> b -> Bool
(?==?)
  infix 4 ?<=?$
  (?<=?$) :: (HasOrderCertainlyAsymmetric a b, Show a, Show b) => a -> b -> Property
  ?<=?$ :: a -> b -> Property
(?<=?$) = String -> (a -> b -> Bool) -> a -> b -> Property
forall prop a b.
(Testable prop, Show a, Show b) =>
String -> (a -> b -> prop) -> a -> b -> Property
printArgsIfFails2 String
"?<=?" a -> b -> Bool
forall a b. HasOrderCertainlyAsymmetric a b => a -> b -> Bool
(?<=?)

{-
  Instances for Integer, Rational etc need an algebraic real or exact real type.
  Such type is not provided in this package. See eg aern2-real.
-}

instance CanSinCos Double -- not exact, will not pass the tests

instance
  (CanSinCos a
  , CanEnsureCE es a
  , CanEnsureCE es (SinCosType a)
  , SuitableForCE es)
  =>
  CanSinCos (CollectErrors es a)
  where
  type SinCosType (CollectErrors es a) = EnsureCE es (SinCosType a)
  sin :: CollectErrors es a -> SinCosType (CollectErrors es a)
sin = (a -> SinCosType a)
-> CollectErrors es a -> EnsureCE es (SinCosType a)
forall es a c.
(SuitableForCE es, CanEnsureCE es a, CanEnsureCE es c) =>
(a -> c) -> CollectErrors es a -> EnsureCE es c
lift1CE a -> SinCosType a
forall t. CanSinCos t => t -> SinCosType t
sin
  cos :: CollectErrors es a -> SinCosType (CollectErrors es a)
cos = (a -> SinCosType a)
-> CollectErrors es a -> EnsureCE es (SinCosType a)
forall es a c.
(SuitableForCE es, CanEnsureCE es a, CanEnsureCE es c) =>
(a -> c) -> CollectErrors es a -> EnsureCE es c
lift1CE a -> SinCosType a
forall t. CanSinCos t => t -> SinCosType t
cos

{-|
  Approximate pi, synonym for Prelude's `P.pi`.

  We do not define (exect) @pi@ in this package as we have no type
  that can represent it exactly.
-}
approxPi :: (P.Floating t) => t
approxPi :: t
approxPi = t
forall a. Floating a => a
P.pi