Skip to content

Commit 87a130e

Browse files
nbrantutdextorious
authored andcommitted
Added function to perform cumulative integrals, and array inputs (#15)
* (1) Added function cumul_integrate to perform cumulative integrals (similar to functions like cumtrapz in Matlab) (2) Added methods to compute integrals and cumulative integrals for each column of an input Array (3) updated documentation of functions (4) updated readme * Modified name of function for cumulative integrals to "cumul_integrate". New methods to integrate along specific dimensions of a matrix. Use Trapzedoial() (instead of TrapezoidalFast()) as default method, for safety.
1 parent 982c596 commit 87a130e

File tree

2 files changed

+158
-7
lines changed

2 files changed

+158
-7
lines changed

README.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,36 @@ Do note that while the code is trivial, it has not been extensively tested and d
1616
```julia
1717
# setup some data
1818
x = collect(-π : π/1000 : π)
19-
y = sin(x)
19+
y = sin.(x)
2020

2121
# integrate using the default TrapezoidalFast method
2222
integrate(x, y)
2323

2424
# integrate using a specific method
2525
integrate(x, y, SimpsonEven())
26+
27+
# compute cumulative integral
28+
Y = cumul_integrate(x, y)
29+
30+
# compute cumulative integral for each column of an array
31+
z = [sin.(x) cos.(x) exp.(x/pi)]
32+
Z = cumul_integrate(x, z)
33+
34+
# compute cumulative integral for each line of an array
35+
zp = permutedims(z)
36+
ZP = cumul_integrate(x, zp, dims=1)
37+
2638
```
2739

2840
The currently available methods are:
29-
- Trapezoidal
41+
- Trapezoidal (default)
3042
- TrapezoidalEven
31-
- TrapezoidalFast (default)
43+
- TrapezoidalFast
3244
- TrapezoidalEvenFast
3345
- SimpsonEven
3446
- SimpsonEvenFast
3547
- RombergEven
3648

49+
Only Trapezoidal methods are available for cumulative integrals.
50+
3751
All methods containing "Even" in the name assume evenly spaced data. All methods containing "Fast" omit basic correctness checks and focus on performance. Consequently, the fast methods will segfault or produce incorrect results if you supply incorrect data (vectors of different lengths, etc.). RombergEven needs a power of 2 + 1 points (so 9, 17, 33, 65, 129, 257, 513, 1025...) evenly spaced for it to work. Useful when control over accuracy is needed.

src/NumericalIntegration.jl

Lines changed: 141 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module NumericalIntegration
33
using LinearAlgebra
44
using Logging
55

6-
export integrate
6+
export integrate, cumul_integrate
77
export Trapezoidal, TrapezoidalEven, TrapezoidalFast, TrapezoidalEvenFast
88
export SimpsonEven, SimpsonEvenFast
99
export RombergEven
@@ -17,18 +17,46 @@ struct TrapezoidalFast <: IntegrationMethod end
1717
struct TrapezoidalEvenFast <: IntegrationMethod end
1818
struct SimpsonEven <: IntegrationMethod end # https://en.wikipedia.org/wiki/Simpson%27s_rule#Alternative_extended_Simpson.27s_rule
1919
struct SimpsonEvenFast <: IntegrationMethod end
20-
struct RombergEven{T<:AbstractFloat} <: IntegrationMethod
20+
struct RombergEven{T<:AbstractFloat} <: IntegrationMethod
2121
acc::T
2222
end # https://en.wikipedia.org/wiki/Romberg%27s_method
2323
RombergEven() = RombergEven(1e-12)
2424

2525
const HALF = 1//2
2626

27+
28+
#documentation
29+
30+
"""
31+
integrate(x,y...)
32+
33+
Compute numerical integral of y(x) from x=x[1] to x=x[end]. Return a scalar of the same type as the input. If not method is supplied, use TrapezdoialFast.
34+
"""
35+
function integrate(x,y...) end
36+
37+
38+
"""
39+
cumul_integrate(x,y...)
40+
41+
Compute cumulative numerical integral of y(x) from x=x[1] to x=x[end]. Return a vector with elements of the same type as the input. If not method is supplied, use TrapezdoialFast.
42+
"""
43+
function cumul_integrate(x,y...) end
44+
45+
#implementation
46+
2747
function _zero(x,y)
2848
ret = zero(eltype(x)) + zero(eltype(y))
29-
ret / 2
3049
end
3150

51+
function _zeros(x::AbstractVector,y::AbstractVector)
52+
ret = zeros(eltype(x),size(x)) + zeros(eltype(y),size(y))
53+
end
54+
55+
"""
56+
integrate(x::AbstractVector, y::AbstractVector, ::Trapezoidal)
57+
58+
Use Trapezoidal rule.
59+
"""
3260
function integrate(x::AbstractVector, y::AbstractVector, ::Trapezoidal)
3361
@assert length(x) == length(y) "x and y vectors must be of the same length!"
3462
retval = _zero(x,y)
@@ -38,11 +66,21 @@ function integrate(x::AbstractVector, y::AbstractVector, ::Trapezoidal)
3866
return HALF * retval
3967
end
4068

69+
"""
70+
integrate(x::AbstractVector, y::AbstractVector, ::TrapezoidalEven)
71+
72+
Use Trapezoidal rule, assuming evenly spaced vector x.
73+
"""
4174
function integrate(x::AbstractVector, y::AbstractVector, ::TrapezoidalEven)
4275
@assert length(x) == length(y) "x and y vectors must be of the same length!"
4376
return (x[2] - x[1]) * (HALF * (y[1] + y[end]) + sum(y[2:end-1]))
4477
end
4578

79+
"""
80+
integrate(x::AbstractVector, y::AbstractVector, ::TrapezoidalFast)
81+
82+
Use Trapezoidal rule. Unsafe method: no bound checking. This is the default when no method is supplied.
83+
"""
4684
function integrate(x::AbstractVector, y::AbstractVector, ::TrapezoidalFast)
4785
retval = _zero(x,y)
4886
@fastmath @simd for i in 1 : length(y)-1
@@ -51,6 +89,11 @@ function integrate(x::AbstractVector, y::AbstractVector, ::TrapezoidalFast)
5189
return HALF * retval
5290
end
5391

92+
"""
93+
integrate(x::AbstractVector, y::AbstractVector, ::TrapezoidalEvenFast)
94+
95+
Use Trapezoidal rule, assuming evenly spaced vector x. Unsafe method: no bound checking.
96+
"""
5497
function integrate(x::AbstractVector, y::AbstractVector, ::TrapezoidalEvenFast)
5598
retval = _zero(x,y)
5699
N = length(y) - 1
@@ -60,6 +103,11 @@ function integrate(x::AbstractVector, y::AbstractVector, ::TrapezoidalEvenFast)
60103
@inbounds return (x[2] - x[1]) * (retval + HALF*y[1] + HALF*y[end])
61104
end
62105

106+
"""
107+
integrate(x::AbstractVector, y::AbstractVector, ::SimpsonEven)
108+
109+
Use Simpson's rule, assuming evenly spaced vector x.
110+
"""
63111
function integrate(x::AbstractVector, y::AbstractVector, ::SimpsonEven)
64112
@assert length(x) == length(y) "x and y vectors must be of the same length!"
65113
retval = (17*y[1] + 59*y[2] + 43*y[3] + 49*y[4] + 49*y[end-3] + 43*y[end-2] + 59*y[end-1] + 17*y[end]) / 48
@@ -69,6 +117,11 @@ function integrate(x::AbstractVector, y::AbstractVector, ::SimpsonEven)
69117
return (x[2] - x[1]) * retval
70118
end
71119

120+
"""
121+
integrate(x::AbstractVector, y::AbstractVector, ::SimpsonEven)
122+
123+
Use Simpson's rule, assuming evenly spaced vector x. Unsafe method: no bound checking.
124+
"""
72125
function integrate(x::AbstractVector, y::AbstractVector, ::SimpsonEvenFast)
73126
@inbounds retval = 17*y[1] + 59*y[2] + 43*y[3] + 49*y[4]
74127
@inbounds retval += 49*y[end-3] + 43*y[end-2] + 59*y[end-1] + 17*y[end]
@@ -79,6 +132,16 @@ function integrate(x::AbstractVector, y::AbstractVector, ::SimpsonEvenFast)
79132
@inbounds return (x[2] - x[1]) * retval
80133
end
81134

135+
"""
136+
integrate(x::AbstractVector, y::AbstractMatrix, method; dims=2)
137+
138+
When y is an array, compute integral along dimension specified by dims (default 2: columns).
139+
"""
140+
function integrate(x::AbstractVector, y::AbstractMatrix, M::IntegrationMethod; dims=2)
141+
out = [integrate(x,selectdim(y,dims,j),M) for j=1:size(y,dims)]
142+
return out
143+
end
144+
82145
function integrate(x::AbstractVector, y::AbstractVector, m::RombergEven)
83146
@assert length(x) == length(y) "x and y vectors must be of the same length!"
84147
@assert ((length(x) - 1) & (length(x) - 2)) == 0 "Need length of vector to be 2^n + 1"
@@ -113,6 +176,80 @@ function integrate(x::AbstractVector, y::AbstractVector, m::RombergEven)
113176
@inbounds return rombaux[maxsteps, prevrow]
114177
end
115178

116-
integrate(x::AbstractVector, y::AbstractVector) = integrate(x, y, TrapezoidalFast())
117179

180+
# cumulative integrals
181+
182+
"""
183+
cumul_integrate(x::AbstractVector, y::AbstractVector, ::Trapezoidal)
184+
185+
Use Trapezoidal rule.
186+
"""
187+
function cumul_integrate(x::AbstractVector, y::AbstractVector, ::Trapezoidal)
188+
@assert length(x) == length(y) "x and y vectors must be of the same length!"
189+
retarr = _zeros(x,y)
190+
for i in 2 : length(y)
191+
retarr[i] = retarr[i-1] + (x[i] - x[i-1]) * (y[i] + y[i-1])
192+
end
193+
return HALF * retarr
118194
end
195+
196+
"""
197+
cumul_integrate(x::AbstractVector, y::AbstractVector, ::TrapezoidalEven)
198+
199+
Use Trapezoidal rule, assuming evenly spaced vector x.
200+
"""
201+
function cumul_integrate(x::AbstractVector, y::AbstractVector, ::TrapezoidalEven)
202+
@assert length(x) == length(y) "x and y vectors must be of the same length!"
203+
retarr = _zeros(x,y)
204+
for i in 2 : length(y)
205+
retarr[i] = retarr[i-1] + (y[i-1] + y[i])
206+
end
207+
return (x[2] - x[1]) * HALF * retarr
208+
end
209+
210+
"""
211+
cumul_integrate(x::AbstractVector, y::AbstractVector, ::TrapezoidalFast)
212+
213+
Use Trapezoidal rule. Unsafe method: no bound checking. This is the default when no method is supplied.
214+
"""
215+
function cumul_integrate(x::AbstractVector, y::AbstractVector, ::TrapezoidalFast)
216+
retarr = _zeros(x,y)
217+
@fastmath for i in 2 : length(y) #not sure if @simd can do anything here
218+
@inbounds retarr[i] = retarr[i-1] + (x[i] - x[i-1]) * (y[i] + y[i-1])
219+
end
220+
return HALF * retarr
221+
end
222+
223+
"""
224+
cumul_integrate(x::AbstractVector, y::AbstractVector, ::TrapezoidalEvenFast)
225+
226+
Use Trapezoidal rule, assuming evenly spaced vector x. Unsafe method: no bound checking.
227+
"""
228+
function cumul_integrate(x::AbstractVector, y::AbstractVector, ::TrapezoidalEvenFast)
229+
retarr = _zeros(x,y)
230+
@fastmath for i in 2 : length(y)
231+
@inbounds retarr[i] = retarr[i-1] + (y[i] + y[i-1])
232+
end
233+
@inbounds return (x[2] - x[1]) * HALF * retarr
234+
end
235+
236+
"""
237+
cumul_integrate(x::AbstractVector, y::AbstractMatrix, method; dims=2)
238+
239+
When y is an array, compute integral along each dimension specified by dims (default 2: columns)
240+
"""
241+
function cumul_integrate(x::AbstractVector, y::AbstractMatrix, M::IntegrationMethod; dims=2)
242+
return hcat([cumul_integrate(x,selectdim(y,dims,j),M) for j=1:size(y,dims)]...)
243+
end
244+
245+
246+
#default behaviour
247+
integrate(x::AbstractVector, y::AbstractVector) = integrate(x, y, Trapezoidal())
248+
249+
integrate(x::AbstractVector, y::AbstractMatrix; dims=2) = integrate(x, y, Trapezoidal(); dims=dims)
250+
251+
cumul_integrate(x::AbstractVector, y::AbstractVector) = cumul_integrate(x, y, Trapezoidal())
252+
253+
cumul_integrate(x::AbstractVector, y::AbstractMatrix; dims=2) = cumul_integrate(x, y, Trapezoidal(); dims=dims)
254+
255+
end # module

0 commit comments

Comments
 (0)