[R] boundary check

Keith Jewell k.jewell at campden.co.uk
Fri Sep 24 14:29:40 CEST 2010


Hi,

Below Baptiste's message I attach  the R code and the .Rd documentation I 
treated as 'final', it may be slightly different from that in the Dec 2009 
post.

I did submit if for inclusion in the geometry package, but last time I 
checked it wasn't there.

I have found (and others have reported via private e-mail) that high 
dimensional data sets cause crashes (R exits with no warnings or messages). 
I tentatively believe this is a 'bug' in convhulln, but tracking it takes me 
to a complicated package and compiled code. It isn't a problem for me, so I 
can't make time to follow it up.

hth.

Keith J
------------------------------------
"baptiste auguie" <baptiste.auguie at googlemail.com> wrote in message 
news:AANLkTikf3+higWyHWyXEU2bRWqS0x9mtYWz9xzyQ_OLW at mail.gmail.com...
Hi,

I remember a discussion we had on this list a few months ago for a
better way to decide if a point is inside a convex hull. It eventually
lead to a R function in this post,

http://tolstoy.newcastle.edu.au/R/e8/help/09/12/8784.html

I don't know if it was included in the geometry package in the end.

HTH,

baptiste
---------------------------------------------
inhull <- function(testpts, calpts, hull=convhulln(calpts), 
tol=mean(mean(abs(calpts)))*sqrt(.Machine$double.eps)) {
#++++++++++++++++++++
# R implementation of the Matlab code by John D'Errico 04 Mar 2006 (Updated 
30 Oct 2006)
# downloaded from 
http://www.mathworks.com/matlabcentral/fileexchange/10226-inhull
# with some modifications and simplifications
#
# Efficient test for points inside a convex hull in n dimensions
#
#% arguments: (input)
#%  testpts - nxp array to test, n data points, in p dimensions
#%       If you have many points to test, it is most efficient to
#%       call this function once with the entire set.
#%
#%  calpts - mxp array of vertices of the convex hull, as used by
#%       convhulln.
#%
#%  hull - (OPTIONAL) tessellation (or triangulation) generated by convhulln
#%       If hull is left empty or not supplied, then it will be
#%       generated.
#%
#%  tol - (OPTIONAL) tolerance on the tests for inclusion in the
#%       convex hull. You can think of tol as the distance a point
#%       may possibly lie outside the hull, and still be perceived
#%       as on the surface of the hull. Because of numerical slop
#%       nothing can ever be done exactly here. I might guess a
#%       semi-intelligent value of tol to be
#%
#%         tol = 1.e-13*mean(abs(calpts(:)))
#%
#%       In higher dimensions, the numerical issues of floating
#%       point arithmetic will probably suggest a larger value
#%       of tol.
#%
# In this R implementation default 
tol=mean(mean(abs(calpts)))*sqrt(.Machine$double.eps)
#
# VALUE: Matlab returns a vector of TRUE (inside/on) or FALSE (outside)
#       This R implementation returns an integer vector of length n
#       1 = inside hull
#      -1 = inside hull
#       0 = on hull (to precision indicated by tol)
#--------------------------------------------------------
# ensure arguments are matrices (not data frames) and get sizes
   calpts <- as.matrix(calpts)
   testpts <- as.matrix(testpts)
   p <- ncol(calpts)   # columns in calpts
   cx <- nrow(testpts)  # rows in testpts
   nt <- nrow(hull)    # number of simplexes in hull
# find normal vectors to each simplex
   nrmls <- matrix(NA, nt, p)         # predefine each nrml as NA, 
degenerate
   degenflag <- matrix(TRUE, nt, 1)
   for (i in  1:nt) {
    nullsp <- t(Null(t(calpts[hull[i,-1],] - 
matrix(calpts[hull[i,1],],p-1,p, byrow=TRUE))))
    if (dim(nullsp)[1] == 1) { nrmls[i,] <- nullsp
       degenflag[i] <- FALSE}}
# Warn of degenerate faces, and remove corresponding normals
   if(sum(degenflag) > 0) warning(sum(degenflag)," degenerate faces in 
convex hull")
   nrmls <- nrmls[!degenflag,]
   nt <- nrow(nrmls)
# find center point in hull, and any (1st) point in the plane of each 
simplex
   center = colMeans(calpts)
   a <- calpts[hull[!degenflag,1],]
# scale normal vectors to unit length and ensure pointing inwards
   nrmls <- nrmls/matrix(apply(nrmls, 1, function(x) sqrt(sum(x^2))), nt, p)
   dp <- sign(apply((matrix(center, nt, p, byrow=TRUE)-a) * nrmls, 1, sum))
   nrmls <- nrmls*matrix(dp, nt, p)
# if  min across all faces of dot((x - a),nrml) is
#      +ve then x is inside hull
#      0   then x is on hull
#      -ve then x is outside hull
# Instead of dot((x - a),nrml)  use dot(x,nrml) - dot(a, nrml)
   aN <- diag(a %*% t(nrmls))
   val <- apply(testpts %*% t(nrmls) - matrix(aN, cx, nt, byrow=TRUE), 
1,min)
# code  values inside 'tol' to zero, return sign as integer
   val[abs(val) < tol] <- 0
   as.integer(sign(val))
}
----------------------------------------
\name{inhull}
\alias{inhull}
%- Also NEED an '\alias' for EACH other topic documented here.
\title{
Test if one set of N-D points is inside the convex hull defined by another 
set
}
\description{
R implementation of the Matlab code by John D'Errico 04 Mar 2006 (Updated 30 
Oct 2006)
downloaded from 
http://www.mathworks.com/matlabcentral/fileexchange/10226-inhull
with some modifications and simplifications
}
\usage{
inhull(testpts, calpts, hull = convhulln(calpts), tol = 
mean(mean(abs(calpts))) * sqrt(.Machine$double.eps))
}
%- maybe also 'usage' for other objects documented here.
\arguments{
  \item{testpts}{
numeric n x p array representing n points in p dimensions; converted to 
matrix by \code{as.matrix(testpts); each point is tested whether inside the 
convex hull (defined by calpts or hull). }
}
  \item{calpts}{
numeric m x p array representing m points in p dimensions; converted to 
matrix by \code{as.matrix(testpts). If 'hull' is not given, 
\code{geometry::convhulln(calpts)} is used to define the convex hull }
}
  \item{hull}{
(OPTIONAL) tessellation (or triangulation) generated by convhulln. If hull 
is left empty or not supplied, then it will be generated.
}
  \item{tol}{
(OPTIONAL) tolerance on the tests for inclusion in the convex hull. You can 
think of tol as the distance a point
may possibly lie outside the hull, and still be perceived
as on the surface of the hull. Because of numerical slop
nothing can ever be done exactly here.
}
}
\details{
%%  ~~ If necessary, more details than the description above ~~
}
\value{
An integer vector of length n \tabular{rl}{
1 \tab inside hull\cr
-1 \tab inside hull\cr
0 \tab on hull (to precision indicated by tol)
}}
\references{
\url{http://www.mathworks.com/matlabcentral/fileexchange/10226-inhull}
}
\author{
Keith Jewell 2009
}
\note{
submitted for inclusion in geometry package~
}

%% ~Make other sections like Warning with \section{Warning }{....} ~

\seealso{
%% ~~objects to See Also as \code{\link{help}}, ~~~
}
\examples{
set.seed(1234)
ps <- matrix(rnorm(4000),ncol=4)
xs <- matrix(rnorm(1200),ncol=4)
inhull(xs, ps)
  }
% Add one or more standard keywords, see file 'KEYWORDS' in the
% R documentation directory.
\keyword{ ~kwd1 }
\keyword{ ~kwd2 }% __ONLY ONE__ keyword per line



More information about the R-help mailing list