freckletonj / haskell-fortran

A demonstration connecting Fortran (and C) code to Haskell, and to HMatrix.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Haskell-Fortran

Fortran ("Formula Translator") is a great imperative language intended to let mathematicians/scientists write performant code. In most industries, it's use is waning, but in many scientific industries, it's actually a critical component. For example, Python, and it' s library numpy are a workhorses in scientific communities and underneath it all are the Fortran libraries BLAS and LAPACK. Haskell's HMatrix library follows the same tact and links to those same battle-hardened libraries.

There are other FOSS Fortran libraries you might want to bring into the Haskell fold, or you might want an imperative, lightning fast language for some of your low-level work, while retaining Haskell's abstraction abilities, and type-safety.

This repository is a good place to start.

TL;DR

You can accomplish:

C -> Haskell
C -> HMatrix
Fortran -> Haskell
Fortran -> HMatrix

Description

To get connect the 2 languages, we must go through C, which isn't that bad.

Fortran  --FFI-->  C  --FFI-->  Haskell

This project builds up an example, step by step, for how to use Haskell's FFI, and C's Fortran FFI, to connect ultimately Fortran code to Haskell, and to Haskell's HMatrix library.

The Demos

The best place to start is in src/Main.hs. In it you'll find:

  1. An demo for getting the exp function out of C's stdio.

  2. A hello world function, reaching all the way from Fortran to C, to Haskell.

  3. A demo for passing values to Fortran. Fortran expects data passed by reference, so there are actually 2 examples. 1 passes references directly. The other utilizes a C wrapper function to help.

  4. Connecting C arrays to HMatrix Matrixs.

  5. And finally, doing array math in Fortran, and using it with HMatrix.

Usage

  1. An infelicity: Cabal won't resolve relative paths in extra-lib-dirs, so you must edit it to an absolute path into this repo. Look for these lines:
extra-lib-dirs:
  - EDIT_ME_TO_ABSOLUTE_PATH/haskell-fortran/c/1_hello
  - EDIT_ME_TO_ABSOLUTE_PATH/haskell-fortran/c/2_fpow
  - EDIT_ME_TO_ABSOLUTE_PATH/haskell-fortran/c/4_scalarmul
  1. And we're off!
make run

Notes

  • GHC can link to static libraries (*.a) and dynamic libraries (*.so). We use dynamic libraries here because GHCi (the repl) only allows dynamic libraries.

  • See the Makefile and package.yaml for how linking is done. Here's the gist:

    • First we compile C and Fortran code into objects that are not linked together yet:
    # C code. Notice it links in `gfortran`, needed by C's FFI.
    gcc -g -lgfortran -c -o OUTPUT_NAME.o C_CODE.c
    
    # Fortran code
    gfortran -c -o OUTPUT_NAME.o FORTRAN_CODE.f95
    • Then, link both those objects into a dynamic library
    gcc -shared -o OUTPUT_NAME.so OBJECT1.o OBJECT2.o ...
    • In package.yaml, you can include raw C files (without Fortran dependencies) without compiling them yourself via:
    include-dirs: SOME/DIR/
    c-sources: SOME/DIR/file.c
    
    • In package.yaml, you can link to the libraries you compiled via:
    extra-lib-dirs:
      - SOME/DIR
    
    extra-libraries
      - THELIBRARY
    
    • There is a naming convention you must follow. Libraries named supercool must be compiled to libsupercool.so, and in package.yaml, included as just supercool.
  • HMatrix's Matrix type looks like this with extra params for the sliced width and height (irows and icols). It's important when writing algorithms to remember that the dimensions of the array in memory may differ from the slice under consideration, so, your algorithm can be dramatically off if you're not careful. The library has poor documentation for this type, so perhaps the subMatrix algorithm is the best explication of what's going on with the extra params in a Matrix.

  • HMatrix has some weird TransArray stuff. To get your head around it, consider an example they wrote: .hs, .c.

My Questions

  • Could I get a code review around some of the C, Makefile, and Fortran? I'm a total noob to all 3.

  • If I have Fortran code mutate the underlying array, how can I do that safely in Haskell? This line seems a little sketchy to me. The other approach is to allocate an output array, and pass that to Fortran to mutate. But what if you want in-place mutation?

  • Any opinions on generating C interfaces to Fortran code, and avoid C boilerplate? I found f2c that seems interesting.

About

A demonstration connecting Fortran (and C) code to Haskell, and to HMatrix.

License:BSD 2-Clause "Simplified" License


Languages

Language:Haskell 57.6%Language:C 21.1%Language:Makefile 16.9%Language:Fortran 4.4%