This site is version 0.0.1. Most of the code on this site is drafted by an agent and needs review. I apologize for the AI-speak, we are working on rewriting it!
viv-lang.org

Notebooks · posts/fitting-electron-mobility-with-minpack

Electron mobility fitted to NIST's certified digits

A seven-parameter rational model fitted to NIST's semiconductor electron-mobility data by lmder, the Levenberg-Marquardt routine of MINPACK, translated to Viv step by step. Every trial step matches a gfortran build of the original Fortran to the last bit, the answer matches scipy.optimize.leastsq, and the parameters land within 0.001 standard deviations of NIST's certified values.

The data are 37 measurements from a NIST study of electron mobility in a semiconductor, as a function of the natural log of the carrier density (the Thurber data set of NIST's Statistical Reference Datasets). NIST rates the fit "higher difficulty" and publishes certified parameter values to 11 digits. The model is a ratio of two cubics in x with seven parameters,

and the fit minimizes the sum of squares of the 37 residuals .

The fit is done by lmder from lib/minpack: a port of MINPACK's Levenberg-Marquardt code (Moré, Garbow and Hillstrom, Argonne, 1980), the same code scipy.optimize.leastsq calls. Each pass computes the Jacobian , factors it, and tries steps inside a trust region , a radius around the current parameters where the linear model of the residuals is trusted. A step that reduces the sum of squares about as much as the model predicted grows the radius; a step that does worse shrinks it and is retried. The library's intent files (lib/minpack/*.intent) explain each step, and viv story lib/minpack/story_osborne1.viv prints one run iteration by iteration.

Three references check the result:

  1. the original Fortran, built with gfortran and instrumented to record every trial step (lib/minpack/oracle); the port does the same operations in the same order, and on this problem, which uses only arithmetic, every recorded number agrees to the last bit;
  2. scipy.optimize.leastsq, with the same settings;
  3. NIST's certified values.

Look inside this program

  • Atlas

    The program’s map: every function and which calls which.

  • Explore

    Run it and step through what each part did, with the code, values and plots beside it.

Shift+Enter in a cell runs it and moves to the next. Running a cell runs every cell above it too, as one program.

[1]lines 46–113

The fit

info 1 means lmder stopped because both the actual and the predicted relative reduction of the sum of squares fell below the tolerance , where is the machine precision. It took 33 evaluations of the residuals and 27 of the Jacobian; each of the 32 trial steps after the first evaluation is one row of hist.

[2]lines 126–135

How it converged

The first two trial steps, starting with the Gauss-Newton step, make the fit worse and are rejected, and each rejection shrinks the trust radius. Three more are rejected in the next few passes, 5 of the 32 in all. After that every step is accepted, and the norm of the residuals approaches its final value roughly geometrically, with the trust radius no longer the limit: the plot shows, on a log scale, how far the norm still is from its final value.

[3]lines 149–256