markmfredrickson / optmatch

Functions for optimal matching in R
https://markmfredrickson.github.io/optmatch
Other
47 stars 14 forks source link

`fullmatch()` doesn't dispatch properly in Rscript sessions #120

Closed fsavje closed 7 years ago

fsavje commented 8 years ago

I cannot get optmatch to work properly with Rscript. The code works excellent in interactive mode, but whenever ran in batch mode, it complains that my input is invalid. The following code replicates the error:

# Content of "test_opt.R"
library("optmatch")
my_data <- data.frame(treatment = factor(c("T", "C", "T", "C", "T", "C", "T", "C", "T", "C")),
                                            x1 = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
                                            x2 = c(1, 2, 3, 4, 5, 5, 4, 3, 2, 1))
my_matches <- fullmatch(treatment ~ x1 + x2, data = my_data)
print(my_matches)

Now if I run this interactively, as follows, it works fine:

$ R
R version 3.3.1 (2016-06-21) -- "Bug in Your Hair"
[...]
> source("test_opt.R")
Loading required package: survival
The optmatch package has an academic license. Enter relaxinfo() for more information.
  1   2   3   4   5   6   7   8   9  10 
1.1 1.1 1.2 1.2 1.3 1.3 1.4 1.4 1.5 1.5
> q()

However, when I run exactly the same with Rscript, it complains:

$ Rscript test_opt.R 
Loading required package: survival
The optmatch package has an academic license. Enter relaxinfo() for more information.
Error in fullmatch.default(m, min.controls = min.controls, max.controls = max.controls,  : 
  Invalid input, must be a potential argument to match_on
Calls: fullmatch ... fullmatch.default -> fullmatch -> fullmatch.default
Execution halted

I'm running R version 3.3.1 with optmatch version 0.9-6. My full sessionInfo() print out:

R version 3.3.1 (2016-06-21)
Platform: x86_64-apple-darwin13.4.0 (64-bit)
Running under: OS X 10.11.6 (El Capitan)

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] optmatch_0.9-6  survival_2.39-5

loaded via a namespace (and not attached):
 [1] Matrix_1.2-6    RItools_0.1-15  tools_3.3.1     SparseM_1.72    abind_1.4-5    
 [6] Rcpp_0.12.6     splines_3.3.1   grid_3.3.1      svd_0.4         digest_0.6.10  
[11] xtable_1.8-2    lattice_0.20-33

Thanks in advance!

@markmfredrickson

benthestatistician commented 8 years ago

I can reproduce the issue on my setup (R 3.2.3 ; x86_64-apple-darwin15.3.0 ; optmatch_0.9-6). For some reason fullmatch() isn't dispatching properly in the Rscript session.

My "test_opt2.R", as follows, also kills Rscript but runs fine in an interactive session:

library("optmatch")
my_data <- data.frame(treatment = factor(c("T", "C", "T", "C", "T", "C", "T", "C", "T", "C")),
                                            x1 = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
                                            x2 = c(1, 2, 3, 4, 5, 5, 4, 3, 2, 1))
my_matchon <- match_on(treatment ~ x1 + x2, data = my_data)
class(my_matchon)
my_matchon
my_matches <- fullmatch(my_matchon, data = my_data)

Rscript gives

$ Rscript test_opt2.R
Loading required package: survival
The optmatch package has an academic license. Enter relaxinfo() for more information.
[1] "DenseMatrix"
attr(,"package")
[1] "optmatch"
An object of class "DenseMatrix"
         control
treatment         2         4         6         8        10
        1 0.7071068 2.1213203 2.9832868 2.5495098 2.8460499
        3 0.7071068 0.7071068 1.5811388 1.5811388 2.5495098
        5 2.1213203 0.7071068 0.3162278 1.5811388 2.9832868
        7 2.0248457 0.9486833 0.7071068 0.7071068 2.1213203
        9 2.2135944 2.0248457 2.1213203 0.7071068 0.7071068
Slot "call":
match_on(x = treatment ~ x1 + x2, data = my_data)

Error in fullmatch.default(my_matchon, data = my_data) : 
  Invalid input, must be a potential argument to match_on
Calls: fullmatch -> fullmatch.default
Execution halted

whereas when I source() the file interactively, it runs fine. Interesting, the following both also work:

 R --vanilla < test_opt.R
 R --vanilla < test_opt2.R

@fsavje, perhaps this could serve you as a workaround until we get the chance to troubleshoot this further? In any event, thanks very much for taking the trouble to isolate the problem in a reproducible example!

fsavje commented 8 years ago

@benthestatistician Thank you, I think that will work for my purposes. No worries with the example, I'm happy that I could help.

josherrickson commented 8 years ago

Debugging this a bit. Going to drop notes as I go in case I get busy and someone else picks up the ball.

When run interactively, the chain of calls goes:

fullmatch -> fullmatch.default -> fullmatch -> fullmatch.matrix

The first arrow is dispatching the original fullmatch call on the formula argument, and we don't define fullmatch.formula.

The second arrow is a fresh version of fullmatch, passing as an argument the result of this match_on call . Correctly, this is a DenseMatrix which inherits matrix, so everything proceeds nicely at the third arrow, dispatching to fullmatch.matrix.

On the other hand, when run via Rscript, the chain of calls is

fullmatch -> fullmatch.default -> fullmatch -> fullmatch.default

During the 2nd fullmatch call, it appears to be correctly creating a DenseMatrix object, but then is dispatching back to fullmatch.default instead of fullmatch.DenseMatrix.

josherrickson commented 8 years ago

PS thank you for such a detailed report @fsavje!

josherrickson commented 8 years ago

Here's some debug output. This output all comes immediately after entering fullmatch.default:

[1] "In fullmatch.default"
[1] "x is a:  formula"
[1] "Does x inherit matrix? FALSE"
[1] "In fullmatch.default"
[1] "x is a:  DenseMatrix"
[1] "Does x inherit matrix? FALSE"

Obviously that last line is the big issue. For some reason, while in Rscript, DenseMatrix is not properly inheriting (or things aren't properly dispatching down to) matrix.

josherrickson commented 8 years ago
[1] "In fullmatch.default"
[1] "x is a:  formula, oldClass"
[1] "Is x a matrix? FALSE"
[1] "Does x inherit matrix? FALSE"
[1] "In fullmatch.default"
[1] "x is a:  DenseMatrix, matrix, array, mMatrix, structure, vector"
[1] "Is x a matrix? TRUE" # checks is(x ,"matrix")
[1] "Does x inherit matrix? FALSE" # checks inherits(x, "matrix")

Some oddity with is vs inherits. Changing the error check to use is instead of inherits moves past that stopping point, but it still fails to properly dispatch, eventually trying to call match_on.DenseMatrix and failing to (again) properly dispatch to match_on.matrix.

benthestatistician commented 7 years ago

Could the problem here be as simple as not loading the matrix package explicitly during the Rscript session? Per Wickham's Advanced R, "OO Field Guide":

All S4 related code is stored in the methods package. This package is always available when you’re running R interactively, but may not be available when running R in batch mode. For this reason, it’s a good idea to include an explicit library(methods) whenever you’re using S4.

benthestatistician commented 7 years ago

Hmm, with R version 3.4.0, optmatch version 0.9.7, I can no longer reproduce the problem using @josherrickson's above test_opt2.R.

On another computer, running R version 3.2.4 + optmatch version 0.9.6, test_opt2.R reproduces the problem, but the problem is also circumvented by adding an explicit library(methods) to the top of the file.

I think this solves the problem: @fsavje , if you're still interested you can circumvent this issue either by including library(methods) in your scripts or by upgrading your R.

fsavje commented 7 years ago

@benthestatistician Great, thanks! I can confirm that there's no error when using R 3.4.0 and optmatch 0.9.7. (Haven't tested the library(methods) route.)