R packages with Fortran code

R is an open-source programming language primarily for statistics. There are about 18000 R packages, and 218 of them have some Fortran code, almost all of it FORTRAN 77 or earlier. There are 759 and 1000 packages using C and C++. R uses gfortran as its Fortran compiler. It is a high-level language in which “arrays know their own size”, so an R wrapper for a FORTRAN code is similar to what a modern Fortran wrapper would look like. One can look at R, Octave, and SciPy as places to “scavenge” well-tested, if often old-fashioned, Fortran code. One can search packages by both programming language and topic – there are for example 21 R packages with Fortran code for regression.

5 Likes

Wikipedia states R to be partially written in R, and other parts in C and Fortran. Recently, @KjellJorner initiated a discussion how to engage Fortran from Python with examples like f2py. Perhaps in contrast to you @Beliavsky, or others, I do not possess any working knowledge about R and still ask – out of curiosity*: is there a similar bridge, while working within R, to reach out for Fortran? For me, FortranCallsR found on the same index mentioned by you looks just the other way around …

*) In part equally a speculation: fortran-lang.org might benefit from a directory-like compilation in tune of «if you happen to work in language example, you may reach (back) to Fortran e.g., with module / library f2example with typical limitations of x and y». This guide need not to be exhaustive.

Yes, one way for R to call Fortran is to use the C interface of R. For example, on Windows for the Fortran code mands.f90

subroutine mands(n,x,dm,s)
implicit none
integer         , parameter   :: dp = kind(1.0d0)
integer         , intent(in)  :: n
real(kind=dp)   , intent(in)  :: x(n)
real(kind=dp)   , intent(out) :: dm,s ! mean and standard deviation
real(kind=dp)                 :: dmold,ds
integer                       :: i
write (*,"(a,i0,/)") "in mands, n = ",n
dm = x(1)
ds = 0.d0
do i=1,n
   dmold = dm
   dm    = dm + (x(i)-dm)/i
   s     = s  + (x(i)-dmold) * (x(i)-dm)
end do
s = sqrt(s/(n-1))
return
end subroutine mands

running the R code call_fortran.r

dyn.load("mands.dll")
n  = 5
x1 = rnorm(n)
mands = .C("mands_",as.integer(length(x1)),as.double(x1),as.double(0.0),as.double(0.0))
names(mands) = c("Sample Size","Sample","Mean","Standard Deviation")
print(mands)
cat("\nchecking in R: mean =",mean(x1),"sd =",sd(x1),"\n")

gives output such as

in mands, n = 5

$`Sample Size`
[1] 5

$Sample
[1]  1.2534455 -0.9944838  0.3846756 -1.0785162 -0.1023869

$Mean
[1] -0.1074532

$`Standard Deviation`
[1] 0.9777587


checking in R: mean = -0.1074532 sd = 0.9777587

The batch file is

setlocal
if exist mands.dll del mands.dll
gfortran -shared -fPIC -o mands.dll mands.f90
C:\programs\R\R-4.0.3\bin\x64\rterm.exe --vanilla --slave < call_fortran.r

The code is modified from here. There is a tutorial Calling Fortran subroutines from R showing how to do it on Linux.

In addition to R’s .C and .Fortran interfaces, there is a .Call interface that can be used for C, and you can use iso_C_binding to call Fortran subroutines directly from this. While it is a bit more complicated, in my experience using .Call interface it was easier to avoid making copies of the function arguments, which could otherwise slow some codes substantially. Although some documentation suggests this should not really be an issue, in my experience it did matter (around 3 or 4 years ago).

More recently there is a package dotcall64 that looks like it has solve this problem, with an easier interface (?) that supports C and Fortran.

See also some further relevant discussion on stackoverflow: performance - R: Advantages of using a Fortran subroutine with .Call and C/C++ wrapper instead of .Fortran? - Stack Overflow.

2 Likes

Have you used the dotCall64 package to import Fortran subroutines into R? I am currently exploring it.

Update: I have converted all my Fortran codes that interface R with the .Fortran function to using the R package dotCall64.

The package dotCall64 not only avoids copying large objects from R to Fortran but also allows for the use of long vectors (length longer than 2^31 - 1). I find it a great tool to interface R with Fortran.

Just like Fortran, the dotCall64 package is incredibly under-marketed.

1 Like