Fortran and Python programs for maximum-likelihood fitting of a standardized
Student-t distribution. The examples compare fitting through native Fortran,
SciPy, subprocess calls, and ctypes calls into Fortran DLLs.
The main benchmark fits location and scale for a Student-t distribution with
fixed degrees of freedom. A second ctypes example also fits the degrees of
freedom.
kind.f90: shared Fortran kind definitions.fit_density.f90: generic Fortran density-fitting routines for location and scale.xfit_density_test.f90: simulates Student-t data and optionally writes text and binary data files.xfit_t.f90: standalone Fortran fixed-dof Student-t fitter.xfit_t.py: SciPy fixed-dof Student-t fitter.xfit_t_fortran.py: Python wrapper that calls the Fortran executable.fit_t_ctypes.f90: Fortran fixed-dof Student-t shared-library entry point.xfit_t_ctypes.py: Python fixed-dof benchmark using SciPy and Fortran throughctypes.fit_t_dof_ctypes.f90: Fortran shared-library entry point for fitting location, scale, and degrees of freedom.xfit_t_dof_ctypes.py: Python benchmark for fitting location, scale, and degrees of freedom.Makefile: build targets.
The preferred binary input format is:
int32 nobs
int32 nu
float64 observations[nobs]
The text format is also supported. Comment metadata lines begin with #.
Only # nobs: ... and # nu: ... are used by the fitting programs.
With gfortran and make available:
make fit-t
make fit-t-ctypes
make fit-t-dof-ctypesTo generate the example data:
make run-fit-density-testFixed degrees of freedom, comparing Fortran through ctypes with SciPy:
python xfit_t_ctypes.pyFit location, scale, and degrees of freedom:
python xfit_t_dof_ctypes.pyThe scripts have top-level settings for the data path, DLL path, methods to run, maximum number of observations to read, and platform-info printing.
The ctypes benchmark uses matching method numbers for Fortran and Python:
0 Fortran Nelder-Mead, density only
1 Fortran BFGS, first derivative
2 Fortran damped Newton, first and second derivatives
3 SciPy Nelder-Mead, density only
4 SciPy L-BFGS-B, first derivative
5 SciPy trust-exact, first and second derivatives
The fixed-dof model fits location and scale for a standardized Student-t
density. The dof-fitting model uses:
dof = 2 + exp(eta)
so the fitted distribution has finite variance.
Run:
python xfit_t_ctypes.pyData and platform:
xfit_t_ctypes.py: fixed-nu standardized Student-t MLE via Fortran ctypes
data file: fit_density_student_t_data.bin
Fortran library: fit_t_ctypes.dll
nobs in file: 1000000
max nobs to read: 1000000
nobs actually read: 1000000
nu: 5
Platform information
Python: 3.13.3 (CPython)
OS: Windows-11-10.0.26200-SP0
machine: AMD64
processor: Intel64 Family 6 Model 140 Stepping 1, GenuineIntel
CPU count: 8
NumPy: 2.2.6
pandas: 2.2.3
SciPy: 1.15.3
Fortran compiler: gfortran
Fortran compiler version: GNU Fortran (GCC) 16.0.1 20260315 (experimental)
Fortran compiler options: -std=f2018 -O2 -Wall -Wextra -fcheck=all
All methods returned essentially the same MLE:
location estimated: 1.249815
scale estimated: 2.502706
log-likelihood: -2289676.561
The density-only Fortran Nelder-Mead result differed only in the last few decimal places:
location estimated: 1.249780
scale estimated: 2.502672
Timing summary:
Fit wall time elapsed by algorithm and language (seconds)
Fortran Python Python/Fortran
Nelder-Mead 3.5763 21.5273 6.0194
1st derivative 0.4630 13.1065 28.3097
2nd derivative 0.1956 2.0394 10.4275
Geometric average 0.6867 8.3176 12.1122
Total wall times (seconds)
Fortran fit 4.2349
Python fit 36.6733
module import 0.9732
data read 0.0028
Fortran library load 0.0008
total 41.9776
On this platform, Fortran was faster for all three fitting algorithms. The second-derivative methods also required the fewest iterations in both languages.
gfortranmake- Python with:
numpypandasscipy
The Makefile is currently written for a Windows command-line environment and
builds DLLs for the ctypes examples.