knitr::opts_chunk$set( collapse = TRUE, comment = "#>" )
This package allows to evaluate multiple integrals like: $$ \int_{-5}^4\int_{-5}^{3-x}\int_{-10}^{6-x-y} f(x,y,z) \,\mathrm{d}z\,\mathrm{d}y\,\mathrm{d}x $$
Using base R only, a possibility is to nest the integrate
function to
evaluate such an integral:
f <- function(x, y, z) x*(x+1) - y*z^2 integrate(Vectorize(function(x) { integrate(Vectorize(function(y) { integrate(function(z) { f(x,y,z) }, -10, 6 - x - y)$value }), -5, 3 - x)$value }), -5, 4)
This approach works well in general. But it has one default: the estimate of the absolute error it returns is not reliable, because the estimates of the absolute errors of the inner integrals are not taken into account.
Here is how to proceed with the polyhedralCubature package.
The domain of integration is defined by the set of inequalities:
$$
\left{\begin{matrix}
-5 & \leq & x & \leq & 4 \
-5 & \leq & y & \leq & 3-x \
-10 & \leq & z & \leq & 6-x-y
\end{matrix}
\right.
$$
which is equivalent to
$$
\left{\begin{matrix}
-x & \leq & 5 \
x & \leq & 4 \
-y & \leq & 5 \
x+y & \leq & 3 \
-z & \leq & 10 \
x+y+z & \leq & 6
\end{matrix}
\right..
$$
This set of inequalities defines a convex polyhedron.
In order to use polyhedralCubature, you have to construct the matrix A
defining the linear combinations of the variables, and the vector b
giving
the upper bounds of these linear combinations:
A <- rbind( c(-1, 0, 0), # -x c( 1, 0, 0), # x c( 0,-1, 0), # -y c( 1, 1, 0), # x+y c( 0, 0,-1), # -z c( 1, 1, 1) # x+y+z ) b <- c(5, 4, 5, 3, 10, 6)
Then you can use the integrateOverPolyhedron
function:
library(polyhedralCubature) f <- function(x, y, z) { x*(x+1) - y*z^2 } integrateOverPolyhedron(f, A, b)
Alternatively, you can use the getAb
function to get A
and b
with the
help of the user-friendly syntax of the ompr package:
library(ompr) model <- MIPModel() %>% add_variable(x) %>% add_variable(y) %>% add_variable(z) %>% add_constraint(-5 <= x) %>% add_constraint(x <= 4) %>% add_constraint(-5 <= y) %>% add_constraint(y <= 3 - x) %>% add_constraint(-10 <= z) %>% add_constraint(z <= 6 - x - y) getAb(model)
Observe that the function $f$ is a polynomial here. Then one can get the
exact value of the integral by feeding integrateOverPolyhedron
with a
spray polynomial instead of a function:
library(spray) x <- lone(1, 3); y <- lone(2, 3); z <- lone(3, 3) p <- f(x, y, z) integrateOverPolyhedron(p, A, b)
The first step in integrateOverPolyhedron
consists in finding the vertices
of the polyhedron from the set of linear inequalities. It is possible, and
better, to use exact arithmetic for this step, by defining the matrix A
and the vector b
in character mode, each entry representing an integer or a
fraction like "1/3"
. Here we can simply do:
storage.mode(A) <- "character" storage.mode(b) <- "character"
But this is not the way to use if you have a fraction like 1/3
in an entry:
as.character(1/3)
Instead, you must directly define A
and b
in character mode and enter
"1/3"
for this entry.
Finally, when $f$ is a polynomial, you can get the exact value of the integral given as a fraction, by using a qspray polynomial instead of a spray polynomial:
library(qspray) x <- qlone(1); y <- qlone(2); z <- qlone(3) q <- f(x, y, z) integrateOverPolyhedron(q, A, b)
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.