R: Understand the ".call" function in R - r

I am using R. I am working with a library called "mco" : https://cran.r-project.org/web/packages/mco/index.html
I was looking over some of the function definitions used in this library at the github repository, for example: https://github.com/olafmersmann/mco/blob/master/R/nsga2.R
Over here, I came across the following lines of code:
res <- .Call(do_nsga2,
ff, cf, sys.frame(),
as.integer(odim),
as.integer(cdim),
as.integer(idim),
lower.bounds, upper.bounds,
as.integer(popsize), as.integer(generations),
cprob, as.integer(cdist),
mprob, as.integer(mdist))
if (1 == length(res)) {
res <- res[[1]]
names(res) <- c("par", "value", "pareto.optimal")
class(res) <- c("nsga2", "mco")
} else {
for (i in 1:length(res)) {
names(res[[i]]) <- c("par", "value", "pareto.optimal")
class(res[[i]]) <- c("nsga2", "mco")
}
class(res) <- "nsga2.collection"
}
return (res)
}
In the very first line of this code, it makes reference to some object called "do_nsga2". But apart from this function, I can't find any reference to "do_nsga2" within the entire package.
Does anyone know what exactly is being "called"?
Thanks
Note: I am trying to copy/paste all the functions from the github repository into my R session, since I am working with an older computer in which directly installing libraries from CRAN is not possible. When I tried to copy/paste all these functions, I got the following error:
Error in nsga2....
object 'do_nsga2' not found

Related

Use Rcpp function in foreach %dopar%

I have created an Rcpp test package called "test" using the Rcpp package skeleton to try to run c++ code in parallel but keep running into errors. I'm running R 4.1.2 on Mac OS and have updated all parallel computing packages. I added to the package skeleton an R script containing
# wrap c++ function in R function
test_func <- function()
{
return(rcpp_hello_world())
}
# attempt to parallelize
parallelize <- function()
{
# create cluster
cl <- parallel::makeCluster(parallel::detectCores() - 1)
parallel::clusterExport(cl,varlist = c("test_func","rcpp_hello_world"),envir = environment())
doParallel::registerDoParallel(cl)
# call test_func in parallel
res <- foreach::`%dopar%`(foreach::foreach(i = 1:5,.combine = c),ex = {test_func()})
# clean up
parallel::stopCluster(cl)
return(res)
}
I loaded my package using devtools::load_all(), but typing parallelize() in my console I get the error "Error in { : task 1 failed - "object '_test_rcpp_hello_world' not found" ". When I add "_test_rcpp_hello_world" to the clusterExport call I get the error "Error in { : task 1 failed - "NULL value passed as symbol address" ".
Everything works fine when I switch %dopar% to %do%, but I'm hoping to be able to still parallelize.
I know that similar questions have been asked here, but I can't use a solution which calls sourceCpp on each worker (the c++ code in my actual R package is huge and this operation would defeat the purpose of parallelizing).
Any help would be greatly appreciated!!
(Continuing from the comments)
The key is that to execute 'local' code on a node, you cannot send a (compiled) function to the node. The node needs to have it, and the best way it to have the node(s) have access to the same package(s), load them and thus be ready to run code using them. I just glanced at some old slide decks from presentations I gave and I didn't find an perfect example -- but a pointer to a (thirteen-plus (!!) year old) directory of example scripts including this for running (cpu-wise expensive) DieHarder tests on nodes via Rmpi:
#!/usr/bin/env r
suppressMessages(library(Rmpi))
suppressMessages(library(snow))
cl <- NULL
mpirank <- mpi.comm.rank(0)
if (mpirank == 0) {
cl <- makeMPIcluster()
} else { # or are we a slave?
sink(file="/dev/null")
slaveLoop(makeMPImaster())
mpi.finalize()
q()
}
clusterEvalQ(cl, library(RDieHarder))
res <- parLapply(cl, c("mt19937","mt19937_1999",
"mt19937_1998", "R_mersenne_twister"),
function(x) {
dieharder(rng=x, test="operm5",
psamples=100, seed=12345)
})
stopCluster(cl)
print( do.call(rbind, lapply(res, function(x) { x[[1]] } )))
mpi.quit()
The key is in the middle: clusterEvalQ(cl, library(RDieHarder)) All worker nodes are asked to load the RDieHarder package. Conceptually, you want to do the same here, and the foreach family lets you do it too.

Adding additional documentation to a package in R

Aside from a vignette, I wish to add an additional document as PDF to my package. I can, of course, copy it to the inst/doc directory and it will then be included in the package documentation.
However, I would like to make it easy for the user to display this file. The authors of the edgeR package decided to do the following: the main users manual is distributed as PDF (and is not a regular vignette), and the authors include a function called edgeRUsersGuide() which shows the PDF by means of the following code:
edgeRUsersGuide <- function (view = TRUE) {
f <- system.file("doc", "edgeRUsersGuide.pdf", package = "edgeR")
if (view) {
if (.Platform$OS.type == "windows")
shell.exec(f)
else system(paste(Sys.getenv("R_PDFVIEWER"), f, "&"))
}
return(f)
}
It appears to work. Do you think it is a reasonable approach?
Or should one use something else? Potentially, the following code would also work and be more robust:
z <- list(PDF="edgeR.pdf", Dir=system.file(package="edgeR"))
class(z) <- "vignette"
return(z)
My solution was to ape the code in utils:::print.vignette():
function(docfile) {
## code inspired by tools:::print.vignette
pdfviewer <- getOption("pdfviewer")
f <- system.file("doc", docfile, package = "tmod")
if(identical(pdfviewer, "false"))
stop(sprintf("Cannot display the file %s", f))
if (.Platform$OS.type == "windows" &&
identical(pdfviewer, file.path(R.home("bin"), "open.exe"))) {
shell.exec(f)
} else {
system2(pdfviewer, shQuote(f), wait = FALSE)
}
return(invisible(f))
}

Access the code of the R_igraph_minimum_size_separators in R

I'm trying to access the code of the minimum.size.separators function from igraph package from R. I tried everything I could using what is suggested here, and only the following appears for me:
function (graph)
{
if (!is_igraph(graph)) {
stop("Not a graph object")
}
on.exit(.Call("R_igraph_finalizer", PACKAGE = "igraph"))
res <- .Call("R_igraph_minimum_size_separators", graph, PACKAGE = "igraph")
if (igraph_opt("return.vs.es")) {
for (i_ in seq_along(res)) {
res[[i_]] <- create_vs(graph, res[[i_]])
}
}
res
}
<environment: namespace:igraph>
In fact this is not the code that performs what the function does, but rather it is the code that calls R_igraph_minimum_size_separators, which I did not find its code. Does anyone know how to find the R_igraph_minimum_size_separators code?

Load package at start-up

I am trying to load a package at start-up if it's already installed. If it isn't then I want to first install it and then load it. So, I created the following function:
RLoadPackage <- function(packname)
{
if((packname %in% rownames(installed.packages()))==FALSE)
{
install.packages(packname,dependencies = TRUE)
}
library(packname,character.only = TRUE)
}
This works well once RStudio is opened, but it doesn't quite work at start-up. I added this function to my local .RProfile file as:
RLoadPackage("ggplot2")
RLoadPackage <- function(packname)
{
if((packname %in% rownames(installed.packages()))==FALSE)
{
install.packages(packname,dependencies = TRUE)
}
library(packname,character.only = TRUE)
}
However, I get the error message as:
Error: could not find function "RLoadPackage"
One option is to install packages manually and then add a bunch of library("xyz")
However, the above option is very clunky. So, I created a function.
I've 2 questions:
1) Can someone please help me with it?
2) Is there more efficient way of doing this?
My post is inspired from the following two links:
1) Check for installed packages before running install.packages()
2) http://www.statmethods.net/interface/customizing.html
I'd appreciate any help.
Thanks
Ok. This piece of code works:
library("utils")
RLoadPackage <- function(packname)
{
if((packname %in% rownames(installed.packages()))==FALSE)
{
install.packages(packname,dependencies = TRUE)
}
library(packname,character.only = TRUE)
}
RLoadPackage("ggplot2")
RLoadPackage("dplyr")
RLoadPackage("lubridate")
However, is there more efficient way of loading multiple packages--maybe a vectorized version of this? I am just curious.

Possible to decompile R bytecode?

Is it possible to go from compiled R code found in packages back to R source code? I would like to get the source code for various functions from packages installed from CRAN or other sources. I know I can download the full source via separate downloads.
You can extract the text of functions in a package using args() and body(). To list all the objects in a package you can use ls() and specify the package environment.
Caveat: The approach below will give you the source code, but not the NAMESPACE or DESCRIPTION.
For example, to print the source code of everything in ggplot2, try this:
library(ggplot2)
pkg <- as.environment("package:ggplot2")
allfuns <- ls(envir = pkg)
for(f in allfuns[1:2]){
args <- capture.output(print(args(f)))[1]
body <- paste(capture.output(print(body(f))), collapse = "\n")
cat(sprintf("%s <- %s\n%s\n\n", f, args, body))
}
This will give you:
%+% <- function (e1, e2)
{
e2name <- deparse(substitute(e2))
if (is.theme(e1))
add_theme(e1, e2, e2name)
else if (is.ggplot(e1))
add_ggplot(e1, e2, e2name)
}
%+replace% <- function (e1, e2)
{
if (!is.theme(e1) || !is.theme(e2)) {
stop("%+replace% requires two theme objects", call. = FALSE)
}
e1[names(e2)] <- e2
e1
}
Andrie's answer above has been hugely helpful for me. I had to use a package that is not on CRAN or git, and was only distributed as a compiled package built for R 3.0.1. Obviously when I tried to use it with R 4 it didn't work, and I didn't want to keep switching back and forth between R versions, so I had to decompile the package, rebuild the source, and reinstall.
However, Andrie's code example has a few shortcomings, most importantly that it only decompiles exported functions, not internal ones. Obviously this post is pretty old, but I'm posting my updates here in case it's helpful for anyone else trying to do the same thing.
packagename <- "ggplot2" #input package name here
pkg <- asNamespace(packagename) # importing as namespace rather than package accesses internals
allfuns <- ls(name = pkg)
for(f in allfuns){
# Andrie's [1] subset didn't work if the function arguments were more than one line long
args <- head(capture.output(print(args(getFromNamespace(f, packagename)))), -1)
body <- paste(capture.output(print(body(getFromNamespace(f, packagename)))),
collapse = "\n")
# This now writes directly to an R code file, rather than the console, to avoid copy/paste
# You could tweak this to create a separate file for each function, if desired.
cat(sprintf("%s <- %s\n%s\n\n", f, args, body),
file = paste(packagename, "functions.R"),
append = TRUE)
}

Resources