An extension to MINPACK-1 library.
Platform | Build Status | Code Coverage |
---|---|---|
Ubuntu 22.04 | ||
Windows 11 |
This software is an extension to the popular double-precision version of MINPACK-1 library [1] - or simply minpack, which provides routines to solve a system of nonlinear equations and nonlinear least squares problems. Without any modification to the source code of minpack, employing the powerful CMake [2] build system to handle platform and compiler intricacies on different operating systems, the goal of minpackex
is to extend the original minpack function signatures to an easier-to-use API to the programmer, allowing user data to be shared across function calls.
Tip
minpackex
has a hard dependency on the minpack library and cannot function without it. In the documentation, we describe in details how to build both libraries on different combinations of platform / compiler toolchains.
The original minpack [1] is a battle-tested minimization package written in Fortran 77 for solving a system of nonlinear equations and nonlinear least squares problems, discussed in details at [3]. Throughout the years, popular scientific libraries like SciPy [4] and Eigen [5] have been using minpack to perform nonlinear optimization.
Important
Do not confuse the original minpack [1] written in Fortran 77 with Modernized Minpack [6]. The modern minpack [6] version ported the initial code to newer Fortran standards. Here, we extend the original minpack library, not the modernized version.
-
In the first place, the most important decision to use this library is the safety to employ the original implementation of minimization code, written in Fortran 77, provided by minpack authors [1], not the code ported to other programming languages by third parties;
-
Second, once you compile the original minpack code to a binary, the usual API (which on Linux resembles minpack.h [7]) does not allow user data to be shared by optimization routines in a straight forward manner. To address this limitation, we apply a trick in the passage of parameters in order to allow user data to be forwarded to such functions. To further explain this point, see how the parameter
void *userdata
works in the basic usage below to perform a function fit on a pair of points$(1, -1)$ and$(4, 5)$ for a model in the form$f(x) = a \cdot x + b$ .
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <minpackex.h>
typedef double (* model)(double x, const double *params);
typedef struct fit_data fit_data;
struct fit_data
{
double *x;
double *y;
model f;
};
static void lmdif1_callback(
void *userdata,
int m,
int n,
const double *x,
double *fvec,
int *info)
{
fit_data *data = (fit_data *)userdata;
model f = data->f;
double *px = data->x;
double *py = data->y;
for (int i = 0; i < m; i++)
{
fvec[i] = f(px[i], x) - py[i];
}
}
static double linear_model(double x, const double *params)
{
double a = params[0];
double b = params[1];
return a * x + b;
}
// void minpackex_lmdif1(
// void *userdata,
// minpackex_lmdif1_callback callback,
// int m, int n, double *x, double *fvec, double tol,
// int *info, int *iwa, double *wa, int lwa);
int main(void)
{
double x[2] = { 1, 4 };
double y[2] = { -1, 5 };
fit_data data;
data.x = x;
data.y = y;
data.f = linear_model;
double guess[2] = { 1, 1 };
/* size of x and y arrays (m = 2) */
int m = sizeof(x) / sizeof(double);
/*
** size of guess (n = 2),
** which is also the number of unknown parameters
** on the model -> linear_model (a and b)
*/
int n = sizeof(guess) / sizeof(double);
double tol = sqrt(minpackex_dpmpar(1));
int info;
int lwa = m * n + 5 * n + m;
double *wa = (double *)malloc(lwa * sizeof(double));
double *fvec = (double *)malloc(m * sizeof(double));
int *iwa = (int *)malloc(n * sizeof(int));
minpackex_lmdif1(
(void *)&data,
(minpackex_lmdif1_callback)&lmdif1_callback,
m,
n,
guess,
fvec,
tol,
&info,
iwa,
wa,
lwa);
printf("\n\n// input:\n\n");
printf("// \t (x, y):\n");
for (int i = 0; i < m; i++)
{
printf("// \t\t (%g, %g)\n", x[i], y[i]);
}
printf("\n// \t model:\n");
printf("// \t\t y = a * x + b\n\n");
if (1 <= info && info <= 4)
{
printf("\n// nice fit\n\n");
printf("// found parameters:\n");
printf("// \t a = %g\n", guess[0]);
printf("// \t b = %g\n\n", guess[1]);
}
else
{
printf("\n// bad fit\n\n");
}
free((void *)iwa);
free((void *)fvec);
free((void *)wa);
return 0;
}
Running the sample above produces the following output:
// input:
// (x, y):
// (1, -1)
// (4, 5)
// model:
// y = a * x + b
// nice fit
// found parameters:
// a = 2
// b = -3
Browse the documentation.
At the moment, running a total of 299 different tests on multiple settings, the continuous integration on github is able to build and install minpackex
in the following combination of platform / compiler toolchain, asserting that exactly the same output is obtained using either minpackex or minpack.
Note
In the tables below, MSVC-like means the underline linker is MSVC-compatible. Therefore, GCC-like means the underline linker is GCC-compatible.
Fortran Compiler | Fortran Compiler Version | C Compiler | C Compiler Version |
---|---|---|---|
GFortran | 14.1.0 | GCC | 14.1.0 |
LLVM flang-new (GCC-like) | 18.1.6 | Clang | 18.1.6 |
Intel LLVM ifx (MSVC-like) | 2024.1.0 | MSVC | 19.39.33523.0 |
Intel LLVM ifx (MSVC-like) | 2024.1.0 | Clang-cl | 16.0.6 |
Intel LLVM ifx (MSVC-like) | 2024.1.0 | Intel LLVM icx (MSVC-like) | 2024.1.0 |
LLVM flang-new (MSVC-like) | 18.1.7 | MSVC | 19.39.33523.0 |
LLVM flang-new (MSVC-like) | 18.1.7 | Clang-cl | 18.1.7 |
Intel ifort (MSVC-like) | 2021.10.0 | MSVC | 19.39.33523.0 |
Intel ifort (MSVC-like) | 2021.10.0 | Clang-cl | 16.0.6 |
Intel ifort (MSVC-like) | 2021.10.0 | Intel icl (MSVC-like) | 2021.10.0 |
Fortran Compiler | Fortran Compiler Version | C Compiler | C Compiler Version |
---|---|---|---|
GFortran | 11.4.0 | GCC | 11.4.0 |
LLVM flang-new (GCC-like) | 18.1.6 | Clang | 18.1.6 |
Intel LLVM ifx (GCC-like) | 2024.1.2 | Intel LLVM icx (GCC-like) | 2024.1.2 |
Intel ifort (GCC-like) | 2021.10.0 | Intel icl (GCC-like) | 2021.10.0 |
Nvidia nvfortran | 2023.11 | Nvidia nvc | 2023.11 |
Up to date, on different levels of activity, there are many alternatives in a wide number of programming languages:
- Python: SciPy [4] is probably the most famous and used out there;
- C++: Eigen [5], based on cminpack below;
- Fortran: Modernized Minpack [6], which seems to allow parallel execution of the algorithms;
- C/C++: cminpack [8] by Frédéric Devernay is a mature code base which I contributed a few times and has been around for almost 20 years (it is also available on Debian / Fedora repositories);
- C++: QuantLib [9] math optimization;
- C/C++/Fortran 90: [10] by Burkardt;
- Java: apache [11];
- R: minpack.lm [12];
- Julia: MINPACK.jl [13].
- minpack. Accessed May 2, 2024. https://www.netlib.org/minpack;
- CMake. Accessed May 2, 2024. https://cmake.org/;
- Moré, Jorge J., Burton S. Garbow, and Kenneth E. Hillstrom. User guide for MINPACK-1.[In FORTRAN]. No. ANL-80-74. Argonne National Lab.(ANL), Argonne, IL (United States), 1980. DOI: 10.2172/6997568;
- SciPy. Accessed May 2, 2024. https://github.com/scipy/scipy/tree/main/scipy/optimize/minpack;
- Eigen. Accessed May 2, 2024. https://eigen.tuxfamily.org/dox/unsupported/index.html;
- Modernized Minpack. Accessed May 3, 2024. https://github.com/fortran-lang/minpack;
- Debian Science Team repository for minpack. Accessed May 28, 2024. https://salsa.debian.org/science-team/minpack/-/blob/master/minpack.h?ref_type=heads;
- cminpack by Frédéric Devernay. Accessed May 29, 2024 https://github.com/devernay/cminpack;
- QuantLib. Accessed May 29, 2024 https://github.com/lballabio/QuantLib/tree/master/ql/math/optimization;
- MINPACK by Burkardt. Accessed May 29, 2024 https://people.sc.fsu.edu/~jburkardt/f_src/minpack/minpack.html;
- LevenbergMarquardtOptimizer by Apache. Accessed May 29, 2024 https://commons.apache.org/proper/commons-math/javadocs/api-3.6.1/org/apache/commons/math3/fitting/leastsquares/LevenbergMarquardtOptimizer.html;
- minpack.lm in R. Accessed May 29, 2024 https://cran.r-project.org/web/packages/minpack.lm/index.html;
- MINPACK.jl in Julia. Acessed May 29, 2024 https://github.com/sglyon/MINPACK.jl.