Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R: Advantages of using a Fortran subroutine with .Call and C/C++ wrapper instead of .Fortran?

I have an R package which uses lots of Fortran subroutines for nested loops of recursive linear algebra computations (depending heavily on BLAS and LAPACK routines). As an interface to Fortran, I use .Fortran function. I just read Jonathan Callahan's blog post about using .Call instead of .C in case of subroutines written in C/C++, and it got me thinking that would it be better to use .Call interface also when using Fortran subroutines, by writing a simple wrapper in C which then calls the Fortran subroutines?

As said, my Fortran codes are quite simple in a sense that I just play with multidimensional arrays of type double or integer. But I have learned that I must write quite a lot of checks in R side to ensure that everything doesn't crash because of I accidentally forgot to change the storage mode of some matrix to integer or the dimensions of some matrix were changed etc.

Subroutines are written as F90/95.

like image 922
Jouni Helske Avatar asked Mar 01 '13 19:03

Jouni Helske


2 Answers

There might be an advantage if you are working with a large dataset. .Call can be much faster because you are not copying the data each time you call the function. For the case described in this question, there will be no such advantage, because the R 2.15.1 release notes state

.C() and .Fortran() do less copying: arguments which are raw, logical, integer, real or complex vectors and are unnamed are not copied before the call, and (named or not) are not copied after the call. Lists are no longer copied (they are supposed to be used read-only in the C code).

Switching to .Call means you give up the convenience of the .Fortran interface. You'd pass SEXPs into the C code, do any checks/manipulation of the data using the (scary and not well-documented) R API, and then call a Fortran function from C. Anyone else working with your code will have to understand the R API and C/Fortran interop.

like image 61
user2225804 Avatar answered Nov 14 '22 02:11

user2225804


The R package dotCall64 could be an interesting alternative. It provides .C64() which is an enhanced version of the Foreign Function Interface, i.e., .C() and .Fortran().

The interface .C64() can be used to interface both Fortran and C/C++ code. It

  • has a similar usage as .C() and .Fortran()
  • provides a mechanism to avoid unnecessary copies of read-only and write-only arguments
  • supports long vectors (vectors with more then 2^31-1 elements)
  • supports 64-bit integer type arguments

Hence, one can avoid unnecessary copies of read-only arguments while avoiding the .Call() interface in combination with a C wrapper function.

Some links:

  • The R package dotCall64: https://CRAN.R-project.org/package=dotCall64
  • Description of dotCall64 with examples: https://doi.org/10.1016/j.softx.2018.06.002
  • An illustration where dotCall64 is used to make the sparse matrix algebra R package spam compatible with huge sparse matrices (more than 2^31-1 non-zero elements): https://doi.org/10.1016/j.cageo.2016.11.015

I am one of the authors of dotCall64 and spam.

like image 44
Nairolf Avatar answered Nov 14 '22 01:11

Nairolf