{-# LANGUAGE ForeignFunctionInterface #-}
module Numerical.Integration
(integration, IntegralResult(..))
where
import Foreign.Marshal.Alloc (free, mallocBytes)
import Foreign.Ptr (FunPtr, Ptr, freeHaskellFunPtr)
import Foreign.Storable (peek, sizeOf)
import Foreign.C (CDouble(..), CInt(..))
data IntegralResult = IntegralResult {
_value :: CDouble,
_error :: CDouble,
_code :: Int
} deriving Show
foreign import ccall safe "wrapper" funPtr
:: (CDouble -> CDouble) -> IO (FunPtr (CDouble -> CDouble))
foreign import ccall safe "integration" c_integration
:: FunPtr (CDouble -> CDouble) -> CDouble -> CDouble -> CDouble -> CInt
-> Ptr CDouble -> Ptr CInt -> IO CDouble
-- | Numerical integration.
integration :: (CDouble -> CDouble) -- ^ integrand
-> CDouble -- ^ lower bound
-> CDouble -- ^ upper bound
-> CDouble -- ^ desired relative error
-> CInt -- ^ number of subdivisions
-> IO IntegralResult -- ^ value, error estimate, error code
integration f lower upper relError subdiv = do
errorEstimatePtr <- mallocBytes (sizeOf (0 :: CDouble))
errorCodePtr <- mallocBytes (sizeOf (0 :: CInt))
fPtr <- funPtr f
result <-
c_integration fPtr lower upper relError subdiv errorEstimatePtr errorCodePtr
errorEstimate <- peek errorEstimatePtr
errorCode <- fromIntegral <$> peek errorCodePtr
let out = IntegralResult {_value = result, _error = errorEstimate, _code = errorCode}
free errorEstimatePtr
free errorCodePtr
freeHaskellFunPtr fPtr
return out