The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
As an illustration of the uniformly
package, we will
show how to uniformly sample some points in a convex hull.
We give an illustration in dimension 3 (in dimension 2, use the
function runif_in_polygon
).
Let’s store the vertices of an icosahedron in a matrix
vs
:
vs <- t(rgl::icosahedron3d()$vb[1:3,])
head(vs)
#> [,1] [,2] [,3]
#> [1,] 0.000000 0.618034 1
#> [2,] 0.000000 0.618034 -1
#> [3,] 0.000000 -0.618034 1
#> [4,] 0.000000 -0.618034 -1
#> [5,] 0.618034 1.000000 0
#> [6,] 0.618034 -1.000000 0
The icosahedron is convex, therefore its convex hull is itself.
The delaunayn
function of the geometry
package calculates a “triangulation” (tetrahedralization in
dimension 3) of the convex hull of a set of points. We use it to get a
tetrahedralization of our icoshaedron:
library(geometry)
tetrahedra <- delaunayn(vs, options="Qz")
head(tetrahedra)
#> [,1] [,2] [,3] [,4]
#> [1,] 6 1 5 9
#> [2,] 6 3 1 9
#> [3,] 6 3 1 10
#> [4,] 6 12 4 2
#> [5,] 6 11 4 2
#> [6,] 6 11 5 9
Each row of the tetrahedra
matrix is a vector of four
identifiers of the vertices defining a tetrahedron.
Now, we calculate the volumes of each of these tetrahedra with the
volume_tetrahedron
function:
library(uniformly)
volumes <-
apply(tetrahedra, 1,
function(t){
volume_tetrahedron(vs[t[1],], vs[t[2],], vs[t[3],], vs[t[4],])
})
We normalize the volumes:
Now, here is the algorithm to uniformly sample a point in the icosahedron:
select a tetrahedron at random, with probability given by the normalized volumes;
uniformly sample a point in the picked tetrahedron.
That is:
i <- sample.int(nrow(tetrahedra), 1, prob=probs)
th <- tetrahedra[i,]
runif_in_tetrahedron(1, vs[th[1],], vs[th[2],], vs[th[3],], vs[th[4],])
#> [,1] [,2] [,3]
#> [1,] 0.5873218 0.7819155 -0.1332604
Let’s use the algorithm to sample 100 random points:
nsims <- 100
sims <- matrix(NA_real_, nrow=nsims, ncol=3)
for(k in 1:nsims){
th <- tetrahedra[sample.int(nrow(tetrahedra), 1, prob=probs),]
sims[k,] <- runif_in_tetrahedron(1, vs[th[1],], vs[th[2],], vs[th[3],], vs[th[4],])
}
library(rgl)
open3d(windowRect=c(100,100,600,600))
#> wgl
#> 1
shade3d(icosahedron3d(), color="red", alpha=0.3)
points3d(sims)
rglwidget()
We can proceed in the same way in higher dimension, using the
functions volume_simplex
and runif_in_simplex
instead of the functions volume_tetrahedron
and
runif_in_tetrahedron
.
Note that the convexity is not the sine qua non condition to
apply the above procedure: the ingredient we need is the “triangulation”
of the object. We took a convex shape because delaunayn
provides the triangulation of a convex shape.
Let’s give an example for a 3D star. Here is the star:
vs <- rbind(
c(7.889562, 1.150329, -2.173651),
c(2.212808, 1.150329, -2.230414),
c(0.068023, 1.150328, -7.923502),
c(-2.151306, 1.150329, -2.254857),
c(-7.817406, 1.150328, -2.261558),
c(-3.523133, 1.150328, 1.888122),
c(-4.869315, 1.150328, 6.987552),
c(-0.006854, 1.150329, 4.473047),
c(4.838127, 1.150328, 7.041885),
c(3.538153, 1.150329, 1.927652),
c(0.033757, 0.000000, -0.314657),
c(0.035668, 2.269531, -0.312831)
)
faces <- rbind(
c(1, 11, 2),
c(2, 11, 3),
c(3, 11, 4),
c(4, 11, 5),
c(5, 11, 6),
c(6, 11, 7),
c(7, 11, 8),
c(8, 11, 9),
c(9, 11, 10),
c(10, 11, 1),
c(1, 12, 10),
c(10, 12, 9),
c(9, 12, 8),
c(8, 12, 7),
c(7, 12, 6),
c(6, 12, 5),
c(5, 12, 4),
c(4, 12, 3),
c(3, 12, 2),
c(2, 12, 1)
)
open3d(windowRect=c(100,100,600,600))
#> wgl
#> 2
for(i in 1:nrow(faces)){
triangles3d(rbind(
vs[faces[i,1],],
vs[faces[i,2],],
vs[faces[i,3],]),
color="red", alpha=0.4)
}
rglwidget()
This star is not convex but it is star-shaped with respect to its centroid, and its faces are triangular. Therefore we get a tetrahedralization by joining the centroid to each of the triangular faces.
Let’s calculate the volumes of these tetrahedra:
centroid <- colMeans(vs)
volumes <- apply(faces, 1,function(f){
volume_tetrahedron(vs[f[1],], vs[f[2],], vs[f[3],], centroid)
})
probs <- volumes/sum(volumes)
Now we pick a face at random, with probability given by the normalized volumes, and we sample in the corresponding tetrahedron:
nsims <- 500
sims <- matrix(NA_real_, nrow=nsims, ncol=3)
for(k in 1:nsims){
f <- faces[sample.int(nrow(faces), 1, prob=probs),]
sims[k,] <- runif_in_tetrahedron(1, vs[f[1],], vs[f[2],], vs[f[3],], centroid)
}
And now, let’s add the sampled points:
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.