packages feed

adaptive-cubature-0.1.1.0: src/Numerical/Cubature.hs

{-# LANGUAGE ForeignFunctionInterface #-}
module Numerical.Cubature
  (cubature, Result(..))
  where
import           Foreign.C.Types       (CUInt(..))
import           Foreign.Marshal.Alloc (free, mallocBytes)
import           Foreign.Marshal.Array (peekArray, pokeArray)
import           Foreign.Ptr           (FunPtr, Ptr, freeHaskellFunPtr)
import           Foreign.Storable      (poke, peek, sizeOf)

type Integrand = CUInt -> Ptr Double -> Ptr () -> CUInt -> Ptr Double -> IO Int

data Result = Result
  { _integral :: Double, _error :: Double } 
  deriving (Show)

foreign import ccall safe "wrapper" integrandPtr
    :: Integrand -> IO (FunPtr Integrand)

foreign import ccall safe "mintegration" c_cubature
    :: Char
    -> FunPtr Integrand
    -> Int
    -> Ptr Double
    -> Ptr Double
    -> Double
    -> Ptr Double
    -> IO Double

fun2integrand :: ([Double] -> Double) -> Int -> Integrand
fun2integrand f n _ x _ _ fval = do
  list <- peekArray n x
  poke fval (f list)
  return 0

-- | Multivariate integration on an axis-aligned box.
cubature :: Char                 -- ^ cubature version, 'h' or 'p'
         -> ([Double] -> Double) -- ^ integrand
         -> Int                  -- ^ dimension (number of variables)
         -> [Double]             -- ^ lower limits of integration
         -> [Double]             -- ^ upper limits of integration
         -> Double               -- ^ desired relative error
         -> IO Result            -- ^ output: integral value and error estimate
cubature version f n xmin xmax relError = do
  fPtr <- integrandPtr (fun2integrand f n)
  xminPtr <- mallocBytes (n * sizeOf (0.0 :: Double))
  pokeArray xminPtr xmin
  xmaxPtr <- mallocBytes (n * sizeOf (0.0 :: Double))
  pokeArray xmaxPtr xmax
  errorPtr <- mallocBytes (sizeOf (0.0 :: Double))
  result <- c_cubature version fPtr n xminPtr xmaxPtr relError errorPtr
  errorEstimate <- peek errorPtr
  free errorPtr
  free xmaxPtr
  free xminPtr
  freeHaskellFunPtr fPtr
  return Result { _integral = result, _error = errorEstimate }

-- fExample :: [Double] -> Double
-- fExample list = exp (-0.5 * (sum $ zipWith (*) list list))

-- example :: IO Result
-- example = cubature 'h' fExample 2 [-6,-6] [6,6] 1e-10