Search code examples
rpackager-s4

Function runs from R console, but fails when built into package


I have a function that works perfectly when run directly from the R console. However, when I build and load a package containing exactly the same function, it throws an error when I call it.

#' Create divided difference matrix
#' @param x vector to process
#' @param d Dimension
#' @export
#' @return Output is divided difference matrix for use internally in regSmooth
divided.diff <- function (x, d){
  m  <- length(x)
  if (d == 0) {
    D <- Matrix::sparseMatrix(1:m,  1:m,  x  =  1,  dims  =  c(m,m))}
  else {
    dx  <-  x[(d + 1):m] - x[1:(m - d)]
    dl <- length(dx)
    V <- Matrix::sparseMatrix(1:dl,  1:dl,  x  =  1/dx,  dims  =  c(dl,dl))
    D  <-  d * V %*% diff(divided.diff(x, d - 1))}
  return (D)
}

Example: cut and paste the above function definition into R console, then run

divided.diff(1:5,2)

The output (as expected) is

3 x 5 sparse Matrix of class "dgCMatrix"

[1,] 1 -2 1 . .
[2,] . 1 -2 1 .
[3,] . . 1 -2 1

But if I use RStudio to build a package containing this function then install and load the package. then running the same command

divided.diff(1:5,2)

generates the error

Error in r[i1] : object of type 'S4' is not subsettable

Traceback is:

5 diff.default(divided.diff(x, d - 1))
4 diff(divided.diff(x, d - 1)) at regSmooth1.0.R#14
3 divided.diff(x, d - 1)
2 diff(divided.diff(x, d - 1)) at regSmooth1.0.R#14
1 divided.diff(1:5, 2)

I have no idea why this function will behave differently depending whether it is in a package or not. It appears to have something to do with building the package creating an S4 class object, but beyond that I am lost. Any explanation of this behaviour and pointers on how to get it working gratefully received.

Update: the DESCRIPTION file (redacted to remove contact details) is as follows

Package: regSmooth
Title: Data Smoothing by Regularization
Version: 1.0
Date: 2016-02-14
Author: xxx
Authors@R: person("xx", "xx", email = "zz", role = c("aut", "cre"))
Maintainer: xx  <[email protected]>
Description: This package provides functions to perform smoothing by  
Tikhonov regularization. Automated optimization of the regularization
parameter can optionally be conducted by cross-validation.
Depends: R (>= 3.1.1)
Imports: Matrix
License: GPL-2
RoxygenNote: 5.0.1

The NAMESPACE file is:

# Generated by roxygen2: do not edit by hand

export(divided.diff)
export(regSmooth)
export(regSmoothAuto)

Solution

  • Thanks to comment from Ben Bolker for leading me to the answer. The package Matrix creates an S4 version of the diff method for its classes. Even though the Matrix package is imported, we need to explicitly direct the function to use the S4 version of diff, rather than the generic version.

    Adding

    #' @importMethodsFrom Matrix diff
    

    to the function preamble, then running Roxygen2 generates the following line in NAMESPACE.

    importMethodsFrom(Matrix,diff)
    

    Which solves the problem.