README.md

January 25, 2025 ยท View on GitHub

roots-fortran: root solvers for modern Fortran

Language GitHub release CI Status codecov last-commit

Description

A modern Fortran library for finding the roots of continuous scalar functions of a single real variable.

Compiling

A fpm.toml file is provided for compiling roots-fortran with the Fortran Package Manager. For example, to build:

fpm build --profile release

By default, the library is built with double precision (real64) real values. Explicitly specifying the real kind can be done using the following processor flags:

Preprocessor flagKindNumber of bytes
REAL32real(kind=real32)4
REAL64real(kind=real64)8
REAL128real(kind=real128)16

For example, to build a single precision version of the library, use:

fpm build --profile release --flag "-DREAL32"

To run the unit tests:

fpm test

To use roots-fortran within your fpm project, add the following to your fpm.toml file:

[dependencies]
roots-fortran = { git="https://github.com/jacobwilliams/roots-fortran.git" }

or, to use a specific version:

[dependencies]
roots-fortran = { git="https://github.com/jacobwilliams/roots-fortran.git", tag = "1.0.0"  }

To generate the documentation using ford, run: ford roots-fortran.md

Usage

Methods

The module contains the following methods:

ProcedureDescriptionReference
bisectionClassic bisection methodBolzano (1817)
regula_falsiClassic regula falsi method?
mullerImproved Muller method (for real roots only)Muller (1956)
brentClassic Brent's method (a.k.a. Zeroin)Brent (1971)
brenthSciPy variant of brentBrent (1971)
brentqSciPy variant of brentBrent (1971)
illinoisIllinois methodDowell & Jarratt (1971)
pegasusPegasus methodDowell & Jarratt (1972)
anderson_bjorckAnderson-Bjorck methodKing (1973)
abkkA variant of anderson_bjorckKing (1973)
riddersClassic Ridders methodRidders (1979)
toms748Algorithm 748Alefeld, Potra, Shi (1995)
chandrupatlaHybrid quadratic/bisection algorithmChandrupatla (1997)
bdqrfBisected Direct Quadratic Regula FalsiGottlieb & Thompson (2010)
zhangZhang's method (with corrections from Stage)Zhang (2011)
rbpRegula Falsi-Bisection-Parabolic methodSuhadolnik (2012)
itpInterpolate Truncate and Project methodOliveira & Takahashi (2020)
barycentricBarycentric interpolation methodMendez & Castillo (2021)
blendtfBlended method of trisection and false positionBadr, Almotairi, Ghamry (2021)
modabModified Anderson-BjorkGanchovski & Traykov (2023)

In general, all the methods are guaranteed to converge. Some will be more efficient (in terms of number of function evaluations) than others for various problems. The methods can be broadly classified into three groups:

  • Simple classical methods (bisection, regula_falsi, illinois, ridders).
  • Newfangled methods (zhang, barycentric, blendtf, bdqrf, abkk, rbp). These rarely or ever seem to be better than the best methods.
  • Best methods (anderson_bjorck, muller, pegasus, toms748, brent, brentq, brenth, chandrupatla, itp). Generally, one of these will be the most efficient method.

Note that some of the implementations in this library contain additional checks for robustness, and so may behave better than naive implementations of the same algorithms. In addition, all methods have an option to fall back to bisection if the method fails to converge.

Functional Interface Example

program main

  use root_module, wp => root_module_rk

  implicit none

  real(wp) :: x, f
  integer :: iflag

  call root_scalar('bisection',func,-9.0_wp,31.0_wp,x,f,iflag)

  write(*,*) 'f(',x,') = ', f
  write(*,*) 'iflag    = ', iflag

contains

  function func(x) result(f)

  implicit none

  real(wp),intent(in) :: x
  real(wp) :: f

  f = -200.0_wp * x * exp(-3.0_wp*x)

  end function func

end program main

Object Oriented Interface Example

program main

  use root_module, wp => root_module_rk

  implicit none

  type,extends(bisection_solver) :: my_solver
  end type my_solver

  real(wp) :: x, f
  integer :: iflag
  type(my_solver) :: solver

  call solver%initialize(func)
  call solver%solve(-9.0_wp,31.0_wp,x,f,iflag)

  write(*,*) 'f(',x,') = ', f
  write(*,*) 'iflag    = ', iflag

contains

  function func(me,x)

    class(root_solver),intent(inout) :: me
    real(wp),intent(in) :: x
    real(wp) :: f

    f = -200.0_wp * x * exp(-3.0_wp*x)

  end function func

end program main

Result

 f( -2.273736754432321E-013 ) =   4.547473508867743E-011
 iflag    =            0

Notes

Documentation

The latest API documentation for the master branch can be found here. This was generated from the source code using FORD.

License

The roots-fortran source code and related files and documentation are distributed under a permissive free software license (BSD-style).

  • polyroots-fortran -- For finding all the roots of polynomials with real or complex coefficients.

Similar libraries in other programming languages

LanguageLibrary
CGSL
C++Boost Math Toolkit
JuliaRoots.jl
Runiroot
Rustroots
MATLABfzero
Pythonscipy.optimize.root_scalar

References

See also