aern2-fun-0.2.9.0: src/AERN2/RealFun/Operations.hs
{-# LANGUAGE CPP #-}
-- #define DEBUG
{-# LANGUAGE PartialTypeSignatures #-}
{-# OPTIONS_GHC -Wno-partial-type-signatures #-}
{-|
Module : AERN2.RealFun.Operations
Description : Classes for real number function operations
Copyright : (c) Michal Konecny
License : BSD3
Maintainer : mikkonecny@gmail.com
Stability : experimental
Portability : portable
Classes for real number function operations
-}
module AERN2.RealFun.Operations
(
HasDomain(..)
, SameDomFnPair(..), ArbitraryWithDom(..)
, CanApply(..)
, CanApplyApprox(..), sampledRange
, HasFnConstructorInfo(..)
, HasConstFunctions, constFn, specEvalConstFn
, HasVars(..), specEvalUnaryVarFn
, CanMaximiseOverDom(..), CanMinimiseOverDom(..)
, specCanMaximiseOverDom
, CanIntegrateOverDom(..)
)
where
#ifdef DEBUG
import Debug.Trace (trace)
#define maybeTrace trace
#define maybeTraceIO putStrLn
#else
#define maybeTrace (\ (_ :: String) t -> t)
#define maybeTraceIO (\ (_ :: String) -> return ())
#endif
import MixedTypesNumPrelude
-- import qualified Prelude as P
import Text.Printf
-- import Data.Typeable
-- import qualified Data.List as List
import Test.Hspec
import Test.QuickCheck
import AERN2.Interval
import AERN2.MP.Dyadic
import AERN2.MP.Enclosure
{- domain -}
class HasDomain f where
type Domain f
getDomain :: f -> Domain f
data SameDomFnPair f = SameDomFnPair (f,f) deriving Show
instance (ArbitraryWithDom f, Arbitrary f) => (Arbitrary (SameDomFnPair f)) where
arbitrary =
do
f1 <- arbitrary
f2 <- arbitraryWithDom (getDomain f1)
return $ SameDomFnPair (f1,f2)
class (HasDomain f) => ArbitraryWithDom f where
arbitraryWithDom :: (Domain f) -> Gen f
{- evaluation -}
class CanApply f x where
type ApplyType f x
{-| compute @f(x)@ -}
apply :: f {-^ @f@ -} -> x {-^ @x@ -} -> ApplyType f x
{-|
Give an unsafe etimate of the function's range which is fast to compute.
Intended to be used in optimisation heuristics.
-}
class CanApplyApprox f x where
type ApplyApproxType f x
{-| compute a cheap and unsafe approximation of @f(x)@ -}
applyApprox :: f {-^ @f@ -} -> x {-^ @x@ -} -> ApplyApproxType f x
{-|
Evaluate a function on a regular grid of the given size and return
the largerst and smallest values found. Useful for making instances
of class 'CanApplyApprox'.
-}
sampledRange ::
(CanApply f t, ApplyType f t ~ t,
CanMinMaxSameType t, ConvertibleExactly Dyadic t, Show t)
=>
DyadicInterval -> Integer -> f -> Interval t t
sampledRange (Interval l r) depth f =
maybeTrace
( "sampledRange:"
++ "\n samplePointsT = " ++ (show samplePointsT)
++ "\n samples = " ++ show samples
) $
Interval minValue maxValue
where
minValue = foldl1 min samples
maxValue = foldl1 max samples
samples = map (apply f) samplePointsT
samplePointsT = map convertExactly samplePoints
_ = minValue : samplePointsT
samplePoints :: [Dyadic]
samplePoints = [(l*i + r*(size - i))*(dyadic (1/size)) | i <- [0..size]]
size = 2^depth
{- constructing basic functions -}
class HasFnConstructorInfo f where
type FnConstructorInfo f
getFnConstructorInfo :: f -> FnConstructorInfo f
type HasConstFunctions t f =
(ConvertibleExactly (FnConstructorInfo f, t) f)
constFn :: (HasConstFunctions t f) => (FnConstructorInfo f) -> t -> f
constFn = curry convertExactly
specEvalConstFn ::
_ => T c-> T f -> T x -> Spec
specEvalConstFn (T cName :: T c) (T fName :: T f) (T xName :: T x) =
it (printf "Evaluating %s-constant functions %s on %s" cName fName xName) $
property $
\ (c :: c) (constrInfo :: FnConstructorInfo f) (xPres :: [x]) ->
let f = constFn constrInfo c :: f in
let dom = getDomain f in
and $ flip map xPres $ \xPre ->
apply f (mapInside dom xPre) ?==? c
class HasVars f where
type Var f
{-| the function @x@, ie the function that project the domain to the given variable @x@ -}
varFn ::
FnConstructorInfo f {-^ eg domain and/or accuracy guide -}->
Var f {-^ @x@ -} ->
f
specEvalUnaryVarFn ::
_ => T f -> T x -> Spec
specEvalUnaryVarFn (T fName :: T f) (T xName :: T x) =
it (printf "Evaluating variable functions %s on %s" fName xName) $ property $
\ (constrInfo :: FnConstructorInfo f) (xPres :: [x]) ->
and $ flip map xPres $ \xPre ->
let f = varFn constrInfo () :: f in
let x = mapInside (getDomain f) xPre in
apply f x ?==? x
{- range computation -}
class CanMaximiseOverDom f d where
type MaximumOverDomType f d
maximumOverDom :: f -> d -> MaximumOverDomType f d
class CanMinimiseOverDom f d where
type MinimumOverDomType f d
minimumOverDom :: f -> d -> MinimumOverDomType f d
-- specCanMaximiseOverDom ::
-- _ => (T f) -> Spec
-- specCanMaximiseOverDom (T fName :: T f) =
-- describe ("CanMaximiseOverDom " ++ fName) $ do
-- it "is consistent over a split domain" $ property $
-- \ (f :: f) ->
-- let dom = getDomain f in
-- let (dom1, dom2) = split dom in
-- let maxOnDom = maximumOverDom f dom in
-- let maxOnDom1 = maximumOverDom f dom1 in
-- let maxOnDom2 = maximumOverDom f dom2 in
-- maxOnDom ?>=? maxOnDom1
-- &&
-- maxOnDom ?>=? maxOnDom2
specCanMaximiseOverDom ::
_ => (T f) -> (T x) -> Spec
specCanMaximiseOverDom (T fName :: T f) (T _xName :: T x) =
describe ("CanMaximiseOverDom " ++ fName) $ do
it "is consistent with evaluation" $ property $
\ (f :: f) (xPres :: [x]) ->
let dom = getDomain f in
let maxOnDom = maximumOverDom f dom in
and $ flip map xPres $ \xPre ->
let x = mapInside dom xPre in
let v1 = apply f x in
maxOnDom ?>=? v1
{- integration -}
class CanIntegrateOverDom f bounds where
type IntegralOverDomType f bounds
integrateOverDom :: f -> bounds -> IntegralOverDomType f bounds