packages feed

scubature-1.0.0.0: src/Numeric/Integration/SphericalSimplexCubature/Internal.hs

module Numeric.Integration.SphericalSimplexCubature.Internal
  (orthants, SphericalSimplex, transformedIntegrand)
  where
import           Data.List.Index     (imap)
import           Data.Matrix         (detLU, diagonalList, fromLists, 
                                      minorMatrix, toLists, zero, (<->))
import           Data.Vector.Unboxed (Vector)
import qualified Data.Vector.Unboxed as V

type SphericalSimplex = [[Double]] -- square [v1, v2, v3, v4]

orthants :: Int -> [SphericalSimplex]
orthants n = reverse $ map (toLists . diagonalList n 0) (pm n)
  where pm 2 = [[i, j] | i <- [-1, 1], j <- [-1, 1]]
        pm k = [i : l | i <- [-1, 1], l <- pm (k-1)]

norm2 :: [Double] -> Double
norm2 v = sqrt $ sum $ zipWith (*) v v

dotproduct :: [Double] -> [Double] -> Double
dotproduct a b = sum $ zipWith (*) a b

scalarTimesList :: Double -> [Double] -> [Double]
scalarTimesList lambda = map (* lambda)

f :: SphericalSimplex -> [Double] -> [Double]
f vertices stu = foldr (zipWith (+)) (vertices!!0) terms
  where
    w = map (zipWith subtract (vertices!!0)) (tail vertices)
    terms = zipWith scalarTimesList stu w

g :: SphericalSimplex -> [Double] -> [Double]
g vertices stu = scalarTimesList (1 / norm2 fstu) fstu
  where fstu = f vertices stu

dg :: SphericalSimplex -> [Double] -> [[Double]]
dg vertices stu = zipWith (zipWith subtract) fviv1 nviv1
  where
    fstu = f vertices stu
    invn = 1 / norm2 fstu
    invn3 = invn*invn*invn
    viv1 = map (zipWith subtract (head vertices)) (tail vertices)
    nviv1 = map (scalarTimesList invn) viv1
    dpi = map ((*invn3) . dotproduct fstu) viv1
    fviv1 = map (`scalarTimesList` fstu) dpi

extProduct :: [[Double]] -> [Double]
extProduct vectors =
  imap (\i mat -> (if even i then 1 else -1) * detLU mat) minorMatrices
  where
    dim = length vectors + 1
    matrix = zero 1 dim <-> fromLists vectors
    minorMatrices = map (\j -> minorMatrix 1 j matrix) [1 .. dim]

sigma :: SphericalSimplex -> [Double] -> Double
sigma ssimplex stu = norm2 $ extProduct (dg ssimplex stu)

transformedIntegrand :: SphericalSimplex -> ([Double] -> Double)
                     -> (Vector Double -> Double)
transformedIntegrand ssimplex integrand stu =
  let stul = V.toList stu in
  sigma ssimplex stul * integrand (g ssimplex stul)