Introduction

There are many important R packages by Stanford authors using Fortran for speed and efficiency. For example, Jerome Friedman, Trevor Hastie and Robert Tibshirani have several packages, glmnet, glasso, gam to name a few, that make use of Fortran. The Fortran in many cases is generated using a preprocessor called Mortran (m77). It is a bit of a chore to ensure that the generated Fortran code generates no warnings and registers the native routines as required by CRAN. This package is an attempt o make it almost automatic.

I'd put together code for this several times over the years but never quite organized it in one place.

A related package ftest provides a complete example of calling back a user-defined R function from Fortran.

Useful functions for general use

While this package is directed specifically towards Mortran, there are several functions that many may find useful.

Example

We will use an example package pcLasso which has a Mortran file (included in this package) that is used for the actual computations along a path of values for $\lambda$.

If all goes well, only one real function call is needed to generate both the Fortran and registration code.

library(SUtools)
mortran_file <- system.file("misc", "pcLasso.m", package = "SUtools")
result  <- process_mortran(input_mortran_file = mortran_file,
                           pkg_name = "pcLasso",
                           control = sutools_control(fix_allocate = TRUE))

This will return a list of three items: a cleaned-up version of the mortran named mortran, the corresponding cleaned and processed fortran named fortran, and registration C code named pcLasso_init.c where the name is constructed from the package name provided. The fortran and the registration code can be saved in appropriate files in pcLasso/src simply by using base::writeLines.

writeLines(result$fortran, "pcLasso/src/pcLasso.f")
writeLines(result[[3]], paste0("pcLasso/src/", names(result)[[3]]))

Details

The process_mortran function goes through several steps.

  1. First, it fixes the allocate statements in the Mortran file. (This step is skipped if the option fix_allocate is FALSE, the default!) Lines of the type:
allocate(a(1:ni),stat=ierr);

are replaced with

allocate(a(1:ni),stat=jerr); if(jerr.ne.0) return;

ensuring that warnings for the variable jerr being ignored go away

  1. All subroutines and functions in Mortran and Fortran subroutines and functions are modified to include a
      implicit double precision(a-h,o-z)

statement to ensure double precision calculations.

  1. All real variables are replaced with double precision variables.

  2. Constants such as [eE][+-]?[0-9]+. are replaced by double precision equivalents.

  3. As a result of replacing real with double precision, there is a possibility for some lines to go over the 72 character limit, in the Fortran sections. For Mortran, this limit is 80 characters and that is also checked.

If this check fails, the function exits with a detailed list of things and approximate line numbers for the user to address.

  1. The Mortran executable is run on the Mortran file to produce the Fortran file with extension .for.

  2. There is extraneous stuff that Mortran adds which can again trigger gfortran warnings. So this step chops off things beyond 72 columns to yield a .f file.

  3. Next gfortran is run on the code in the .f file with flags -Wunusued to detect unused labels. The output is then scanned for the warning messages.

  4. If the warning messages pertain only to unusued labels, an automatic fix is made on the generated Fortran file. Otherwise, an informative message is printed with hints on how to fix the source.

  5. If registration is asked for and a package name is provided, the registration is code is generated in a file typically named based on the package, pcLasso_init.c in our example. This is done by scanning the Mortran file for subroutine declarations (even if they span several lines) and using implicit Fortran conventions to generate C registration code.

Notes



bnaras/SUtools documentation built on Nov. 26, 2022, 6:07 p.m.