https://github.com/cran/spatstat
Raw File
Tip revision: 8ba424ae2810d8985064bafb88d4ad7c421f84a5 authored by Adrian Baddeley on 09 May 2016, 10:08:26 UTC
version 1.45-2
Tip revision: 8ba424a
closepairs.R
#
# closepairs.R
#
#   $Revision: 1.38 $   $Date: 2016/03/06 11:17:28 $
#
#  simply extract the r-close pairs from a dataset
# 
#  Less memory-hungry for large patterns
#

closepairs <- function(X, rmax, ...) {
  UseMethod("closepairs")
}
  
closepairs.ppp <- function(X, rmax, twice=TRUE,
                           what=c("all", "indices", "ijd"),
                           distinct=TRUE, neat=TRUE, 
                           ...) {
  verifyclass(X, "ppp")
  what <- match.arg(what)
  stopifnot(is.numeric(rmax) && length(rmax) == 1)
  stopifnot(is.finite(rmax))
  stopifnot(rmax >= 0)
  ordered <- list(...)$ordered
  if(missing(twice) && !is.null(ordered)) {
    warning("Obsolete argument 'ordered' has been replaced by 'twice'")
    twice <- ordered
  }
  npts <- npoints(X)
  null.answer <- switch(what,
                        all = {
                          list(i=integer(0),
                               j=integer(0),
                               xi=numeric(0),
                               yi=numeric(0),
                               xj=numeric(0),
                               yj=numeric(0),
                               dx=numeric(0),
                               dy=numeric(0),
                               d=numeric(0))
                        },
                        indices = {
                          list(i=integer(0),
                               j=integer(0))
                        },
                        ijd = {
                          list(i=integer(0),
                               j=integer(0),
                               d=numeric(0))
                        })
  if(npts == 0)
    return(null.answer)
  # sort points by increasing x coordinate
  oo <- fave.order(X$x)
  Xsort <- X[oo]
  # First make an OVERESTIMATE of the number of unordered pairs
  nsize <- ceiling(2 * pi * (npts^2) * (rmax^2)/area(Window(X)))
  nsize <- max(1024, nsize)
  if(nsize > .Machine$integer.max) {
    warning("Estimated number of close pairs exceeds maximum possible integer",
            call.=FALSE)
    nsize <- .Machine$integer.max
  }
  # Now extract pairs
  if(spatstat.options("closepairs.newcode")) {
    # ------------------- use new faster code ---------------------
    # fast algorithms collect each distinct pair only once
    got.twice <- FALSE
    ng <- nsize
    #
    x <- Xsort$x
    y <- Xsort$y
    r <- rmax
    storage.mode(x) <- "double"
    storage.mode(y) <- "double"
    storage.mode(r) <- "double"
    storage.mode(ng) <- "integer"
    switch(what,
           all = {
             z <- .Call("Vclosepairs",
                        xx=x, yy=y, rr=r, nguess=ng)
             if(length(z) != 9)
               stop("Internal error: incorrect format returned from Vclosepairs")
             i  <- z[[1]]  # NB no increment required
             j  <- z[[2]]
             xi <- z[[3]]
             yi <- z[[4]]
             xj <- z[[5]]
             yj <- z[[6]]
             dx <- z[[7]]
             dy <- z[[8]]
             d  <- z[[9]]
           },
           indices = {
             z <- .Call("VcloseIJpairs",
                        xx=x, yy=y, rr=r, nguess=ng)
             if(length(z) != 2)
               stop("Internal error: incorrect format returned from VcloseIJpairs")
             i  <- z[[1]]  # NB no increment required
             j  <- z[[2]]
           },
           ijd = {
             z <- .Call("VcloseIJDpairs",
                        xx=x, yy=y, rr=r, nguess=ng)
             if(length(z) != 3)
               stop("Internal error: incorrect format returned from VcloseIJDpairs")
             i  <- z[[1]]  # NB no increment required
             j  <- z[[2]]
             d  <- z[[3]]
           })

  } else {
    # ------------------- use older code --------------------------
    if(!distinct) {
      ii <- seq_len(npts)
      xx <- X$x
      yy <- X$y
      zeroes <- rep(0, npts)
      null.answer <- switch(what,
                            all = {
                              list(i=ii,
                                   j=ii,
                                   xi=xx,
                                   yi=yy,
                                   xj=xx,
                                   yj=yy,
                                   dx=zeroes,
                                   dy=zeroes,
                                   d=zeroes)
                            },
                            indices = {
                              list(i=ii,
                                   j=ii)
                            },
                            ijd = {
                              list(i=ii,
                                   j=ii,
                                   d=zeroes)
                            })
    }

    got.twice <- TRUE
    nsize <- nsize * 2
    z <-
      .C("Fclosepairs",
         nxy=as.integer(npts),
         x=as.double(Xsort$x),
         y=as.double(Xsort$y),
         r=as.double(rmax),
         noutmax=as.integer(nsize), 
         nout=as.integer(integer(1)),
         iout=as.integer(integer(nsize)),
         jout=as.integer(integer(nsize)), 
         xiout=as.double(numeric(nsize)),
         yiout=as.double(numeric(nsize)),
         xjout=as.double(numeric(nsize)),
         yjout=as.double(numeric(nsize)),
         dxout=as.double(numeric(nsize)),
         dyout=as.double(numeric(nsize)),
         dout=as.double(numeric(nsize)),
         status=as.integer(integer(1)))

    if(z$status != 0) {
      # Guess was insufficient
      # Obtain an OVERCOUNT of the number of pairs
      # (to work around gcc bug #323)
      rmaxplus <- 1.25 * rmax
      nsize <- .C("paircount",
                  nxy=as.integer(npts),
                  x=as.double(Xsort$x),
                  y=as.double(Xsort$y),
                  rmaxi=as.double(rmaxplus),
                  count=as.integer(integer(1)))$count
      if(nsize <= 0)
        return(null.answer)
      # add a bit more for safety
      nsize <- ceiling(1.1 * nsize) + 2 * npts
      # now extract points
      z <-
        .C("Fclosepairs",
           nxy=as.integer(npts),
           x=as.double(Xsort$x),
           y=as.double(Xsort$y),
           r=as.double(rmax),
           noutmax=as.integer(nsize), 
           nout=as.integer(integer(1)),
           iout=as.integer(integer(nsize)),
           jout=as.integer(integer(nsize)), 
           xiout=as.double(numeric(nsize)),
           yiout=as.double(numeric(nsize)),
           xjout=as.double(numeric(nsize)),
           yjout=as.double(numeric(nsize)),
           dxout=as.double(numeric(nsize)),
           dyout=as.double(numeric(nsize)),
           dout=as.double(numeric(nsize)),
           status=as.integer(integer(1)))
      if(z$status != 0)
        stop(paste("Internal error: C routine complains that insufficient space was allocated:", nsize))
    }
  # trim vectors to the length indicated
    npairs <- z$nout
    if(npairs <= 0)
      return(null.answer)
    actual <- seq_len(npairs)
    i  <- z$iout[actual]  # sic
    j  <- z$jout[actual]
    switch(what,
           indices={},
           all={
             xi <- z$xiout[actual]
             yi <- z$yiout[actual]
             xj <- z$xjout[actual]
             yj <- z$yjout[actual]
             dx <- z$dxout[actual]
             dy <- z$dyout[actual]
             d <-  z$dout[actual]
           },
           ijd = {
             d <- z$dout[actual]
           })
    # ------------------- end code switch ------------------------
  }
  
  # convert i,j indices to original sequence
  i <- oo[i]
  j <- oo[j]
  if(twice) {
    ## both (i, j) and (j, i) should be returned
    if(!got.twice) {
      ## duplication required
      iold <- i
      jold <- j
      i <- c(iold, jold)
      j <- c(jold, iold)
      switch(what,
             indices = { },
             ijd = {
               d <- rep(d, 2)
             },
             all = {
               xinew <- c(xi, xj)
               yinew <- c(yi, yj)
               xjnew <- c(xj, xi)
               yjnew <- c(yj, yi)
               xi <- xinew
               yi <- yinew
               xj <- xjnew
               yj <- yjnew
               dx <- c(dx, -dx)
               dy <- c(dy, -dy)
               d <- rep(d, 2)
             })
    }
  } else {
    ## only one of (i, j) and (j, i) should be returned
    if(got.twice) {
      ## remove duplication
      ok <- (i < j)
      i  <-  i[ok]
      j  <-  j[ok]
      switch(what,
             indices = { },
             all = {
               xi <- xi[ok]
               yi <- yi[ok]
               xj <- xj[ok]
               yj <- yj[ok]
               dx <- dx[ok]
               dy <- dy[ok]
               d  <-  d[ok]
             },
             ijd = {
               d  <-  d[ok]
             })
    } else if(neat) {
      ## enforce i < j
      swap <- (i > j)
      tmp <- i[swap]
      i[swap] <- j[swap]
      j[swap] <- tmp
      if(what == "all") {
        xinew <- ifelse(swap, xj, xi)
        yinew <- ifelse(swap, yj, yi)
        xjnew <- ifelse(swap, xi, xj)
        yjnew <- ifelse(swap, yi, yj)
        xi <- xinew
        yi <- yinew
        xj <- xjnew
        yj <- yjnew
        dx[swap] <- -dx[swap]
        dy[swap] <- -dy[swap]
      }
    } ## otherwise no action required
  }
  ## add pairs of identical points?
  if(!distinct) {
    ii <- seq_len(npts)
    xx <- X$x
    yy <- X$y
    zeroes <- rep(0, npts)
    i <- c(i, ii)
    j <- c(j, ii)
    switch(what,
           ijd={
             d  <- c(d, zeroes)
           },
           all = {
             xi <- c(xi, xx)
             yi <- c(yi, yy)
             xj <- c(xj, xx)
             yi <- c(yi, yy)
             dx <- c(dx, zeroes)
             dy <- c(dy, zeroes)
             d  <- c(d, zeroes)
           })
  }
  ## done
  switch(what,
         all = {
           answer <- list(i=i,
                          j=j,
                          xi=xi, 
                          yi=yi,
                          xj=xj,
                          yj=yj,
                          dx=dx,
                          dy=dy,
                          d=d)
         },
         indices = {
           answer <- list(i = i, j = j)
         },
         ijd = {
           answer <- list(i=i, j=j, d=d)
         })
  return(answer)
}

#######################

crosspairs <- function(X, Y, rmax, ...) {
  UseMethod("crosspairs")
}

crosspairs.ppp <- function(X, Y, rmax, what=c("all", "indices", "ijd"), ...) {
  verifyclass(X, "ppp")
  verifyclass(Y, "ppp")
  what <- match.arg(what)
  stopifnot(is.numeric(rmax) && length(rmax) == 1 && rmax >= 0)
  null.answer <- switch(what,
                        all = {
                          list(i=integer(0),
                               j=integer(0),
                               xi=numeric(0),
                               yi=numeric(0),
                               xj=numeric(0),
                               yj=numeric(0),
                               dx=numeric(0),
                               dy=numeric(0),
                               d=numeric(0))
                        },
                        indices = {
                          list(i=integer(0),
                               j=integer(0))
                        },
                        ijd = {
                          list(i=integer(0),
                               j=integer(0),
                               d=numeric(0))
                        })
  nX <- npoints(X)
  nY <- npoints(Y)
  if(nX == 0 || nY == 0) return(null.answer)
  # order patterns by increasing x coordinate
  ooX <- fave.order(X$x)
  Xsort <- X[ooX]
  ooY <- fave.order(Y$x)
  Ysort <- Y[ooY]
  if(spatstat.options("crosspairs.newcode")) {
    # ------------------- use new faster code ---------------------
    # First (over)estimate the number of pairs
    nsize <- ceiling(2 * pi * (rmax^2) * nX * nY/area(Window(Y)))
    nsize <- max(1024, nsize)
    if(nsize > .Machine$integer.max) {
      warning(
        "Estimated number of close pairs exceeds maximum possible integer",
        call.=FALSE)
      nsize <- .Machine$integer.max
    }
    # .Call
    Xx <- Xsort$x
    Xy <- Xsort$y
    Yx <- Ysort$x
    Yy <- Ysort$y
    r <- rmax
    ng <- nsize
    storage.mode(Xx) <- storage.mode(Xy) <- "double"
    storage.mode(Yx) <- storage.mode(Yy) <- "double"
    storage.mode(r) <- "double"
    storage.mode(ng) <- "integer"
    switch(what,
           all = {
             z <- .Call("Vcrosspairs",
                        xx1=Xx, yy1=Xy,
                        xx2=Yx, yy2=Yy,
                        rr=r, nguess=ng)
             if(length(z) != 9)
               stop("Internal error: incorrect format returned from Vcrosspairs")
             i  <- z[[1]]  # NB no increment required
             j  <- z[[2]]
             xi <- z[[3]]
             yi <- z[[4]]
             xj <- z[[5]]
             yj <- z[[6]]
             dx <- z[[7]]
             dy <- z[[8]]
             d  <- z[[9]]
           },
           indices = {
             z <- .Call("VcrossIJpairs",
                        xx1=Xx, yy1=Xy,
                        xx2=Yx, yy2=Yy,
                        rr=r, nguess=ng)
             if(length(z) != 2)
               stop("Internal error: incorrect format returned from VcrossIJpairs")
             i  <- z[[1]]  # NB no increment required
             j  <- z[[2]]
           }, 
           ijd = {
             z <- .Call("VcrossIJDpairs",
                        xx1=Xx, yy1=Xy,
                        xx2=Yx, yy2=Yy,
                        rr=r, nguess=ng)
             if(length(z) != 3)
               stop("Internal error: incorrect format returned from VcrossIJDpairs")
             i  <- z[[1]]  # NB no increment required
             j  <- z[[2]]
             d  <- z[[3]]
           })
           
  } else {
    # Older code 
    # obtain upper estimate of number of pairs
    # (to work around gcc bug 323)
    rmaxplus <- 1.25 * rmax
    nsize <- .C("crosscount",
                nn1=as.integer(X$n),
                x1=as.double(Xsort$x),
                y1=as.double(Xsort$y),
                nn2=as.integer(Ysort$n),
                x2=as.double(Ysort$x),
                y2=as.double(Ysort$y),
                rmaxi=as.double(rmaxplus),
                count=as.integer(integer(1)))$count
    if(nsize <= 0)
      return(null.answer)

    # allow slightly more space to work around gcc bug #323
    nsize <- ceiling(1.1 * nsize) + X$n + Y$n
    
    # now extract pairs
    z <-
      .C("Fcrosspairs",
         nn1=as.integer(X$n),
         x1=as.double(Xsort$x),
         y1=as.double(Xsort$y),
         nn2=as.integer(Y$n),
         x2=as.double(Ysort$x),
         y2=as.double(Ysort$y),
         r=as.double(rmax),
         noutmax=as.integer(nsize), 
         nout=as.integer(integer(1)),
         iout=as.integer(integer(nsize)),
         jout=as.integer(integer(nsize)), 
         xiout=as.double(numeric(nsize)),
         yiout=as.double(numeric(nsize)),
         xjout=as.double(numeric(nsize)),
         yjout=as.double(numeric(nsize)),
         dxout=as.double(numeric(nsize)),
         dyout=as.double(numeric(nsize)),
         dout=as.double(numeric(nsize)),
         status=as.integer(integer(1)))
    if(z$status != 0)
      stop(paste("Internal error: C routine complains that insufficient space was allocated:", nsize))
    # trim vectors to the length indicated
    npairs <- z$nout
    if(npairs <= 0)
      return(null.answer)
    actual <- seq_len(npairs)
    i  <- z$iout[actual] # sic
    j  <- z$jout[actual] 
    xi <- z$xiout[actual]
    yi <- z$yiout[actual]
    xj <- z$xjout[actual]
    yj <- z$yjout[actual]
    dx <- z$dxout[actual]
    dy <- z$dyout[actual]
    d <-  z$dout[actual]
  }
  # convert i,j indices to original sequences
  i <- ooX[i]
  j <- ooY[j]
  # done
  switch(what,
         all = {
           answer <- list(i=i,
                          j=j,
                          xi=xi, 
                          yi=yi,
                          xj=xj,
                          yj=yj,
                          dx=dx,
                          dy=dy,
                          d=d)
         },
         indices = {
           answer <- list(i=i, j=j)
         },
         ijd = {
           answer <- list(i=i, j=j, d=d)
         })
  return(answer)
}

closethresh <- function(X, R, S, twice=TRUE, ...) {
  # list all R-close pairs
  # and indicate which of them are S-close (S < R)
  # so that results are consistent with closepairs(X,S)
  verifyclass(X, "ppp")
  stopifnot(is.numeric(R) && length(R) == 1 && R >= 0)
  stopifnot(is.numeric(S) && length(S) == 1 && S >= 0)
  stopifnot(S < R)
  ordered <- list(...)$ordered
  if(missing(twice) && !is.null(ordered)) {
    warning("Obsolete argument 'ordered' has been replaced by 'twice'")
    twice <- ordered
  }
  npts <- npoints(X)
   if(npts == 0)
     return(list(i=integer(0), j=integer(0), t=logical(0)))
  # sort points by increasing x coordinate
  oo <- fave.order(X$x)
  Xsort <- X[oo]
  # First make an OVERESTIMATE of the number of pairs
  nsize <- ceiling(4 * pi * (npts^2) * (R^2)/area(Window(X)))
  nsize <- max(1024, nsize)
  if(nsize > .Machine$integer.max) {
    warning("Estimated number of close pairs exceeds maximum possible integer",
            call.=FALSE)
    nsize <- .Machine$integer.max
  }
  # Now extract pairs
  x <- Xsort$x
  y <- Xsort$y
  r <- R
  s <- S
  ng <- nsize
  storage.mode(x) <- "double"
  storage.mode(y) <- "double"
  storage.mode(r) <- "double"
  storage.mode(s) <- "double"
  storage.mode(ng) <- "integer"
  z <- .Call("Vclosethresh",
             xx=x, yy=y, rr=r, ss=s, nguess=ng)
  if(length(z) != 3)
    stop("Internal error: incorrect format returned from Vclosethresh")
  i  <- z[[1]]  # NB no increment required
  j  <- z[[2]]
  th <- as.logical(z[[3]])
  
  # convert i,j indices to original sequence
  i <- oo[i]
  j <- oo[j]
  # fast C code only returns i < j
  if(twice) {
    iold <- i
    jold <- j
    i <- c(iold, jold)
    j <- c(jold, iold)
    th <- rep(th, 2)
  }
  # done
  return(list(i=i, j=j, th=th))
}

crosspairquad <- function(Q, rmax, what=c("all", "indices")) {
  # find all close pairs X[i], U[j]
  stopifnot(inherits(Q, "quad"))
  what <- match.arg(what)
  X <- Q$data
  D <- Q$dummy
  clX <- closepairs(X=X, rmax=rmax, what=what)
  clXD <- crosspairs(X=X, Y=D, rmax=rmax, what=what)
  # convert all indices to serial numbers in union.quad(Q)
  # assumes data are listed first
  clXD$j <- npoints(X) + clXD$j
  result <- list(rbind(as.data.frame(clX), as.data.frame(clXD)))
  return(result)
}

back to top