packages feed

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