AERN-RnToRm-0.4.9: src/Data/Number/ER/RnToRm/UnitDom/Base.hs
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-|
Module : Data.Number.ER.RnToRm.UnitDom.Base
Description : class abstracting imprecise function arithmetic on [-1,1]^n
Copyright : (c) 2007-2008 Michal Konecny
License : BSD3
Maintainer : mik@konecny.aow.cz
Stability : experimental
Portability : portable
A class abstracting function arithmetic with directed rounding.
It is used to describe a boundary for an approximation
to a real function on the interval [-1,1]^n.
To be imported qualified, usually with the synonym UFB.
-}
module Data.Number.ER.RnToRm.UnitDom.Base where
import Prelude hiding (min, max, recip, const)
import qualified Data.Number.ER.Real.DomainBox as DBox
import Data.Number.ER.Real.DomainBox (VariableID(..), DomainBox, DomainIntBox)
import Data.Number.ER.BasicTypes
import qualified Data.Number.ER.Real.Base as B
import qualified Data.Number.ER.Real.Approx as RA
import Data.Number.ER.Misc
import qualified Data.Map as Map
import Data.Typeable
class
(B.ERRealBase b, RA.ERIntApprox ra, Ord ufb,
DomainBox boxb varid b, DomainIntBox boxra varid ra) =>
ERUnitFnBase boxb boxra varid b ra ufb
| ufb -> boxb boxra varid b ra
where
{--------------}
{----- Miscellaneous associated operations -----}
{--------------}
{-| This should be evaluated before using any of the following operations. -}
initialiseBaseArithmetic :: ufb -> IO ()
initialiseBaseArithmetic _ =
B.initialiseBaseArithmetic (0 :: b)
{-|
Convert from the associated interval type to the base type.
(The types are determined by the given example function.)
-}
raEndpoints ::
ufb {-^ this parameter is not used except for type checking -} ->
ra ->
(b,b)
{-|
Convert from the base type to the associated interval type.
(The types are determined by the given example function.)
-}
raFromEndpoints ::
ufb {-^ this parameter is not used except for type checking -} ->
(b,b) ->
ra
{-|
A linear ordering on basic functions, which can be syntactic and rather arbitrary.
-}
compareApprox :: ufb -> ufb -> Ordering
showDiGrCmp ::
Int {- ^ number of decimal digits to show -} ->
Bool {-^ whether to show granularity -} ->
Bool {-^ whether to show internal structure -} ->
ufb -> String
{--------------}
{----- Structural analysis and update of functions -----}
{--------------}
{-|
Check internal consistency of the basic function, typically absence of NaN.
-}
isValid :: ufb -> Bool
{-|
Check internal consistency of the basic function and report problem if any.
-}
check ::
String {-^ indentification of caller location for easier debugging -} ->
ufb -> ufb
{-|
Get the granularity of the coefficients inside this basic function.
-}
getGranularity :: ufb -> Granularity
setMinGranularity :: Granularity -> ufb -> ufb
setGranularity :: Granularity -> ufb -> ufb
{-|
Get the degree of this basic function.
If the function is a polynomial, this function should
return its degree.
-}
getDegree :: ufb -> Int
{-|
Decrease the degree of a basic function, rounding pointwise upwards.
-}
reduceDegreeUp :: Int -> ufb -> ufb
{-|
Get the term size of this basic function.
If the function is a polynomial, this function should
return the number of terms in the polynomial.
-}
getSize :: ufb -> Int
{-|
Decrease the size of this basic function, rounding pointwise upwards.
-}
reduceSizeUp :: Int -> ufb -> ufb
{-|
Get a list of all variables featured in this basic function.
-}
getVariables :: ufb -> [varid]
{--------------}
{----- Construction of basic functions -----}
{--------------}
{-| Construct a constant basic function. -}
const :: b -> ufb
{-| Construct a constant basic enclosure (negated lower bound, upper bound). -}
constEncl :: (b,b) -> (ufb, ufb)
{-| Construct an affine basic function. -}
affine ::
b {-^ value at 0 -} ->
Map.Map varid b {-^ ascent of each base vector -} ->
ufb
{--------------}
{----- Pointwise order operations ----------}
{--------------}
{-|
Find an upper bound of a basic function over @[-1,1]^n@.
-}
upperBound :: EffortIndex -> ufb -> b
{-|
Approximate the function @max(f1,f2)@ from above.
-}
maxUp ::
Int {-^ max degree for result -} ->
Int {-^ max approx size for result -} ->
ufb {-^ @f1@ -} ->
ufb {-^ @f2@ -} ->
ufb
{-|
Approximate the function @min(f1,f2)@ from above.
-}
minUp ::
Int {-^ max degree for result -} ->
Int {-^ max approx size for result -} ->
ufb {-^ @f1@ -} ->
ufb {-^ @f2@ -} ->
ufb
{--------------}
{----- Field operations ----------}
{--------------}
{-| Pointwise exact negation of a basic function -}
neg :: ufb -> ufb
{-|
Multiply a basic function by a scalar, rounding upwards.
-}
scaleUp :: b -> ufb -> ufb
{-|
Multiply a basic function by an approximation of a scalar,
rounding upwards.
-}
scaleApproxUp ::
Int {-^ maximum polynomial degree -} ->
Int {-^ maximum term count -} ->
ra -> ufb -> ufb
{-| Pointwise upwards rounded addition -}
(+^) :: ufb -> ufb -> ufb
{-| Pointwise upwards rounded subtraction -}
(-^) :: ufb -> ufb -> ufb
{-| Pointwise upwards rounded multiplication -}
(*^) :: ufb -> ufb -> ufb
{-| Enclosure multiplication
IMPORTANT: enclosure = (negated lower bound, upper bound)
-}
multiplyEncl ::
Int {-^ maximum polynomial degree -} ->
Int {-^ maximum term count -} ->
(ufb,ufb) -> (ufb,ufb) -> (ufb, ufb)
{-|
Approximate the function @1/f@ from above, assuming
@f@ does not hit zero in the unit domain.
-}
recipUp :: Int -> Int -> EffortIndex -> ufb -> ufb
{-|
Approximate the reciprocal of an enclosure, assuming
@f@ does not hit zero in the unit domain.
IMPORTANT: enclosure = (negated lower bound, upper bound)
-}
recipEncl ::
Int {-^ max degree for result -} ->
Int {-^ max approx size for result -} ->
EffortIndex ->
(ufb,ufb) {-^ enclosure of @f@ -} ->
(ufb,ufb)
{--------------}
{----- Evaluation and composition of functions -----}
{--------------}
{-|
Evaluate a basic function at a point rounding upwards
using a basic number for both the point and the result.
-}
evalUp :: boxb -> ufb -> b
{-|
Safely evaluate a basic function at a point using a real number approximation
for both the point and the result.
-}
evalApprox :: boxra -> ufb -> ra
{-|
Partially evaluate a basic function at a lower-dimensional point
given using a real number approximation.
Approximate the resulting function from above.
-}
partialEvalApproxUp :: boxra -> ufb -> ufb
{-|
Compose two basic functions, rounding downwards and upwards,
assuming @f_v@ ranges within the domain @[-1,1]@.
-}
composeUp ::
Int {-^ max degree for result -} ->
Int {-^ max approx size for result -} ->
ufb {-^ function @f@ -} ->
varid {-^ variable @v@ to substitute in @f@ -} ->
ufb
{-^ function @f_v@ to substitute for @v@
that maps @[-1,1]@ into @[-1,1]@ -} ->
ufb {-^ pointwise upper bound of @f[v |-> f_v]@ -}
{-|
Compose two basic functions, rounding downwards and upwards,
assuming @f_v@ ranges within the domain @[-1,1]@.
-}
composeEncl ::
Int {-^ max degree for result -} ->
Int {-^ max approx size for result -} ->
ufb {-^ function @f@ -} ->
varid {-^ variable @v@ to substitute in @f@ -} ->
(ufb, ufb)
{-^ enclosure of a function @f_v@ to substitute for @v@
that maps @[-1,1]@ into @[-1,1]@ -} ->
(ufb, ufb) {-^ enclosure of @f[v |-> f_v]@ -}
{-|
Substitute several variables in a basic function with other basic functions,
rounding downwards and upwards, assuming each @f_v@ ranges
within the domain @[-1,1]@.
-}
composeManyUp ::
Int {-^ max degree for result -} ->
Int {-^ max approx size for result -} ->
ufb {-^ function @f@ -} ->
Map.Map varid ufb
{-^ variables to substitute and for each variable @v@,
function @f_v@ to substitute for @v@
that maps @[-1,1]@ into @[-1,1]@ -} ->
ufb {-^ pointwise upper bound of @f[v |-> f_v]@ -}
{-|
Substitute several variables in a basic function with other basic functions,
rounding downwards and upwards, assuming each @f_v@ ranges
within the domain @[-1,1]@.
-}
composeManyEncls ::
Int {-^ max degree for result -} ->
Int {-^ max approx size for result -} ->
ufb {-^ function @f@ -} ->
Map.Map varid (ufb, ufb)
{-^ variables to substitute and for each variable @v@,
enclosure of a function @f_v@ to substitute for @v@
that maps @[-1,1]@ into @[-1,1]@ -} ->
(ufb, ufb) {-^ enclosure of @f[v |-> f_v]@ -}
{--------------}
{----- Selected elementary operations ----------}
{--------------}
{-|
Approximate @sqrt(f)@ for enclosures.
-}
sqrtEncl ::
Int {-^ max degree for result -} ->
Int {-^ max approx size for result -} ->
EffortIndex {-^ how hard to try when approximating exp as a polynomial -} ->
(ufb, ufb) {-^ @f@ -} ->
(ufb, ufb)
{-|
Approximate @exp(f)@ for enclosures.
-}
expEncl ::
Int {-^ max degree for result -} ->
Int {-^ max approx size for result -} ->
EffortIndex {-^ how hard to try when approximating exp as a polynomial -} ->
(ufb, ufb) {-^ @f@ -} ->
(ufb, ufb)
{-|
Approximate @log(f)@ for enclosures.
-}
logEncl ::
Int {-^ max degree for result -} ->
Int {-^ max approx size for result -} ->
EffortIndex {-^ how hard to try when approximating log as a polynomial -} ->
(ufb, ufb) {-^ @f@ -} ->
(ufb, ufb)
{-|
Approximate @sin(f)@ for enclosures,
assuming the range of @f@ is within @[-pi/2,pi/2]@.
-}
sinEncl ::
Int {-^ max degree for result -} ->
Int {-^ max approx size for result -} ->
EffortIndex {-^ how hard to try when approximating sin as a polynomial -} ->
(ufb, ufb) {-^ @f@ -} ->
(ufb, ufb)
{-|
Approximate @cos(f)@ for enclosures,
assuming the range of @f@ is within @[-pi/2,pi/2]@.
-}
cosEncl ::
Int {-^ max degree for result -} ->
Int {-^ max approx size for result -} ->
EffortIndex {-^ how hard to try when approximating cos as a polynomial -} ->
(ufb, ufb) {-^ @f@ -} ->
(ufb, ufb)
{-|
Approximate @atan(f)@ for enclosures.
-}
atanEncl ::
Int {-^ max degree for result -} ->
Int {-^ max approx size for result -} ->
EffortIndex {-^ how hard to try when approximating cos as a polynomial -} ->
(ufb, ufb) {-^ @f@ -} ->
(ufb, ufb)
{--------------}
{----- Approximate symbolic integration ----------}
{--------------}
{-|
Approximate the primitive function of @f@ from below and from above.
-}
integrate ::
varid {-^ variable to integrate by -} ->
ufb {-^ @f@ -} ->
(ufb, ufb)
{-|
Measure the volume between a function
and the zero hyperplane on the domain @[-1,1]^n@.
-}
volumeAboveZeroUp ::
[varid]
{-^ dimensions to include in the measuring domain;
have to include all those present in @f@ -} ->
ufb {-^ @f@ -} ->
b
volumeAboveZeroUp vars p =
-- unsafePrint ("chplVolumeAboveZero: returning:" ++ show result) $
-- unsafePrint ("chplVolumeAboveZero: vars = " ++ show vars) $
result
where
result = integUpAtEvenCorners - integDownAtOddCorners
integUpAtEvenCorners = sumUp $ map (\pt -> evalUp pt integUp) evenCorners
integDownAtOddCorners = sumUp $ map (\pt -> evalUp pt integDownNeg) oddCorners
evenCorners = map (DBox.fromList) evenCornersL
oddCorners = map (DBox.fromList) oddCornersL
(evenCornersL, oddCornersL) =
allPairsCombinationsEvenOdd $ zip vars $ repeat (1,-1)
integUp = integrateByAllVars snd p vars
integDownNeg = neg $ integrateByAllVars fst p vars
integrateByAllVars pick p [] = p
integrateByAllVars pick p (x : xs) =
integrateByAllVars pick ip xs
where
ip = pick $ integrate x p