{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE FlexibleContexts #-}
module Data.Massiv.Array.Numeric.Integral (
midpointRule,
midpointStencil,
trapezoidRule,
trapezoidStencil,
simpsonsRule,
simpsonsStencil,
integrateWith,
integralApprox,
fromFunction,
fromFunctionMidpoint,
) where
import Data.Coerce
import Data.Massiv.Array.Delayed.Pull (D)
import Data.Massiv.Array.Delayed.Windowed (DW)
import Data.Massiv.Array.Manifest.Internal
import Data.Massiv.Array.Ops.Construct (rangeInclusive)
import Data.Massiv.Array.Ops.Transform (extract')
import Data.Massiv.Array.Stencil
import Data.Massiv.Array.Unsafe
import Data.Massiv.Core.Common
midpointStencil
:: (Fractional e, Index ix)
=> e
-> Dim
-> Int
-> Stencil ix e e
midpointStencil :: forall e ix.
(Fractional e, Index ix) =>
e -> Dim -> Int -> Stencil ix e e
midpointStencil e
dx Dim
dim Int
k =
Sz ix -> ix -> (ix -> (ix -> e) -> e) -> Stencil ix e e
forall ix e a.
Index ix =>
Sz ix -> ix -> (ix -> (ix -> e) -> a) -> Stencil ix e a
makeUnsafeStencil (ix -> Sz ix
forall ix. Index ix => ix -> Sz ix
Sz (ix -> Dim -> Int -> ix
forall ix. (HasCallStack, Index ix) => ix -> Dim -> Int -> ix
setDim' (Int -> ix
forall ix. Index ix => Int -> ix
pureIndex Int
1) Dim
dim Int
k)) ix
forall ix. Index ix => ix
zeroIndex ((ix -> (ix -> e) -> e) -> Stencil ix e e)
-> (ix -> (ix -> e) -> e) -> Stencil ix e e
forall a b. (a -> b) -> a -> b
$ \ix
_ ix -> e
g ->
e
dx e -> e -> e
forall a. Num a => a -> a -> a
* Int -> (Int -> Bool) -> (Int -> Int) -> e -> (Int -> e -> e) -> e
forall a.
Int -> (Int -> Bool) -> (Int -> Int) -> a -> (Int -> a -> a) -> a
loop Int
0 (Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
k) (Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) e
0 (\Int
i -> (e -> e -> e
forall a. Num a => a -> a -> a
+ ix -> e
g (ix -> Dim -> Int -> ix
forall ix. (HasCallStack, Index ix) => ix -> Dim -> Int -> ix
setDim' ix
forall ix. Index ix => ix
zeroIndex Dim
dim Int
i)))
{-# INLINE midpointStencil #-}
trapezoidStencil
:: (Fractional e, Index ix)
=> e
-> Dim
-> Int
-> Stencil ix e e
trapezoidStencil :: forall e ix.
(Fractional e, Index ix) =>
e -> Dim -> Int -> Stencil ix e e
trapezoidStencil e
dx Dim
dim Int
n =
Sz ix -> ix -> (ix -> (ix -> e) -> e) -> Stencil ix e e
forall ix e a.
Index ix =>
Sz ix -> ix -> (ix -> (ix -> e) -> a) -> Stencil ix e a
makeUnsafeStencil (ix -> Sz ix
forall ix. Index ix => ix -> Sz ix
Sz (ix -> Dim -> Int -> ix
forall ix. (HasCallStack, Index ix) => ix -> Dim -> Int -> ix
setDim' (Int -> ix
forall ix. Index ix => Int -> ix
pureIndex Int
1) Dim
dim (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1))) ix
forall ix. Index ix => ix
zeroIndex ((ix -> (ix -> e) -> e) -> Stencil ix e e)
-> (ix -> (ix -> e) -> e) -> Stencil ix e e
forall a b. (a -> b) -> a -> b
$ \ix
_ ix -> e
g ->
(e
dx e -> e -> e
forall a. Fractional a => a -> a -> a
/ e
2)
e -> e -> e
forall a. Num a => a -> a -> a
* ( Int -> (Int -> Bool) -> (Int -> Int) -> e -> (Int -> e -> e) -> e
forall a.
Int -> (Int -> Bool) -> (Int -> Int) -> a -> (Int -> a -> a) -> a
loop Int
1 (Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
n) (Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (ix -> e
g ix
forall ix. Index ix => ix
zeroIndex) (\Int
i -> (e -> e -> e
forall a. Num a => a -> a -> a
+ e
2 e -> e -> e
forall a. Num a => a -> a -> a
* ix -> e
g (ix -> Dim -> Int -> ix
forall ix. (HasCallStack, Index ix) => ix -> Dim -> Int -> ix
setDim' ix
forall ix. Index ix => ix
zeroIndex Dim
dim Int
i)))
e -> e -> e
forall a. Num a => a -> a -> a
+ ix -> e
g (ix -> Dim -> Int -> ix
forall ix. (HasCallStack, Index ix) => ix -> Dim -> Int -> ix
setDim' ix
forall ix. Index ix => ix
zeroIndex Dim
dim Int
n)
)
{-# INLINE trapezoidStencil #-}
simpsonsStencil
:: (Fractional e, Index ix)
=> e
-> Dim
-> Int
-> Stencil ix e e
simpsonsStencil :: forall e ix.
(Fractional e, Index ix) =>
e -> Dim -> Int -> Stencil ix e e
simpsonsStencil e
dx Dim
dim Int
n
| Int -> Bool
forall a. Integral a => a -> Bool
odd Int
n =
[Char] -> Stencil ix e e
forall a. HasCallStack => [Char] -> a
error ([Char] -> Stencil ix e e) -> [Char] -> Stencil ix e e
forall a b. (a -> b) -> a -> b
$
[Char]
"Number of sample points for Simpson's rule stencil should be even, but received: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Int -> [Char]
forall a. Show a => a -> [Char]
show Int
n
| Bool
otherwise =
Sz ix -> ix -> (ix -> (ix -> e) -> e) -> Stencil ix e e
forall ix e a.
Index ix =>
Sz ix -> ix -> (ix -> (ix -> e) -> a) -> Stencil ix e a
makeUnsafeStencil (ix -> Sz ix
forall ix. Index ix => ix -> Sz ix
Sz (ix -> Dim -> Int -> ix
forall ix. (HasCallStack, Index ix) => ix -> Dim -> Int -> ix
setDim' (Int -> ix
forall ix. Index ix => Int -> ix
pureIndex Int
1) Dim
dim (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1))) ix
forall ix. Index ix => ix
zeroIndex ((ix -> (ix -> e) -> e) -> Stencil ix e e)
-> (ix -> (ix -> e) -> e) -> Stencil ix e e
forall a b. (a -> b) -> a -> b
$ \ix
_ ix -> e
g ->
let simAcc :: Int -> (e, e) -> (e, e)
simAcc Int
i (e
prev, e
acc) =
let !fx3 :: e
fx3 = ix -> e
g (ix -> Dim -> Int -> ix
forall ix. (HasCallStack, Index ix) => ix -> Dim -> Int -> ix
setDim' ix
forall ix. Index ix => ix
zeroIndex Dim
dim (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2))
!newAcc :: e
newAcc = e
acc e -> e -> e
forall a. Num a => a -> a -> a
+ e
prev e -> e -> e
forall a. Num a => a -> a -> a
+ e
4 e -> e -> e
forall a. Num a => a -> a -> a
* ix -> e
g (ix -> Dim -> Int -> ix
forall ix. (HasCallStack, Index ix) => ix -> Dim -> Int -> ix
setDim' ix
forall ix. Index ix => ix
zeroIndex Dim
dim (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)) e -> e -> e
forall a. Num a => a -> a -> a
+ e
fx3
in (e
fx3, e
newAcc)
in e
dx e -> e -> e
forall a. Fractional a => a -> a -> a
/ e
3 e -> e -> e
forall a. Num a => a -> a -> a
* (e, e) -> e
forall a b. (a, b) -> b
snd (Int
-> (Int -> Bool)
-> (Int -> Int)
-> (e, e)
-> (Int -> (e, e) -> (e, e))
-> (e, e)
forall a.
Int -> (Int -> Bool) -> (Int -> Int) -> a -> (Int -> a -> a) -> a
loop Int
2 (Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) (Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2) (Int -> (e, e) -> (e, e)
simAcc Int
0 (ix -> e
g ix
forall ix. Index ix => ix
zeroIndex, e
0)) Int -> (e, e) -> (e, e)
simAcc)
{-# INLINE simpsonsStencil #-}
integrateWith
:: (Fractional e, StrideLoad DW ix e, Manifest r e)
=> (Dim -> Int -> Stencil ix e e)
-> Dim
-> Int
-> Array r ix e
-> Array r ix e
integrateWith :: forall e ix r.
(Fractional e, StrideLoad DW ix e, Manifest r e) =>
(Dim -> Int -> Stencil ix e e)
-> Dim -> Int -> Array r ix e -> Array r ix e
integrateWith Dim -> Int -> Stencil ix e e
stencil Dim
dim Int
n Array r ix e
arr =
Stride ix -> Array DW ix e -> Array r ix e
forall r ix e r'.
(Manifest r e, StrideLoad r' ix e) =>
Stride ix -> Array r' ix e -> Array r ix e
computeWithStride (ix -> Stride ix
forall ix. Index ix => ix -> Stride ix
Stride ix
nsz) (Array DW ix e -> Array r ix e) -> Array DW ix e -> Array r ix e
forall a b. (a -> b) -> a -> b
$ Border e -> Stencil ix e e -> Array r ix e -> Array DW ix e
forall ix r e a.
(Index ix, Manifest r e) =>
Border e -> Stencil ix e a -> Array r ix e -> Array DW ix a
mapStencil (e -> Border e
forall e. e -> Border e
Fill e
0) (Dim -> Int -> Stencil ix e e
stencil Dim
dim Int
n) Array r ix e
arr
where
!nsz :: ix
nsz = ix -> Dim -> Int -> ix
forall ix. (HasCallStack, Index ix) => ix -> Dim -> Int -> ix
setDim' (Int -> ix
forall ix. Index ix => Int -> ix
pureIndex Int
1) Dim
dim Int
n
{-# INLINE integrateWith #-}
integralApprox
:: (Fractional e, StrideLoad DW ix e, Manifest r e)
=> (e -> Dim -> Int -> Stencil ix e e)
-> e
-> Sz ix
-> Int
-> Array r ix e
-> Array D ix e
integralApprox :: forall e ix r.
(Fractional e, StrideLoad DW ix e, Manifest r e) =>
(e -> Dim -> Int -> Stencil ix e e)
-> e -> Sz ix -> Int -> Array r ix e -> Array D ix e
integralApprox e -> Dim -> Int -> Stencil ix e e
stencil e
d Sz ix
sz Int
n Array r ix e
arr =
ix -> Sz ix -> Array r ix e -> Array D ix e
forall r ix e.
(HasCallStack, Index ix, Source r e) =>
ix -> Sz ix -> Array r ix e -> Array D ix e
extract' ix
forall ix. Index ix => ix
zeroIndex Sz ix
sz (Array r ix e -> Array D ix e) -> Array r ix e -> Array D ix e
forall a b. (a -> b) -> a -> b
$ Int
-> (Int -> Bool)
-> (Int -> Int)
-> Array r ix e
-> (Int -> Array r ix e -> Array r ix e)
-> Array r ix e
forall a.
Int -> (Int -> Bool) -> (Int -> Int) -> a -> (Int -> a -> a) -> a
loop Int
1 (Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Dim -> Int
forall a b. Coercible a b => a -> b
coerce (Sz ix -> Dim
forall ix (proxy :: * -> *). Index ix => proxy ix -> Dim
forall (proxy :: * -> *). proxy ix -> Dim
dimensions Sz ix
sz)) (Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Array r ix e
arr Int -> Array r ix e -> Array r ix e
forall {r}. Manifest r e => Int -> Array r ix e -> Array r ix e
integrateAlong
where
!dx :: e
dx = e
d e -> e -> e
forall a. Fractional a => a -> a -> a
/ Int -> e
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
integrateAlong :: Int -> Array r ix e -> Array r ix e
integrateAlong Int
dim = (Dim -> Int -> Stencil ix e e)
-> Dim -> Int -> Array r ix e -> Array r ix e
forall e ix r.
(Fractional e, StrideLoad DW ix e, Manifest r e) =>
(Dim -> Int -> Stencil ix e e)
-> Dim -> Int -> Array r ix e -> Array r ix e
integrateWith (e -> Dim -> Int -> Stencil ix e e
stencil e
dx) (Int -> Dim
Dim Int
dim) Int
n
{-# INLINE integrateAlong #-}
{-# INLINE integralApprox #-}
midpointRule
:: (Fractional e, StrideLoad DW ix e, Manifest r e)
=> Comp
-> r
-> ((Int -> e) -> ix -> e)
-> e
-> e
-> Sz ix
-> Int
-> Array D ix e
midpointRule :: forall e ix r.
(Fractional e, StrideLoad DW ix e, Manifest r e) =>
Comp
-> r
-> ((Int -> e) -> ix -> e)
-> e
-> e
-> Sz ix
-> Int
-> Array D ix e
midpointRule Comp
comp r
r (Int -> e) -> ix -> e
f e
a e
d Sz ix
sz Int
n =
(e -> Dim -> Int -> Stencil ix e e)
-> e -> Sz ix -> Int -> Array r ix e -> Array D ix e
forall e ix r.
(Fractional e, StrideLoad DW ix e, Manifest r e) =>
(e -> Dim -> Int -> Stencil ix e e)
-> e -> Sz ix -> Int -> Array r ix e -> Array D ix e
integralApprox e -> Dim -> Int -> Stencil ix e e
forall e ix.
(Fractional e, Index ix) =>
e -> Dim -> Int -> Stencil ix e e
midpointStencil e
d Sz ix
sz Int
n (Array r ix e -> Array D ix e) -> Array r ix e -> Array D ix e
forall a b. (a -> b) -> a -> b
$ r -> Array D ix e -> Array r ix e
forall r e r' ix.
(Manifest r e, Load r' ix e) =>
r -> Array r' ix e -> Array r ix e
computeAs r
r (Array D ix e -> Array r ix e) -> Array D ix e -> Array r ix e
forall a b. (a -> b) -> a -> b
$ Comp
-> ((Int -> e) -> ix -> e)
-> e
-> e
-> Sz ix
-> Int
-> Array D ix e
forall ix a e.
(Index ix, Fractional a) =>
Comp
-> ((Int -> a) -> ix -> e)
-> a
-> a
-> Sz ix
-> Int
-> Array D ix e
fromFunctionMidpoint Comp
comp (Int -> e) -> ix -> e
f e
a e
d Sz ix
sz Int
n
{-# INLINE midpointRule #-}
trapezoidRule
:: (Fractional e, StrideLoad DW ix e, Manifest r e)
=> Comp
-> r
-> ((Int -> e) -> ix -> e)
-> e
-> e
-> Sz ix
-> Int
-> Array D ix e
trapezoidRule :: forall e ix r.
(Fractional e, StrideLoad DW ix e, Manifest r e) =>
Comp
-> r
-> ((Int -> e) -> ix -> e)
-> e
-> e
-> Sz ix
-> Int
-> Array D ix e
trapezoidRule Comp
comp r
r (Int -> e) -> ix -> e
f e
a e
d Sz ix
sz Int
n =
(e -> Dim -> Int -> Stencil ix e e)
-> e -> Sz ix -> Int -> Array r ix e -> Array D ix e
forall e ix r.
(Fractional e, StrideLoad DW ix e, Manifest r e) =>
(e -> Dim -> Int -> Stencil ix e e)
-> e -> Sz ix -> Int -> Array r ix e -> Array D ix e
integralApprox e -> Dim -> Int -> Stencil ix e e
forall e ix.
(Fractional e, Index ix) =>
e -> Dim -> Int -> Stencil ix e e
trapezoidStencil e
d Sz ix
sz Int
n (Array r ix e -> Array D ix e) -> Array r ix e -> Array D ix e
forall a b. (a -> b) -> a -> b
$ r -> Array D ix e -> Array r ix e
forall r e r' ix.
(Manifest r e, Load r' ix e) =>
r -> Array r' ix e -> Array r ix e
computeAs r
r (Array D ix e -> Array r ix e) -> Array D ix e -> Array r ix e
forall a b. (a -> b) -> a -> b
$ Comp
-> ((Int -> e) -> ix -> e)
-> e
-> e
-> Sz ix
-> Int
-> Array D ix e
forall ix a e.
(Index ix, Fractional a) =>
Comp
-> ((Int -> a) -> ix -> e)
-> a
-> a
-> Sz ix
-> Int
-> Array D ix e
fromFunction Comp
comp (Int -> e) -> ix -> e
f e
a e
d Sz ix
sz Int
n
{-# INLINE trapezoidRule #-}
simpsonsRule
:: (Fractional e, StrideLoad DW ix e, Manifest r e)
=> Comp
-> r
-> ((Int -> e) -> ix -> e)
-> e
-> e
-> Sz ix
-> Int
-> Array D ix e
simpsonsRule :: forall e ix r.
(Fractional e, StrideLoad DW ix e, Manifest r e) =>
Comp
-> r
-> ((Int -> e) -> ix -> e)
-> e
-> e
-> Sz ix
-> Int
-> Array D ix e
simpsonsRule Comp
comp r
r (Int -> e) -> ix -> e
f e
a e
d Sz ix
sz Int
n =
(e -> Dim -> Int -> Stencil ix e e)
-> e -> Sz ix -> Int -> Array r ix e -> Array D ix e
forall e ix r.
(Fractional e, StrideLoad DW ix e, Manifest r e) =>
(e -> Dim -> Int -> Stencil ix e e)
-> e -> Sz ix -> Int -> Array r ix e -> Array D ix e
integralApprox e -> Dim -> Int -> Stencil ix e e
forall e ix.
(Fractional e, Index ix) =>
e -> Dim -> Int -> Stencil ix e e
simpsonsStencil e
d Sz ix
sz Int
n (Array r ix e -> Array D ix e) -> Array r ix e -> Array D ix e
forall a b. (a -> b) -> a -> b
$ r -> Array D ix e -> Array r ix e
forall r e r' ix.
(Manifest r e, Load r' ix e) =>
r -> Array r' ix e -> Array r ix e
computeAs r
r (Array D ix e -> Array r ix e) -> Array D ix e -> Array r ix e
forall a b. (a -> b) -> a -> b
$ Comp
-> ((Int -> e) -> ix -> e)
-> e
-> e
-> Sz ix
-> Int
-> Array D ix e
forall ix a e.
(Index ix, Fractional a) =>
Comp
-> ((Int -> a) -> ix -> e)
-> a
-> a
-> Sz ix
-> Int
-> Array D ix e
fromFunction Comp
comp (Int -> e) -> ix -> e
f e
a e
d Sz ix
sz Int
n
{-# INLINE simpsonsRule #-}
fromFunction
:: (Index ix, Fractional a)
=> Comp
-> ((Int -> a) -> ix -> e)
-> a
-> a
-> Sz ix
-> Int
-> Array D ix e
fromFunction :: forall ix a e.
(Index ix, Fractional a) =>
Comp
-> ((Int -> a) -> ix -> e)
-> a
-> a
-> Sz ix
-> Int
-> Array D ix e
fromFunction Comp
comp (Int -> a) -> ix -> e
f a
a a
d (Sz ix
sz) Int
n =
(Int -> a) -> ix -> e
f Int -> a
forall {a}. Integral a => a -> a
scale (ix -> e) -> Array D ix ix -> Array D ix e
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Comp -> ix -> ix -> Array D ix ix
forall ix. Index ix => Comp -> ix -> ix -> Array D ix ix
rangeInclusive Comp
comp ix
forall ix. Index ix => ix
zeroIndex ((Int -> Int) -> ix -> ix
forall ix. Index ix => (Int -> Int) -> ix -> ix
liftIndex (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
*) ix
sz)
where
nFrac :: a
nFrac = Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
scale :: a -> a
scale a
i = a
a a -> a -> a
forall a. Num a => a -> a -> a
+ a
d a -> a -> a
forall a. Num a => a -> a -> a
* a -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
i a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
nFrac
{-# INLINE scale #-}
{-# INLINE fromFunction #-}
fromFunctionMidpoint
:: (Index ix, Fractional a)
=> Comp
-> ((Int -> a) -> ix -> e)
-> a
-> a
-> Sz ix
-> Int
-> Array D ix e
fromFunctionMidpoint :: forall ix a e.
(Index ix, Fractional a) =>
Comp
-> ((Int -> a) -> ix -> e)
-> a
-> a
-> Sz ix
-> Int
-> Array D ix e
fromFunctionMidpoint Comp
comp (Int -> a) -> ix -> e
f a
a a
d (Sz ix
sz) Int
n =
(Int -> a) -> ix -> e
f Int -> a
forall {a}. Integral a => a -> a
scale (ix -> e) -> Array D ix ix -> Array D ix e
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Comp -> ix -> ix -> Array D ix ix
forall ix. Index ix => Comp -> ix -> ix -> Array D ix ix
rangeInclusive Comp
comp ix
forall ix. Index ix => ix
zeroIndex ((Int -> Int) -> ix -> ix
forall ix. Index ix => (Int -> Int) -> ix -> ix
liftIndex (\Int
i -> Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) ix
sz)
where
nFrac :: a
nFrac = Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n
dx2 :: a
dx2 = a
d a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
nFrac a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
2
scale :: a -> a
scale a
i = a
dx2 a -> a -> a
forall a. Num a => a -> a -> a
+ a
a a -> a -> a
forall a. Num a => a -> a -> a
+ a
d a -> a -> a
forall a. Num a => a -> a -> a
* a -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
i a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
nFrac
{-# INLINE scale #-}
{-# INLINE fromFunctionMidpoint #-}