I am trying to pass an S4 object (sparse matrix of class dgCMatrix from the Matrix package) to a function in another package (Wrench). I am getting some very strange behavior that I am struggling to understand. I suspect it has something to do with S3/S4 method dispatch in R, a subject which I don't really understand.
Example setup:
library(Matrix)
library(Wrench)
M <- Matrix(10 + 1:28, 4, 7)
M[, c(2,4:6)] <- 0
sM <- as(M, "sparseMatrix")
print(sM)
# 4 x 7 sparse Matrix of class "dgCMatrix"
#
# [1,] 11 . 19 . . . 35
# [2,] 12 . 20 . . . 36
# [3,] 13 . 21 . . . 37
# [4,] 14 . 22 . . . 38
print(rowSums(sM))
# [1] 65 68 71 74
Next, I call the function, Wrench::wrench to do my analysis:
wrench(sM, colData=c('A','B','A','B','B','A','B'))
# Error in h(simpleError(msg, call)) :
# error in evaluating the argument 'i' in selecting a method for function '[': 'x' must be an array of at least two dimensions
Strange... I set a breakpoint on that line in RStudio, step into wrench, it starts like this:
function (mat, condition, etype = "w.marg.mean", ebcf = TRUE,
z.adj = FALSE, phi.adj = TRUE, detrend = FALSE, ...)
{
mat <- mat[rowSums(mat) > 0, ]
# ...
Step into that first line, into the call to rowSums(mat), and find myself in base::rowSums.
function (x, na.rm = FALSE, dims = 1L)
{
if (is.data.frame(x))
x <- as.matrix(x)
if (!is.array(x) || length(dn <- dim(x)) < 2L)
stop("'x' must be an array of at least two dimensions")
is.data.frame(x) is FALSE, is.array(x) is FALSE, the stop() function is invoked and the error originates from within there. OK, so base::rowSums doesn't know how to handle the sparse matrix and is raising the error...
But why is base::rowSums being invoked when rowSums(mat) is called within wrench, whereas Matrix::rowSums.dgCMatrix is being invoked and everything is working fine when I call rowSums(sM) in the outer scope?
More generally, how do I debug this kind of problem, where method dispatch is not happening as expected (especially within a package that I don't control)?
Other things I have tried:
I tried using
debugcall, i.e.eval(debugcall(rowSums(sM)))from the outer scope, and it takes me into somewhere inMatrixwhich calls some C code and ultimately the row sums are printed. When I try the same thing with the debugger paused withinWrench::wrench, I get an error:Browse[1]> eval(debugcall(rowSums(mat))) Error in .signatureFromCall(func, mcall, env) : trying to get slot "signature" from an object of a basic class ("function") with no slotsI have read the S4 chapter of Advanced R several times