aern2-mp-0.2.1.0: src/AERN2/MP/WithCurrentPrec.hs
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE StandaloneDeriving #-}
{-|
Module : AERN2.MP.WithCurrentPrec
Description : Type wrapper setting default precision
Copyright : (c) Michal Konecny
License : BSD3
Maintainer : mikkonecny@gmail.com
Stability : experimental
Portability : portable
Type wrapper setting default precision.
Not suitable for use with MixedTypesNumPrelude since we need binary operators to enforce
the same precision on both operands via the equality of their types.
Borrowed some tricks from https://github.com/ekmett/rounded/blob/master/src/Numeric/Rounded/Precision.hs
-}
module AERN2.MP.WithCurrentPrec
(
WithCurrentPrec(..), runWithPrec, HasCurrentPrecision(..)
, WithAnyPrec(..)
-- , _example1 , _example2 , _example3
)
where
import qualified MixedTypesNumPrelude as MxP
import Prelude
-- import Text.Printf
-- import Text.Printf
import Numeric.CollectErrors (CN, cn, NumErrors, CanTakeErrors(..))
-- import qualified Numeric.CollectErrors as CN
import Data.Proxy
import Data.Reflection
import GHC.TypeLits
-- import Data.Complex
import AERN2.Limit
import AERN2.MP.Precision
import AERN2.MP.Ball
class HasCurrentPrecision p where
getCurrentPrecision :: proxy p -> Precision
instance KnownNat n => HasCurrentPrecision n where
getCurrentPrecision p = max (prec 2) . min maximumPrecision $ prec (natVal p)
{-|
An existential type wrapper for convenient conversions, eg using aern2-real:
> _x :: KnownNat p => WithCurrentPrec (CN MPBall) p
> _x = undefined
>
> _r_x :: CReal
> _r_x = creal $ WithAnyPrec _x
-}
newtype WithAnyPrec t = WithAnyPrec (forall p. (KnownNat p) => WithCurrentPrec t p)
-- data PrecAdd10 (p :: *)
-- instance (HasCurrentPrecision p) => HasCurrentPrecision (PrecAdd10 p) where
-- isPrecision (_ :: proxy _) = 10 + isPrecision (undefined :: proxy p)
newtype WithCurrentPrec t p = WithCurrentPrec { unWithCurrentPrec :: t }
deriving (Show)
deriving instance (CanTakeErrors NumErrors t) => (CanTakeErrors NumErrors (WithCurrentPrec t p))
runWithPrec :: Precision -> (forall n. (KnownNat n) => WithCurrentPrec t n) -> t
runWithPrec p (wfp :: (forall n. (KnownNat n) => WithCurrentPrec t n)) =
reifyNat (MxP.integer p) withNat
where
withNat :: KnownNat n => Proxy n -> t
withNat (_ :: Proxy n) =
unWithCurrentPrec (wfp :: WithCurrentPrec t n)
-- -- The following does not work:
-- instance (CanAddAsymmetric t1 t2) => (CanAddAsymmetric (WithCurrentPrec t1 p) (WithCurrentPrec t2 p)) where
-- type AddType (WithCurrentPrec t1 p) (WithCurrentPrec t2 p) = WithCurrentPrec (AddType t1 t2) p
-- add (WithCurrentPrec a1) (WithCurrentPrec a2) = WithCurrentPrec $ a1 + a2
instance
(MxP.HasOrderAsymmetric t1 t2)
=>
MxP.HasOrderAsymmetric (WithCurrentPrec t1 p1) (WithCurrentPrec t2 p2)
where
type OrderCompareType (WithCurrentPrec t1 p1) (WithCurrentPrec t2 p2) = MxP.OrderCompareType t1 t2
greaterThan (WithCurrentPrec v1) (WithCurrentPrec v2) = MxP.greaterThan v1 v2
lessThan (WithCurrentPrec v1) (WithCurrentPrec v2) = MxP.lessThan v1 v2
geq (WithCurrentPrec v1) (WithCurrentPrec v2) = MxP.geq v1 v2
leq (WithCurrentPrec v1) (WithCurrentPrec v2) = MxP.leq v1 v2
instance
(MxP.CanMinMaxAsymmetric t1 t2, p1 ~ p2)
=>
MxP.CanMinMaxAsymmetric (WithCurrentPrec t1 p1) (WithCurrentPrec t2 p2)
where
type MinMaxType (WithCurrentPrec t1 p1) (WithCurrentPrec t2 p2) = WithCurrentPrec (MxP.MinMaxType t1 t2) p1
min (WithCurrentPrec v1) (WithCurrentPrec v2) = WithCurrentPrec $ MxP.min v1 v2
max (WithCurrentPrec v1) (WithCurrentPrec v2) = WithCurrentPrec $ MxP.max v1 v2
instance Eq t => Eq (WithCurrentPrec t p) where
(==) = lift2P (==)
instance Ord t => Ord (WithCurrentPrec t p) where
compare = lift2P compare
instance
(HasCurrentPrecision p, Num t, ConvertibleWithPrecision Integer t)
=>
Num (WithCurrentPrec t p)
where
fromInteger n = r
where
r = WithCurrentPrec $ convertP (getCurrentPrecision r) n
negate = lift1 negate
abs = lift1 abs
(+) = lift2 (+)
(*) = lift2 (*)
signum = lift1 signum
instance
(HasCurrentPrecision p, Fractional t
, ConvertibleWithPrecision Integer t, ConvertibleWithPrecision Rational t)
=>
Fractional (WithCurrentPrec t p)
where
fromRational q = r
where
r = WithCurrentPrec $ convertP (getCurrentPrecision r) q
recip = lift1 recip
(/) = lift2 (/)
instance (HasCurrentPrecision p) => Floating (WithCurrentPrec (CN MPBall) p) where
pi = r
where
r = WithCurrentPrec $ cn $ piBallP (getCurrentPrecision r)
sqrt = lift1 sqrt
exp = lift1 exp
log = lift1 log
sin = lift1 sin
cos = lift1 cos
asin = lift1 asin
acos = lift1 acos
atan = lift1 atan
sinh = lift1 sinh
cosh = lift1 cosh
asinh = lift1 asinh
acosh = lift1 acosh
atanh = lift1 atanh
instance
(HasLimits ix (CN MPBall -> CN MPBall)
, LimitType ix (CN MPBall -> CN MPBall) ~ (CN MPBall -> CN MPBall)
,HasCurrentPrecision p)
=>
HasLimits ix (WithCurrentPrec (CN MPBall) p)
where
type LimitType ix (WithCurrentPrec (CN MPBall) p) = WithCurrentPrec (CN MPBall) p
limit (s :: ix -> (WithCurrentPrec (CN MPBall) p)) =
WithCurrentPrec $ limit (snop) $ sample
where
sample :: CN MPBall
sample = setPrecision (getCurrentPrecision sampleP) 0
sampleP :: WithCurrentPrec MPBall p
sampleP = error "sampleP is not defined, it is only a type proxy"
snop :: ix -> (CN MPBall -> CN MPBall)
snop ix _sample = unWithCurrentPrec $ s ix
lift1 :: (t1 -> t2) -> (WithCurrentPrec t1 p) -> (WithCurrentPrec t2 p)
lift1 f (WithCurrentPrec v1) = WithCurrentPrec (f v1)
lift2 :: (t1 -> t2 -> t3) -> (WithCurrentPrec t1 p) -> (WithCurrentPrec t2 p) -> (WithCurrentPrec t3 p)
lift2 f (WithCurrentPrec v1) (WithCurrentPrec v2) = WithCurrentPrec (f v1 v2)
lift2P :: (t1 -> t2 -> t3) -> (WithCurrentPrec t1 p) -> (WithCurrentPrec t2 p) -> t3
lift2P f (WithCurrentPrec v1) (WithCurrentPrec v2) = f v1 v2
_example1 :: CN MPBall
_example1 = runWithPrec (prec 1000) pi
_example2 :: CN MPBall
_example2 = runWithPrec (prec 1000) $ pi - pi
_example3 :: CN MPBall
_example3 = runWithPrec (prec 1000) $ sqrt 2