-
-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #173 from IlianPihlajamaa/master
add Trapezoidal rule
- Loading branch information
Showing
11 changed files
with
392 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# Integrating pre-sampled data | ||
|
||
In some cases, instead of a function that acts as integrand, | ||
one only possesses a list of data points `y` at a set of sampling | ||
locations `x`, that must be integrated. This package contains functionality | ||
for doing that. | ||
|
||
## Example | ||
|
||
Say, by some means we have generated a dataset `x` and `y`: | ||
```example 1 | ||
using Integrals # hide | ||
f = x -> x^2 | ||
x = range(0, 1, length=20) | ||
y = f.(x) | ||
``` | ||
|
||
Now, we can integrate this data set as follows: | ||
|
||
```example 1 | ||
problem = SampledIntegralProblem(y, x) | ||
method = TrapezoidalRule() | ||
solve(problem, method) | ||
``` | ||
|
||
The exact aswer is of course \$ 1/3 \$. | ||
|
||
## Details | ||
|
||
### Non-equidistant grids | ||
|
||
If the sampling points `x` are provided as an `AbstractRange` | ||
(constructed with the `range` function for example), faster methods are used that take advantage of | ||
the fact that the points are equidistantly spaced. Otherwise, general methods are used for | ||
non-uniform grids. | ||
|
||
Example: | ||
|
||
```example 2 | ||
using Integrals # hide | ||
f = x -> x^7 | ||
x = [0.0; sort(rand(1000)); 1.0] | ||
y = f.(x) | ||
problem = SampledIntegralProblem(y, x) | ||
method = TrapezoidalRule() | ||
solve(problem, method) | ||
``` | ||
|
||
### Evaluating multiple integrals at once | ||
|
||
If the provided data set `y` is a multidimensional array, the integrals are evaluated across only one | ||
of its axes. For performance reasons, the last axis of the array `y` is chosen by default, but this can be modified with the `dim` | ||
keyword argument to the problem definition. | ||
|
||
```example 3 | ||
using Integrals # hide | ||
f1 = x -> x^2 | ||
f2 = x -> x^3 | ||
f3 = x -> x^4 | ||
x = range(0, 1, length=20) | ||
y = [f1.(x) f2.(x) f3.(x)] | ||
problem = SampledIntegralProblem(y, x; dim=1) | ||
method = TrapezoidalRule() | ||
solve(problem, method) | ||
``` | ||
|
||
### Supported methods | ||
|
||
Right now, only the `TrapezoidalRule` is supported, [see wikipedia](https://en.wikipedia.org/wiki/Trapezoidal_rule). | ||
|
||
```@docs | ||
TrapezoidalRule | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
abstract type AbstractWeights end | ||
|
||
# must have field `n` for length, and a field `h` for stepsize | ||
abstract type UniformWeights <: AbstractWeights end | ||
@inline Base.iterate(w::UniformWeights) = (0 == w.n) ? nothing : (w[1], 1) | ||
@inline Base.iterate(w::UniformWeights, i) = (i == w.n) ? nothing : (w[i+1], i+1) | ||
Base.length(w::UniformWeights) = w.n | ||
Base.eltype(w::UniformWeights) = typeof(w.h) | ||
Base.size(w::UniformWeights) = (length(w), ) | ||
|
||
# must contain field `x` which are the sampling points | ||
abstract type NonuniformWeights <: AbstractWeights end | ||
@inline Base.iterate(w::NonuniformWeights) = (0 == length(w.x)) ? nothing : (w[firstindex(w.x)], firstindex(w.x)) | ||
@inline Base.iterate(w::NonuniformWeights, i) = (i == lastindex(w.x)) ? nothing : (w[i+1], i+1) | ||
Base.length(w::NonuniformWeights) = length(w.x) | ||
Base.eltype(w::NonuniformWeights) = eltype(w.x) | ||
Base.size(w::NonuniformWeights) = (length(w), ) | ||
|
||
_eachslice(data::AbstractArray; dims=ndims(data)) = eachslice(data; dims=dims) | ||
_eachslice(data::AbstractArray{T, 1}; dims=ndims(data)) where T = data | ||
|
||
|
||
# these can be removed when the Val(dim) is removed from SciMLBase | ||
dimension(::Val{D}) where {D} = D | ||
dimension(D::Int) = D | ||
|
||
|
||
function evalrule(data::AbstractArray, weights, dim) | ||
fw = zip(_eachslice(data, dims=dim), weights) | ||
next = iterate(fw) | ||
next === nothing && throw(ArgumentError("No points to integrate")) | ||
(f1, w1), state = next | ||
out = w1 * f1 | ||
next = iterate(fw, state) | ||
if isbits(out) | ||
while next !== nothing | ||
(fi, wi), state = next | ||
out += wi * fi | ||
next = iterate(fw, state) | ||
end | ||
else | ||
while next !== nothing | ||
(fi, wi), state = next | ||
out .+= wi .* fi | ||
next = iterate(fw, state) | ||
end | ||
end | ||
return out | ||
end | ||
|
||
|
||
# can be reused for other sampled rules, which should implement find_weights(x, alg) | ||
|
||
function init_cacheval(alg::SciMLBase.AbstractIntegralAlgorithm, prob::SampledIntegralProblem) | ||
find_weights(prob.x, alg) | ||
end | ||
|
||
function __solvebp_call(cache::SampledIntegralCache, alg::SciMLBase.AbstractIntegralAlgorithm; kwargs...) | ||
dim = dimension(cache.dim) | ||
err = nothing | ||
data = cache.y | ||
grid = cache.x | ||
if cache.isfresh | ||
cache.cacheval = find_weights(grid, alg) | ||
cache.isfresh = false | ||
end | ||
weights = cache.cacheval | ||
I = evalrule(data, weights, dim) | ||
prob = build_problem(cache) | ||
return SciMLBase.build_solution(prob, alg, I, err, retcode = ReturnCode.Success) | ||
end |
Oops, something went wrong.