R/interact.R

Defines functions instantiate.interact versionstring.interact interactionorder.ppm interactionorder.interact interactionorder.isf interactionorder interactionfamilyname as.isf as.interact.interact as.interact reincarnate.interact newstyle.coeff.handling outdated.interact parameters.interact is.poisson.interact update.interact is.interact print.interact print.isf

Documented in as.interact as.interact.interact as.isf instantiate.interact interactionfamilyname interactionorder interactionorder.interact interactionorder.isf interactionorder.ppm is.interact is.poisson.interact newstyle.coeff.handling outdated.interact parameters.interact print.interact print.isf reincarnate.interact update.interact versionstring.interact

#
#	interact.S
#
#
#	$Revision: 1.32 $	$Date: 2022/03/07 04:00:24 $
#
#	Class 'interact' representing the interpoint interaction
#               of a point process model
#              (e.g. Strauss process with a given threshold r)
#
#       Class 'isf' representing a generic interaction structure
#              (e.g. pairwise interactions)
#
#	These do NOT specify the "trend" part of the model,
#	only the "interaction" component.
#
#               The analogy is:
#
#                       glm()             ppm()
#
#                       model formula     trend formula
#
#                       family            interaction
#
#               That is, the 'systematic' trend part of a point process
#               model is specified by a 'trend' formula argument to ppm(),
#               and the interpoint interaction is specified as an 'interact'
#               object.
#
#       You only need to know about these classes if you want to
#       implement a new point process model.
#
#       THE DISTINCTION:
#       An object of class 'isf' describes an interaction structure
#       e.g. pairwise interaction, triple interaction,
#       pairwise-with-saturation, Dirichlet interaction.
#       Think of it as determining the "order" of interaction
#       but not the specific interaction potential function.
#
#       An object of class 'interact' completely defines the interpoint
#       interactions in a specific point process model, except for the
#       regular parameters of the interaction, which are to be estimated
#       by ppm() or otherwise. An 'interact' object specifies the values
#       of all the 'nuisance' or 'irregular' parameters. An example
#       is the Strauss process with a given, fixed threshold r
#       but with the parameters beta and gamma undetermined.
#
#       DETAILS:
#
#       An object of class 'isf' contains the following:
#
#	     $name               Name of the interaction structure         
#                                        e.g. "pairwise"
#
#	     $print		 How to 'print()' this object
#				 [A function; invoked by the 'print' method
#                                 'print.isf()']
#
#            $eval               A function which evaluates the canonical
#                                sufficient statistic for an interaction
#                                of this general class (e.g. any pairwise
#                                interaction.)
#
#       If lambda(u,X) denotes the conditional intensity at a point u
#       for the point pattern X, then we assume
#                  log lambda(u, X) = theta . S(u,X)
#       where theta is the vector of regular parameters,
#       and we call S(u,X) the sufficient statistic.
#
#       A typical calling sequence for the $eval function is
#
#            (f$eval)(X, U, E, potentials, potargs, correction)
#
#       where X is the data point pattern, U is the list of points u
#       at which the sufficient statistic S(u,X) is to be evaluated,
#       E is a logical matrix equivalent to (X[i] == U[j]),
#       $potentials defines the specific potential function(s) and
#       $potargs contains any nuisance/irregular parameters of these
#       potentials [the $potargs are passed to the $potentials without
#       needing to be understood by $eval.]
#       $correction is the name of the edge correction method.
#
#
#       An object of class 'interact' contains the following:
#
#
#            $name               Name of the specific potential
#                                        e.g. "Strauss"
#
#            $family              Object of class "isf" describing
#                                the interaction structure
#
#            $pot	         The interaction potential function(s)
#                                -- usually a function or list of functions.
#                                (passed as an argument to $family$eval)
#
#            $par                list of any nuisance/irregular parameters
#                                (passed as an argument to $family$eval)
#
#            $parnames           vector of long names/descriptions
#                                of the parameters in 'par'
#
#            $init()             initialisation action
#                                or NULL indicating none required
#
#            $update()           A function to modify $par
#                                [Invoked by 'update.interact()']
#                                or NULL indicating a default action
#
#	     $print		 How to 'print()' this object
#				 [Invoked by 'print' method 'print.interact()']
#                                or NULL indicating a default action
#
# --------------------------------------------------------------------------

print.isf <- function(x, ...) {
  if(is.null(x)) return(invisible(NULL))
  verifyclass(x, "isf")
  if(!is.null(x$print))
    (x$print)(x)
  invisible(NULL)
}

print.interact <- function(x, ..., family, brief=FALSE, banner=TRUE) {
  verifyclass(x, "interact")
  if(missing(family)) family <- waxlyrical('extras')
  #' Print name of model
  if(banner) {
    if(family && !brief && !is.null(xf <- x$family))
      print.isf(xf)
    splat(if(!brief) "Interaction:" else NULL, x$name, sep="")
  }
  # Now print the parameters
  if(!is.null(x$print)) {
     (x$print)(x)
  } else {
    # default
    # just print the parameter names and their values
    pwords <- x$parnames
    parval <- x$par
    pwords <- paste(toupper(substring(pwords, 1, 1)),
                    substring(pwords, 2), sep="")
    isnum <- sapply(parval, is.numeric)
    parval[isnum] <- lapply(parval[isnum], signif,
                            digits=getOption("digits"))
    splat(paste(paste0(pwords, ":\t", parval), collapse="\n"))
  }
  invisible(NULL)
}

is.interact <- function(x) { inherits(x, "interact") }

update.interact <- function(object, ...) {
  verifyclass(object, "interact")
  if(!is.null(object$update))
    (object$update)(object, ...)
  else {
    # Default
    # First update the version
    if(outdated.interact(object))
      object <- reincarnate.interact(object)
    # just match the arguments in "..."
    # with those in object$par and update them
    want <- list(...)
    if(length(want) > 0) {
      m <- match(names(want),names(object$par))
      nbg <- is.na(m)
      if(any(nbg)) {
        which <- paste((names(want))[nbg])
        warning(paste("Arguments not matched: ", which))
      }
      m <- m[!nbg]
      object$par[m] <- want
    }
    # call object's own initialisation routine
    if(!is.null(object$init))
      (object$init)(object)
    object
  }    
}

  
is.poisson.interact <- function(x) {
  verifyclass(x, "interact")
  is.null(x$family)
}

parameters.interact <- function(model, ...) {
  model$par
}

# Test whether interact object was made by an older version of spatstat

outdated.interact <- function(object) {
  ver <- object$version
  older <- is.null(ver) || (package_version(ver) < versionstring.spatstat())
  return(older)
}


# Test whether the functions in the interaction object
# expect the coefficient vector to contain ALL coefficients,
# or only the interaction coefficients.
# This change was introduced in 1.11-0, at the same time
# as interact objects were given version numbers.

newstyle.coeff.handling <- function(object) {
  stopifnot(inherits(object, "interact"))  
  ver <- object$version
  old <- is.null(ver) || (package_version(ver) < "1.11")
  return(!old)
}

# ######
#
# Re-create an interact object in the current version of spatstat
#
# 

reincarnate.interact <- function(object) {
  # re-creates an interact object in the current version of spatstat

  if(!is.null(object$update)) {
    newobject <- (object$update)(object)
    return(newobject)
  }
  
  par <- object$par
#  pot <- object$pot
  name <- object$name
  
  # get creator function
  creator <- object$creator
  if(is.null(creator)) {
    # old version: look up list
    creator <- .Spatstat.Old.InteractionList[[name]]
    if(is.null(creator))
      stop(paste("Don't know how to update", sQuote(name),
                 "to current version of spatstat"))
  }
  if(is.character(creator))
    creator <- get(creator)
  if(!is.function(creator) && !is.expression(creator))
    stop("Internal error: creator is not a function or expression")

  # call creator
  if(is.expression(creator)) 
    newobject <- eval(creator)
  else {
    # creator is a function
  
    # It's assumed that the creator function's arguments are
    # either identical to components of 'par' (the usual case)
    # or to one of the components of the object itself (Ord, Saturated)
    # or to printfun=object$print (Pairwise).
  
    argnames <- names(formals(creator))
    available <- append(par, object)
    available <- append(available, list(printfun=object$print))
    ok <- argnames %in% names(available)
    if(!all(ok))
      stop(paste("Internal error:",
                 ngettext(sum(!ok), "argument", "arguments"),
                 paste(sQuote(argnames[!ok]), collapse=", "),
                 "in creator function were not understood"))
    newobject <- do.call(creator, available[argnames])
  }
  
  if(!inherits(newobject, "interact"))
    stop("Internal error: creator did not return an object of class interact")

  return(newobject)
}


# This list is necessary to deal with older formats of 'interact' objects
# which did not include the creator name

.Spatstat.Old.InteractionList <-
  list("Diggle-Gratton process"    = "DiggleGratton",
       "Geyer saturation process"  = "Geyer",
       "Lennard-Jones potential"   = "LennardJones",
       "Multitype Strauss process" = "MultiStrauss",
       "Multitype Strauss Hardcore process" = "MultiStraussHard",
       "Ord process with threshold potential"="OrdThresh",
       "Piecewise constant pairwise interaction process"="PairPiece",
       "Poisson process"           = "Poisson",
       "Strauss process"           = "Strauss",
       "Strauss - hard core process" = "StraussHard",
       "Soft core process" = "Softcore",
       # weird ones:
       "Ord process with user-defined potential" = expression(Ord(object$pot)),
       "Saturated process with user-defined potential"
          =expression(Saturated(object$pot)),
       "user-defined pairwise interaction process"=
       expression(
           Pairwise(object$pot,
                    par=object$par,
                    parnames=object$parnames,
                    printfun=object$print))
           
     )
       
as.interact <- function(object) {
  UseMethod("as.interact")
}

as.interact.interact <- function(object) {
  verifyclass(object, "interact")
  return(object)
}

as.isf <- function(object) {
  if(inherits(object, "isf")) return(object)
  object <- as.interact(object)
  return(object$family)
}

interactionfamilyname <- function(object) { as.isf(object)$name }

interactionorder <- function(object) {
  UseMethod("interactionorder")
}

interactionorder.isf <- function(object) {
  return(object$order %orifnull% Inf)
}

interactionorder.interact <- function(object) {
  ## order may be specified in the interaction object itself (e.g. in a hybrid, or Poisson)
  ## but is usually determined by the interaction family
  object$order %orifnull% interactionorder(object$family)
}

interactionorder.fii <- interactionorder.ppm <- function(object) {
  interactionorder(as.interact(object))
}

# Extract version string from interact object

versionstring.interact <- function(object) {
  verifyclass(object, "interact")
  v <- object$version
  return(v)  # NULL before 1.11-0
}

#### internal code for streamlining initialisation of interactions
#
#    x should be a partially-completed 'interact' object
#

instantiate.interact <- function(x, par=NULL) {
  if(is.character(x$family)) x$family <- get(x$family)
  # set parameter values
  x$par    <- par
  # validate parameters
  if(!is.null(x$init)) x$init(x)
  x$version <- versionstring.spatstat()
  return(x)
}

Try the spatstat.core package in your browser

Any scripts or data that you put into this service are public.

spatstat.core documentation built on May 18, 2022, 9:05 a.m.