UP | HOME

MR Fortran Finance Library (MRFFL)
Primary Documentation

Author: Mitch Richling
Updated: 2025-01-21 13:41:36
Generated: 2025-01-21 13:41:37

Copyright © 2025 Mitch Richling. All rights reserved.

Table of Contents

1. Introduciton

The functionality powering the programs published in the FortranFinance repository is contained in the MR Fortran Finance Library (MRFFL). MRFFL is a collection of Fortran modules that include advanced TVM solver computations, cashflow stream analysis, US tax calculations, and some monte carlo capabilities (US interest rates & US stock market returns).

API documentation may be found here: MR Fortran Finance Library (MRFFL) API Documentation

The TVM solvers differs from other TVM software I've used in that both annuities (level/geometric/arithmatic) and lump sums are generalized. Annuity payments can stop and start on arbitrary period boundaries within the term. Similarly, lump sums can occur at any payment boundary. This means the solvers can handle a variety of lump sum & annuity types (due, ordinary, delayed, early ending). Together this allows one to solve some difficult, non-standard TVM problems.

The cashflow stream module uses a similar generalization in that cashflows can be placed at any period boundary. This eliminates the need to treat the cashflow at time zero as special. It also eliminates the need to bother with that BEGIN or END mode nonsense. Without these complications we can group cashflow sequences together without worry about the mode of each or period alignment issues that plague some other cashflow software. The module includes cashflow series builders using the same notation and variables as the TVM solvers allowing one to use the TVM solvers to find necessary values, and then use the same variables to populate a cashflow that can be further analyzed or printed.

2. MRFFL (MR Fortran Finance Library) Modules

Financial applications
mrffl_config
Contains parameters used to configure the rest of the modules.
mrffl_cashflows
TVM problems involving cash flows.
mrffl_life_table
Life table computations and some US life table data.
mrffl_percentages
Working with percentages
mrffl_tvm12
Classic financial calculator style TVM solver and amortization.
mrffl_tvm
TVM solvers for: deferred lump sums and generalized level/geometric/arithmatic annuities.
mrffl_us_inflation
Historical US inflation data. Adjust values across years. Random inflation generation via resampling.
mrffl_us_markets
Historical stock market annual return data. Includes random return generation via resampling.
mrffl_us_taxes
Basic US tax information and computation for filing joint or single.
mrffl_prt_sets
Constants to specify things to print (used by *_print routines)
mrffl_var_sets
Constants to specify variables (used by TVM solvers to specify unknown variables)
Support Modules
mrffl_solver
Solves equations using bisection – used by the TVM solvers in the tvm & tvm12 modules.
mrffl_stats
Statistics stuff – resamplers, random variables (gamma & log-gamma), etc…
mrffl_bitset
Bitsets used by TVM solvers for unknown variables.

3. Example Programs

You will find several programs, most of which use MRFFL, in various directories at the base of the FortranFinance repository:

cashflows
Some simple MRFFL cashflow examples.
loans
Illustrates how to use MRFFL TVM solvers in combination with cashflow series.
monte_carlo
Illustrates basic resampling monte carlo for inflation and stock market returns.
retirement
Some TVM based retirement computations.
retirement_simulation
A comprehensive simulator for a married couple's retirement (not much MRFFL used here)

In addiont, the unit & functional tests in the MRFFL directory can provide some insight into the useage ofMRFFL:

MRFFL/functional_tests
Functional tests for MRFFL. While these are basic MRFFL tests, they also demonstrate the API.
MRFFL/unit_tests
Unit (well unit-like) tests for MRFFL. These also demonstrate the API; however, they can be a bit complex.

3.1. Building Example Programs With GNU Make

This section describes how to build using GNU Make. A later section describes how to build with CMake.

The GNU Make based build is the one I use day to day, and thus gets more testing and is more complete. In order to compile on your platform you may need to modify the makefile in each directory to use your favorite Fortran compiler. At the top of each makefile you will find something like this:

################################################

MRFFL_PATH = ../MRFFL

include $(MRFFL_PATH)/tools_gfortran.mk
# include $(MRFFL_PATH)/tools_flang.mk
# include $(MRFFL_PATH)/tools_ifx.mk
# include $(MRFFL_PATH)/tools_lfortran.mk
# include $(MRFFL_PATH)/tools_nvfortran.mk

include $(MRFFL_PATH)/include.mk

################################################

If you are using gfortran on a UNIX'ish system, then you can probably just leave it as is. If you want to use a different compiler, then you may be able to simply uncomment the appropriate line if your system is similarly configured to mine. If you are unlucky, then you may need to set some variables. In particular, you might need to comment out the gfortran include and add something like this:

AR := ar
FC := nvfortran
FFLAGS := -O3 -Wall  -W -Xlinker -z -Xlinker execstack
FSHFLG = -o $(MRFFL_SHARED_LIB_FILE) -shared $(MRFFL_OBJ_FILES)

The only tricky one is the FSHFLG variable. Luckily you only need the FSHFLG variable if you plan on building a shared library. The shared library is completely unnecessary for making full use of the modules, so you you can safely ignore that one unless you really, really want to use a shared library. ;)

3.2. Building Example Programs With CMake

This section describes how to build using CMake. A previous section describes how to build with GNU Make.

Most of the programs in FortranFinance make use of MRFFL. When using a CMake based workflow, MRFFL is accessed via a central include directory of compiled module files and a static library. Before we can compile any examples, we must create these module files and library.

cd MRFFL/build
rm -rf *
cmake .. -DCMAKE_Fortran_COMPILER=gfortran
cmake --build .

Now that MRFFL is compiled, we can make use of it. As an example, we can build the irr executable in the cashflows directory like so:

cd cashflows/build
rm -rf *
cmake .. -DCMAKE_Fortran_COMPILER=gfortran
cmake --build .

4. Using MRFFL (MR Fortran Finance Library) Modules

4.1. Using CMake

In the section on building examples we build the MRFFL library using CMake. This process will result in several new files and directories:

  • MRFFL/build/lib/ will contain the compiled MRFFL library.
  • MRFFL/build/modules/ will contain the generated module files.
  • MRFFL/build/MRFFL.cmake/ a CMake include file that can be used to compile things with the MRFFL library.

For the most part, the following compilers are well supported:

  • GNU Fortran
  • Intel ifx
  • NVIDIA HPC Fortran
  • Flang

If you are using a compiler not on this list, then more configuration may be required (-DCMAKE_Fortran_FLAGS for example).

With MRFFL compiled using CMake, we can use it from another project. The cashflows directory contains an example CMakeLists.txt for the irr executable:

cmake_minimum_required(VERSION 3.30)

project(MRFFL_cashflow_examples VERSION 0.1
        DESCRIPTION "Examples for MRFFL_cashflows module"
        LANGUAGES Fortran)

set(CMAKE_Fortran_PREPROCESS NO)

# Find and include the MRFFL.cmake file.  This will setup the MRFFL library -- it's include dirs and link dir.
if(EXISTS "../../MRFFL/build/MRFFL.cmake")
  message(STATUS " MRFFL Search: Found: Exported")
  include("../MRFFL/build/MRFFL.cmake")
  if(NOT (EXISTS "../../MRFFL/build/modules/mrffl_config.mod") )
    message(ERROR " MRFFL Search: Found exported cmake file, but MRFFL library has not been built!!!")
  endif()
else()
  message(ERROR " MRFFL Search: Failed!!!")
endif()

add_executable(irr irr.f90)
target_link_libraries(irr PRIVATE MRFFL)

That's really all we need to ake use of MRFFL. Note this CMakeLists.txt uses MRFFL.cmake, but this is not strictly required. The paths can be set by hand, and the following would work instead:

cmake_minimum_required(VERSION 3.30)

project(MRFFL_cashflow_examples VERSION 0.1
        DESCRIPTION "Examples for MRFFL_cashflows module"
        LANGUAGES Fortran)

set(CMAKE_Fortran_PREPROCESS NO)

add_executable(irr irr.f90)
target_link_libraries(irr PRIVATE MRFFL)
target_include_directories(irr AFTER PRIVATE ../MRFFL/build/modules)
target_link_directories(irr BEFORE PRIVATE ../MRFFL/build/lib)

4.2. Using GNU Make

All of the code is in the module source files with no external dependencies at all. So you just need to call the modules from your code, and then compile/link everything together.

To help with that compile/link part, a makefile fragment has been provided (include.mk). Note it works with GNU make and is designed for UNIX-like environments (Mac OS X, Linux, MSYS2 on Windows 11, WSL on Windows 11). I mostly use MSYS2 on Windows 11 so that is where it gets the most testing. The makefile in the functional tests directory is a good guide on how to use include.mk. In essence you do the following in your makefile:

  1. Set MRFFL_PATH in your makefile to the path of the MRFFL source directory – that's the one with the include.mk file.
  2. Set FC, FFLAGS, & AR if necessary – most of the time you can use the defaults.
  3. Include the "include.mk" file in the MRFFL source directory.
  4. Add a build rule for your program.

Your makefile will look something like this:

MRFFL_PATH = ../MRFFL

# Set FC, FFLAGS, & AR here.  The include below has the settings I use on my system.
include $(MRFFL_PATH)/tools_gfortran.mk

include $(MRFFL_PATH)/include.mk

your_program : your_program.f90 $(MRFFL_OBJ_FILES)
    $(FC) $(FFLAGS) $^ -o $@

Note the rule in the makefile above takes the lazy approach of adding every MRFFL module as a dependency regardless of if your program actually needs them all. This is how most people use the modules because it's simple. The cost might be a couple seconds of extra compile time. You can explicitly list out the modules in the makefile if you wish. Such a rule might look like the following:

your_program : your_program.f90 mrffl_config$(OBJ_SUFFIX) mrffl_tvm$(OBJ_SUFFIX) mrffl_solver$(OBJ_SUFFIX)
    $(FC) $(FFLAGS) $^ -o $@

4.2.1. Notes about include.mk

4.2.1.1. Names of files
File extensions on Windows (outside of WSL)
  • Executable files use .exe
  • Shared libraries use .dll
  • Object files will .obj
On UNIX systems (not including MSYS2)
  • Executable files have no extension
  • Shared libraries use .so
  • Object files will use .o
4.2.1.2. Useful Variables
MRFFL_MOD_FILES
All the module (.mod) files. These will appear in your build directory.
MRFFL_OBJ_FILES
All the object (.obj or .o) files. These will appear in your build directory.
MRFFL_STATIC_LIB_FILE
The name of the static library file. It's not created by default. It will appear in your build directory if it is listed as a dependency on one of your targets.
MRFFL_SHARED_LIB_FILE
The name of the shared library file. It's not created by default. It will appear in your build directory if it is listed as a dependency on one of your targets.
4.2.1.3. Useful Targets
all_mrffl_lib
Builds the library files.
all_mrffl_mod
Builds the module (.mod) files
all_mrffl_obj
Builds the object (.obj or .o) files
clean_mrffl_mod
Deletes all the MRFFL module (.mod) files in the build directory.
clean_mrffl_obj
Deletes all the MRFFL object (.obj or .o) files in the build directory.
clean_mrffl_lib
Deletes all the library files in the build directory.
clean_mrffl
Simply calls the following targets: clean_mrffl_mod, clean_mrffl_obj, & clean_mrffl_lib
clean_multi_mrffl
The previous clean targets will only remove products from the current platform. For example, the clean_mrffl_obj target will delete object files with an extension of .obj on windows and an extension of .o on UNIX'ish platforms. I use the same directories to build for all platforms, so I sometimes want to clean up the build products from all platforms at once. That's what this target will do.
4.2.1.4. Static Library

A rule to make a static library is included in include.mk. A build rule like the following should build that library and link it to your executable. Note I'm just including the library file on the command line instead of linker like options (i.e. -L and -l for GNU compilers). That's because simply including the library on the command line is broadly supported across more compilers – this way I don't have to document how to do the same thing for each one. ;)

your_program : your_program.f90 $(MRFFL_STATIC_LIB_FILE)
    $(FC) $(FFLAGS) $^ $(MRFFL_STATIC_LIB_FILE) -o $@
4.2.1.5. Dynamic Library (.so and .dll files)

A rule to make a static library is included in include.mk. You can build it with the target clean_mrffl_lib, or by using $(MRFFL_SHARED_LIB_FILE) as a dependency in your build rule. As the options to link to a shared library differ wildly across platforms and compilers/linkers, I don't provide an example of how to do that.

5. Tested Environments

MSYS2 running on Windows 11
  • GNU Fortran (Rev2, Built by MSYS2 project) 14.2.0 : Everything works
  • LFortran 0.42.0 LLVM 19.1.3 : Nothing works. Compiler crashes during compile.
  • Intel ifx 2024.1.0 Build 20240308 : Everything works
  • flang 19.1.6 inside clang: Nested functions cause a seg fault, and I don't know how to get the linker to do the right thing.
Debian 12.8 running in WSL on Windows 11
  • GNU Fortran (Debian 14.2.0-8) 14.2.0 from debian-testing: Everything works
  • LFortran 0.42.0 LLVM 19.1.3 : Nothing works. Compiler crashes during compile.
  • Intel ifx 2025.0.4 20241205 : Everything works
  • nvfortran 24.11-0 64-bit target on x86-64 Linux : Everything works.
  • flang-new version 19.1.6 : Everything works.