In R, we can call Fortran subroutines. For example, we have the following toy Fortran subroutine in the file test.f.
CCCCCCCCCCCCCCCCC C The subroutine is to calculate Hadama product of two matrices. C out[i][j]=x[i][j]*y[i][j]. C Both R and Fortran store matrix by column. CCCCCCCCCCCCCCCCC CCCCCCCCC Fortran program (f77) has to be between 7-th and 72-th column. CCCCCCCCC The 6-th column is for continuation marker. subroutine myHadamaProduct(x, y, nrow, ncol, mo) integer i, j, nrow, ncol CCCCCCC In Fortran, you don't need to specify the second dimension for matrix double precision x(nrow, *), y(nrow, *), mo(nrow, *) do i = 1, nrow do j = 1, ncol mo(i,j)=x(i,j)*y(i,j) enddo enddo return end
First, we need to compile the file test.f to create a shared library, test.so say, by using the GNU Fortran compiler:
g77 -fpic -shared -fno-gnu-linker -o test.so test.f
Next, we need to use the R function dyn.load to load the shared library test.so.
if(!is.loaded("myhadamaproduct")){ dyn.load("./test.so") }
The R function is.loaded is to check if the Fortran subroutine myHadamaProduct is already be loaded to R. If yes, then we do not need to loaded it again.
Next, we use the R function .Fortran to call the Fortran subroutine myHadamaProduct. For example,
x<-matrix(1:10,nrow=5, ncol=2) # get a 5x2 matrix y<-matrix(1:10,nrow=5, ncol=2) # get a 5x2 matrix out<-matrix(0, nrow=5, ncol=2) # initialize output matrix # to format matrix or array, use function storage.mode() storage.mode(x)<-"double" storage.mode(y)<-"double" storage.mode(out)<-"double" nr<-as.integer(nrow(x)) nc<-as.integer(ncol(x)) # Fortran is *NOT* case-sensitive. So it will change the all characters # to lower case. Thus, to use .Fortran call Fortran subroutines, you # have to type lower case. Otherwise, R will prompt error message. res<-.Fortran("myhadamaproduct", x, y, nr, nc, out=out) cat("Hadama product >>n") print(res$out)
If you do not need to use the shared library test.so any more, you can use the R function dyn.unload to unload it.
if(is.loaded("myhadamaproduct")){ dyn.unload("./test.so") }
Note:
The Fortran program called by R must be subroutines, not functions. For the example above, myHadamaProduct is defined as subroutine.
subroutine myHadamaProduct(x, y, nrow, ncol, mo)
The arguments in Fortran subroutines are passed by address instead of by values. And not like C language, there is no "pointer" concept in Fortran.
- When you use ".Fortran" to call Fortran subroutines, the name of the Fortran subroutines must be in lower case.
Any values returned by Fortran subroutines which are called in R must be initialized and must have the format:
# if the variable is defined as double in the Fortran subroutine variablename=as.double(initialized values) # inside .Fortran # if the variable is defined as integer in the Fortran subroutine variablename=as.integer(initialized values) # inside .Fortran # if the output is double precision matrix or array storage.mode(variablename)<-"double" # before .Fortran variablename=variablename # inside .Fortran
The input values must also be initialized and must have the above format. However, they can be formated before the ".Fortran" function.
- If the output is not written as variablename=variablename format (e.g. out=out in the above example), You still can get results. However, you have to use res[[5]] to refer out in the above example. In fact, the .Fortran function return a list containing all arguments of the Fortran subroutine myHadamaProduct. Since out is the 5-th argument, you can use res[[5]] to refer to the 5-th elements of the list.
- It is okay that the file test.f contains the main program.
Sometimes, the command "dyn.load("test.so")" gets error message. This is probably caused by the environment variable "$PATH" was not set correctly. You can either add the following line to the file ".bashrc" in your home directory:
export PATH=$PATH:.:
or use the command
dyn.load("./test.so")