packages feed

scubature-1.1.0.0: src/Numeric/Integration/SimplexCubature.hs

{-# LANGUAGE DuplicateRecordFields #-}
module Numeric.Integration.SimplexCubature
  (Result(..), Results(..), integrateOnSimplex, integrateOnSimplex')
  where
import           Data.Array.Unboxed                  (UArray, array)
import           Data.Array.Unsafe                   (unsafeThaw)
import qualified Data.Vector.Unboxed                 as UV
import           Numeric.Integration.Simplex.Simplex ( isValidSimplices, Simplices )
import           Numeric.Integration.SimplexCubature.Internal  ( VectorD, IO3dArray, adsimp )

data Results = Results
  { values         :: [Double]
  , errorEstimates :: [Double]
  , evaluations    :: Int
  , success        :: Bool
  } deriving Show

data Result = Result
  { value         :: Double
  , errorEstimate :: Double
  , evaluations   :: Int
  , success       :: Bool
  } deriving Show

simplicesToArray :: Simplices -> IO IO3dArray
simplicesToArray simplices = do
  let dim = length (head (head simplices))
      nsimplices = length simplices
      assocList = map (\[i, j, k] -> ((i, j, k), (simplices!!(k-1))!!(j-1)!!(i-1)))
                      (sequence [[1 .. dim], [1 .. (dim+1)], [1 .. nsimplices]])
      arr = array ((1, 1, 1), (dim, dim+1, nsimplices)) assocList
            :: UArray (Int, Int, Int) Double
  unsafeThaw arr

-- | Integral of a vector-valued function over an union of simplices.
integrateOnSimplex
    :: (VectorD -> VectorD)   -- ^ integrand
    -> Simplices              -- ^ domain of integration
    -> Int                    -- ^ number of components
    -> Int                    -- ^ maximum number of evaluations
    -> Double                 -- ^ desired absolute error
    -> Double                 -- ^ desired relative error
    -> Int                    -- ^ integration rule: 1, 2, 3 or 4
    -> IO Results             -- ^ integral, error, evaluations, success
integrateOnSimplex f s ncomp maxevals absError relError rule = do
  let n = length (head s) - 1
  if isValidSimplices s
    then do
      v <- simplicesToArray s
      (vals, errors, nevals, fl) <-
        adsimp n ncomp maxevals f absError relError rule v
      return $ Results (UV.toList vals) (UV.toList errors) nevals (not fl)
    else error "invalid simplices"

-- | Integral of a real-valued function over an union of simplices.
integrateOnSimplex'
    :: (VectorD -> Double)    -- ^ integrand
    -> Simplices              -- ^ domain of integration
    -> Int                    -- ^ maximum number of evaluations
    -> Double                 -- ^ desired absolute error
    -> Double                 -- ^ desired relative error
    -> Int                    -- ^ integration rule: 1, 2, 3 or 4
    -> IO Result              -- ^ integral, error, evaluations, success
integrateOnSimplex' f s maxevals absError relError rule = do
  let n = length (head s) - 1
  if isValidSimplices s
    then do
      v <- simplicesToArray s
      (val, err, nevals, fl) <-
        adsimp n 1 maxevals (UV.singleton . f) absError relError rule v
      return $ Result (UV.head val) (UV.head err) nevals (not fl)
    else error "invalid simplices"