/*----------------------------------------------------------------------------*
TEST FOR CONVERGENCE
This routine returns a measure of convergence in parameters being fit. It
carries a running average of each parameter and its rate of change, calculating
a discrete representation of 'w=(1/x)dx/dt' for each parameter. When that
measure sufficiently approaches zero for each parameter, the system has
converged.
For a single number to serve as the measure of convergence, this routine
computes and returns the euclidean distance from the origin of all 'n'
individual 'w's, scaled to the length of the diagonal of the unit hypercube for
that number of parameters. In other words, it returns the square root of the sum
of the squares of the individual 'w's, divided by the square root of 'n'.
There is a potential problem if any of the parameters actually approach zero,
since convergence will then be tested by the ratio of two random numbers
approaching zero. The distribution for that ratio can easily be without mean or
variance (e.g., the Cauchy results if the two numbers are normally distributed).
In such cases, the parameter should be biased before being passed to this
routine, such as by adding one to it.
Note: The routine drops the oldest set of parameters by subtracting it from the
totals, rather than re-summing all the values. This could introduce some
floating-point inaccuracies if it were done hundred of thousands of times, but
in convergence testing it will happen at most thousands of times, so
inaccuracies will not become an issue.
ENTRY: 't' contains the step number, which must be 0 on the very first call
and advance by one on each call thereafter.
'n' contains the number of parameters, which does not exceed 'NPAR'.
'cpar' contains the current set of parameters.
EXIT: 'converge' contains the absolute-value rate of change of parameters,
averaged over the last 'NSTEP' steps, or over how many steps are
available. The closer this is to zero, the closer the fitting system is
to equilibrium. At the very first call, when no differences can be
calculated, 'converge' is negative.
WORK: 'vpar', 'dpar', 'vtot', 'dtot', and 'nstep' are updated on each call.
*/
#include "common.h"
#define NPAR 10 //Maximum number of parameters.
#define NSTEP 20 //Maximum number of steps in the running average.
static dec vpar[NSTEP][NPAR]; //Most recent parameters for running average.
static dec dpar[NSTEP][NPAR]; //Most recent differences for running average.
static dec vtot[NPAR]; //Most recent totals.
static dec dtot[NPAR]; //Most recent total absolute differences.
static dec nstep; //Number of steps in the array.
dec converge(int t, int n, dec cpar[])
{ int i,j, h,k; dec d, e;
if(t==0) //If this is the first call, clear
{ for(i=0; iNPAR) { Error(477.0); n = NPAR; } //Check the number of parameters.
h = (t-1) % NSTEP; k = t % NSTEP; //Locate the current and previous.
for(j=0; jNSTEP) //If a new derivative is available,
{ dtot[j] -= abs(dpar[k][j]); //subtract the old derivative from
vtot[j] -= abs(vpar[k][j]); } //its running total, also the value.
vpar[k][j] = cpar[j]; //Store the new value.
if(t>0) //If a new derivative is available,
{ dpar[k][j] = vpar[h][j]-vpar[k][j]; //add to its running total, and
dtot[j] += abs(dpar[k][j]); //also the value.
vtot[j] += abs(vpar[k][j]); }
if(nstep