home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
vol_200
/
209_01
/
simplib0.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-03-04
|
19KB
|
865 lines
/* SIMPLIB0.C VERS:- 01.00 DATE:- 09/26/86 TIME:- 09:39:24 PM */
/*
Description:
functions for simplex fitting:
simplex fitting routine = simpfit()
quadratic fit for standard deviations = simpdev()
supporting functions
By J.A. Rupley, Tucson, Arizona
Coded for ECO C compiler, version 3.40
*/
#include <stdio.h>
#include <ctrlcnst.h>
#define NPARM 10
/* STRUCTURES */
struct pstruct {
double val ;
double parm[NPARM] ;
} ;
struct qstruct {
int parmndx[NPARM] ;
double q[NPARM] ;
double yplus[NPARM] ;
double yminus[NPARM] ;
double a[NPARM] ;
double bdiag[NPARM] ;
double inv_bdiag[NPARM] ;
double std_dev[NPARM] ;
} ;
/* page eject */
/* SIMPFIT
SIMPLEX MINIMIZATION BY USE OF NELDER-MEAD ALGORITHM,
FOR MODEL DEFINED IN <FUNC()> .
*/
/* defines for simpfit */
#define ILLEGAL 0
#define REFLECT 1
#define STARCONTRACT 2
#define HIGHCONTRACT 3
#define SHRINK 4
#define FAILREFLECT 5
#define STAREXPAND 6
int simpfit(fptr)
FILE *fptr ;
{
register int j, i ;
int opcode ;
int c ;
int test_break ;
int nlow, nhigh ;
struct pstruct *p_best, pbar, pstar, p2star ;
void bsort(), fprintf() ;
int getchar() ;
double sqrt() ;
int pvalcomp(), p_swap() ;
int centroid(), func(), ptrial() ;
void fpprint(), pcopy() ;
extern struct pstruct p[], pcent, *p_p[] ;
extern double exit_test, mean_func, rms_func, test, rms_data;
extern int iter, maxiter, nparm, nvert, ndata, nfree ;
/* expansion-contraction coefficients */
double alpha ;
double beta ;
double gamma ;
/* descriptions of expn-cntrctn operations */
static char *opname[] = {
"illegal",
"reflect",
"reflect & contract",
"contract",
"shrink on lowest vertex",
"reflect after fail to expand",
"reflect and expand"
} ;
nlow = 0 ;
nhigh = nvert - 1 ;
/* initialization:
coefficients
pointers */
alpha = 1 ;
beta = .5 ;
gamma = 2 ;
for (j = 0; j < nvert; j++)
p_p[j] = &p[j] ;
fprintf(fptr,
"\n\ntype ^X to exit loop, ^S to pause\n\n") ;
/* MAIN LOOP OF MINIMIZATION */
while (++iter) {
/* ascending sort of pointers p_p
to struct array p */
bsort(nvert, pvalcomp, p_swap) ;
/* form reduced simplex, pbar,
for (nvert - 1) vertices
ie without high vertex */
centroid(&pbar, p_p, (nvert - 1)) ;
/* form pstar, new reflection trial vertex */
ptrial(&pstar, &pbar, p_p[nhigh], (1 + alpha), -alpha) ;
func(&pstar) ;
/* NELDER-MEAD ALGORITHM = test trial vertex
vs old high and low vertices ;
construct new trial vertices as appropriate;
set pointer to best new vertex */
if (pstar.val < p_p[nlow]->val){
ptrial(&p2star, &pstar, &pbar, (1 + gamma), -gamma) ;
func(&p2star) ;
if (p2star.val < p_p[nlow]->val) {
p_best = &p2star ;
opcode = STAREXPAND ;
} else {
p_best = &pstar ;
opcode = FAILREFLECT ;
}
} else if (pstar.val <= p_p[nhigh-1]->val) {
p_best = &pstar ;
opcode = REFLECT ;
} else {
if (pstar.val <= p_p[nhigh]->val) {
pcopy(p_p[nhigh], &pstar) ;
opcode = STARCONTRACT ;
} else
opcode = HIGHCONTRACT ;
ptrial(&p2star, p_p[nhigh], &pbar, beta, (1-beta)) ;
func(&p2star) ;
if (p2star.val <= p_p[nhigh]->val)
p_best = &p2star ;
else
opcode = SHRINK ;
}
/* END OF NELDER-MEAD ALGORITHM */
/* possible exit from loop on operator kbhit
clear keyboard of any extra chars typed */
test_break = FALSE ;
if (KBHIT) {
c = getchar() ;
while (KBHIT) {
getchar() ;
}
if ((c == CTRLX) || (c == CTRLC))
test_break = TRUE ;
else if (c == CTRLS)
getchar() ;
}
/* print results */
fprintf(fptr, "\n%5d %20.14e %20.14e %s\n",
iter, p_p[nhigh]->val, p_best->val, opname[opcode]) ;
fpprint(fptr, p_p[nhigh]) ;
fpprint(fptr, p_best) ;
/* adjust simplex
either loop over all vertices > lowest = [0]
to shrink on lowest
else copy best movement into high vertex */
if (opcode == SHRINK)
for (j = 1; j < nvert; j++) {
for (i = 0; i < nparm; i++)
p_p[j]->parm[i] = (p_p[nlow]->parm[i]
+ p_p[j]->parm[i])/2 ;
func(p_p[j]) ;
}
else
pcopy(p_p[nhigh], p_best) ;
/* calculate and print new centroid */
centroid(&pcent, p_p, nvert) ;
fpprint(fptr, &pcent) ;
/* calculate and print
mean and rms of function values */
mean_func = 0 ;
for (j = 0; j < nvert; j++)
mean_func = mean_func + p[j].val ;
mean_func = mean_func/nvert ;
rms_func = 0 ;
for (j = 0; j < nvert; j++)
rms_func = rms_func
+ (p[j].val - mean_func) * (p[j].val - mean_func) ;
rms_func = sqrt(rms_func/nvert) ;
test = rms_func/mean_func ;
rms_data = sqrt(p_p[nlow]->val/(ndata - nfree));
fprintf(fptr, "mean=%20.14e rms=%20.14e test=%20.14e\n",
mean_func, rms_func, test) ;
fprintf(fptr,
"root mean square weighted error of best fit to data = %20.14e\n\n",
rms_data) ;
fspecial(fptr) ;
/* exit test
calculate centroid function value if exit */
if ((test_break == TRUE) || (iter == maxiter)) {
func(&pcent) ;
break ;
}
if (test < exit_test) {
func(&pcent) ;
if ((pcent.val - mean_func) < (2 * rms_func))
break ;
}
}
/* END OF MAIN LOOP OF MINIMIZATION */
return (OK) ;
} /* END OF SIMPFIT */
/* page eject */
/* SIMPDEV
QUADRATIC FIT TO FUNCTION SURFACE FOR ESTIMATION OF:
VARIANCE-COVARIANCE MATRIX
STANDARD DEVIATIONS OF PARAMETERS
*/
int simpdev(fptr)
FILE *fptr ;
{
register int i, j, k, l ;
int xfree, free_count ;
int c ;
int err_count ;
double dtemp ;
double yminusij, yplusij ;
double tmparray[NPARM] ;
struct pstruct ptemp ;
void fprintf() ;
int getchar() ;
double sqrt() ;
int func() ;
void fpprint(), pcopy() ;
void fqprint(), fmatprint() ;
void bsort();
int pvalcomp(), p_swap() ;
extern struct pstruct *p_p[], p[], pcent, pmin ;
extern struct qstruct q ;
extern double qmat[][NPARM] ;
extern double rms_data, yzero, ymin, ypmin, mse ;
extern int nparm, nvert, ndata, nfree ;
/* be sure that pcent.val is set */
if (func(&pcent) == ERROR)
return (ERROR) ;
/* ascending sort of pointers p_p
to struct array p */
bsort(nvert, pvalcomp, p_swap) ;
/* if lowest vertex < centroid, then
replace centroid by lowest vertex */
if (p_p[0]->val < pcent.val) {
pcopy(&pcent, p_p[0]);
fprintf(fptr, "\n\nlowest vertex replaces centroid");
}
/* set yzero */
yzero = pcent.val ;
fprintf(fptr,
"\n\nlowest function value = yzero = %20.14e\n\n", yzero) ;
fpprint(fptr, &pcent) ;
fprintf(fptr, "\n") ;
/* calculate
q value = avg devn of a free parameter
from the centroid value ;
store the q value in structure q :
q.q[free_cnt] = q value ;
also store map of free parm to parm array in
q.parmndx[free_cnt] = index of parm
in p[nvert].parm[nparm] ;
set nfree and nvert */
free_cnt = 0 ;
for (i = 0; i < nparm; i++) {
dtemp = 0 ;
for (j = 0; j < nvert; j++)
dtemp = dtemp + ABS(p[j].parm[i] - pcent.parm[i]) ;
dtemp = dtemp/nvert ;
if (ABS(dtemp/pcent.parm[i]) < 1.e-16) {
fprintf(fptr, "parameter %d is fixed\n", i) ;
continue ;
} else {
q.q[free_cnt] = dtemp ;
q.parmndx[free_cnt] = i ;
free_cnt++ ;
}
}
nfree = free_cnt ;
if (nvert != (nfree + 1)) {
fprintf(fptr, "\nerror in count of free parameters\n") ;
return (ERROR) ;
}
fprintf(fptr,
"\nq values for the %d free parameters out of %d total:\n",
nfree, nparm) ;
fqprint(fptr, q.q) ;
/* check and if necessary adjust q values
for each free parameter, to be sure that the
function values are OK for the
centroid parameter values (+ & -) q ;
store function value for parameter value
(+ & -) q in q.yplus and q.yminus */
for (i = 0; i < nfree; i++) {
k = q.parmndx[i] ;
pcopy(&ptemp, &pcent) ;
fprintf(fptr,
"\nchecking q value %d, for parameter %d: ", i, k) ;
while (TRUE) {
fprintf(fptr, "*") ;
while (TRUE) {
ptemp.parm[k] = pcent.parm[k] - q.q[i] ;
if (func(&ptemp) == ERROR)
q.q[i] = q.q[i] / 2 ;
else
break ;
}
q.yminus[i] = ptemp.val ;
dtemp = q.q[i] ;
while (TRUE) {
ptemp.parm[k] = pcent.parm[k] + dtemp ;
if (func(&ptemp) == ERROR)
dtemp = dtemp / 2 ;
else
break ;
}
q.yplus[i] = ptemp.val ;
if (dtemp == q.q[i])
break ;
else
q.q[i] = dtemp ;
}
}
fprintf(fptr, "\n\nadjusted q values:\n") ;
fqprint(fptr, q.q) ;
fprintf(fptr, "\nyplus values:\n") ;
fqprint(fptr, q.yplus) ;
fprintf(fptr, "\nyminus values:\n") ;
fqprint(fptr, q.yminus) ;
/* calculate
<a> vector
store in q.a */
/* calculate
<B> matrix diagonal elements ;
store in qmat and q.bdiag */
for (i = 0; i < nfree; i++) {
q.a[i] = 0.25 * (q.yplus[i] - q.yminus[i]) ;
qmat[i][i] = q.bdiag[i] = 0.5 * (q.yplus[i] + q.yminus[i]
- 2 * yzero) ;
}
fprintf(fptr, "\n<a> vector:\n") ;
fqprint(fptr, q.a) ;
fprintf(fptr,
"\n<B> matrix diagonal:\n") ;
fqprint(fptr, q.bdiag) ;
/* calculate
<B> matrix off-diagonal elements ;
keep track of any function errors ;
store results in qmat */
err_count = 0 ;
for (i = 1; i < nfree; i++) {
k = q.parmndx[i] ;
fprintf(fptr,
"\ncalculating off-diag Bij for row %d: ", i) ;
for (j = 0; j < i; j++) {
fprintf(fptr, "*") ;
l = q.parmndx[j] ;
pcopy(&ptemp, &pcent) ;
ptemp.parm[k] = pcent.parm[k] + q.q[i] ;
ptemp.parm[l] = pcent.parm[l] + q.q[j] ;
if (func(&ptemp) == ERROR)
++err_count ;
yplusij = ptemp.val ;
ptemp.parm[k] = pcent.parm[k] - q.q[i] ;
ptemp.parm[l] = pcent.parm[l] - q.q[j] ;
if (func(&ptemp) == ERROR)
++err_count ;
yminusij = ptemp.val ;
qmat[j][i] = qmat[i][j] = 0.25 * (yplusij + yminusij
+ 2 * yzero - q.yplus[i] - q.yminus[i]
- q.yplus[j] - q.yminus[j]) ;
}
}
if (err_count > 0) {
fprintf(fptr, "\n\n%d function errors in <B> matrix calculation\n",
err_count) ;
return (ERROR) ;
}
fprintf(fptr, "\n\n<B> matrix:\n") ;
fmatprint(fptr, qmat) ;
/* invert
<B> matrix */
xfree = nfree - 1 ;
for (l = 0; l < nfree; l++) {
tmparray[xfree] = 1 / qmat[0][0] ;
for (i = 0; i < xfree; i++)
tmparray[i] = tmparray[xfree] * qmat[0][i+1] ;
for (i = 0; i < xfree; i++) {
qmat[i][xfree] = -tmparray[xfree] * qmat[i+1][0] ;
for (j = 0; j < xfree; j++)
qmat[i][j] = qmat[i+1][j+1]
- tmparray[j] * qmat[i+1][0] ;
}
for (i = 0; i < nfree; i++)
qmat[xfree][i] = tmparray[i] ;
}
fprintf(fptr, "\n<B> matrix inverse:\n") ;
fmatprint(fptr, qmat) ;
/* store
inv B matrix diagonal in q.inv_bdiag */
/* calculate
ymin = yzero - sumij(ai * invBij * aj) */
/* calculate
pmin(k) = centroid(k) - sumj(qi * invBij * aj)
where k = parmndx[i] if parm[k] free
and pmin = centroid if parm[k] fixed */
ymin = yzero ;
pcopy(&pmin, &pcent) ;
for (i = 0; i < nfree; i++) {
q.inv_bdiag[i] = qmat[i][i] ;
k = q.parmndx[i] ;
for (j = 0; j < nfree; j++) {
ymin = ymin - q.a[i] * qmat[i][j] * q.a[j] ;
pmin.parm[k] = pmin.parm[k]
- q.q[i] * qmat[i][j] * q.a[j] ;
}
}
if (func(&pmin) == ERROR)
fprintf(fptr, "\nerror in y-pmin\n") ;
ypmin = pmin.val ;
/* calculate
mse = (func val)/degrees freedom
rms error */
/* calculate
variance-covariance matrix
vcij = qi * invBij * qj * mse */
/* calculate
standard deviations */
mse = pcent.val / (ndata - nfree) ;
rms_data = sqrt(mse) ;
for (i = 0; i < nfree; i++) {
for (j = 0; j < nfree; j++) {
qmat[i][j] = qmat[j][i]
= q.q[i] * qmat[i][j] * q.q[j] * mse ;
}
q.std_dev[i] = sqrt(qmat[i][i]) ;
}
fprintf(fptr,
"\nvariance-covariance matrix:\n") ;
fmatprint(fptr, qmat) ;
/* replace centroid with pmin,
if y-pmin < y-centroid */
/* reconstruct simplex, based on q values
and centroid, in preparation for more fitting ;
nfree vertices are based on nfree q values ;
the remaining vertex is set at the centroid
(or pmin if it is lower) */
fprintf(fptr,"\n\nCalculating for reconstructed simplex...\n\n") ;
if (pmin.val < pcent.val)
pcopy(&p[nfree], &pmin) ;
else
pcopy(&p[nfree], &pcent) ;
for (i = 0; i < nfree; i++) {
pcopy(&p[i], &pcent) ;
k = q.parmndx[i] ;
p[i].parm[k] = p[i].parm[k] + q.q[i] ;
func(&p[i]) ;
}
return (OK) ;
} /* END OF SIMPDEV */
/* page eject */
/* SUPPORTING FUNCTIONS
NOTE THAT <FUNC()> AND <FDATPRINT()>, <MAIN()>, AND
THE INPUT ROUTINE <READ_DATA()> AND ITS SUPPORT ARE IN
SEPARATE FILES
*/
int centroid(pdest, psrc, xvert)
struct pstruct *pdest, *psrc[] ;
int xvert ;
{
register int i, j ;
extern int nparm ;
for (i = 0; i < nparm; i++) {
pdest->parm[i] = psrc[0]->parm[i] ;
for (j = 1; j < xvert; j++)
pdest->parm[i] = pdest->parm[i]
+ (psrc[j]->parm[i]
- psrc[0]->parm[i]) / xvert ;
}
return (OK) ;
} /* END OF CENTROID */
/* code changes parm even if all parms equal-- WRONG CODE
for (i = 0; i < nparm; i++) {
pdest->parm[i] = 0 ;
for (j = 0; j < xvert; j++)
pdest->parm[i] = pdest->parm[i] + psrc[j]->parm[i] ;
pdest->parm[i] = pdest->parm[i] / xvert ;
} */
int ptrial(pnew, p1, p2, coef1, coef2)
struct pstruct *pnew, *p1, *p2 ;
double coef1, coef2 ;
{
register int i ;
extern int nparm ;
for (i = 0; i < nparm; i++)
pnew->parm[i] = p1->parm[i] +
coef2 * (p2->parm[i] - p1->parm[i]) ;
return (OK) ;
} /* END OF PTRIAL */
/* code that possibly changes parm even if all parms equal-- WRONG CODE
pnew->parm[i] = (coef1 * p1->parm[i]) + (coef2 * p2->parm[i]) ; */
void pcopy(pdest, psrc)
struct pstruct *pdest, *psrc ;
{
register int i ;
extern int nparm ;
pdest->val = psrc->val ;
for (i = 0; i < nparm; i++)
pdest->parm[i] = psrc->parm[i] ;
} /* END OF PCOPY */
/* NOTE-- the swap routine exchanges
pointers to structure records ;
the comp routines compare a structure
member for two structure records,
which may be swapped later */
/* swap contents of array elements x and y
which are pointers to structure
records tested in comp routines */
int p_swap(x, y)
int x, y ;
{
int *temp ;
extern struct pstruct *p_p[] ;
temp = p_p[x] ;
p_p[x] = p_p[y] ;
p_p[y] = temp ;
return (OK) ;
} /* END OF P_SWAP */
/* compare float contents of a structure
member for records x and y */
int pvalcomp(x, y)
int x,y ;
{
extern struct pstruct *p_p[] ;
if (p_p[x]->val < p_p[y]->val)
return (-1) ;
else if (p_p[x]->val > p_p[y]->val)
return (1) ;
else
return (0) ;
} /* END OF PVALCOMP */
char *str_in(fptr, dummy)
char *dummy ;
FILE *fptr ;
{
register int i ;
int isspace() ;
int getc() ;
int ungetc() ;
while (isspace(dummy[0] = getc(fptr))) {
}
for (i = 1; !isspace(dummy[i] = getc(fptr)); i++)
;
dummy[i] = '\0' ;
return (&dummy[0]) ;
} /* END OF *STR_IN */
void ffitprint(fptr)
FILE *fptr;
{
void fprintf() ;
void fpprint(), fsprint();
extern int iter ;
extern double mean_func, rms_func, test, rms_data ;
extern struct pstruct pcent ;
extern char title[] ;
/* first all vertices of simplex */
fprintf(fptr,
"\1\f\n%-s\n\nsummary of simplex fitting results:\niteration number %d\n",
title, iter) ;
fsprint(fptr, "\nsimplex:\n") ;
/*then centroid */
fprintf(fptr,
"\ncentroid:\nfunction value = %20.14e\n", pcent.val) ;
fpprint(fptr, &pcent) ;
/* then test for exit, etc */
fprintf(fptr,
"mean=%20.14e rms=%20.14e test=%20.14e\n", mean_func, rms_func, test) ;
fprintf(fptr,
"root mean square weighted error of best fit to data = %20.14e\n\n", rms_data);
} /* END OF FFITPRINT */
void fquadprint(fptr)
FILE *fptr;
{
register int i, k ;
void fprintf() ;
void fsprint();
extern int iter, nfree ;
extern double rms_data ;
extern double yzero, ymin, ypmin, mse ;
extern double mean_func, rms_func, test ;
extern struct qstruct q ;
extern struct pstruct pcent, pmin ;
extern char title[] ;
fprintf(fptr,
"\1\f\n%-s\n\nsummary of results of quadratic fit\niteration number %d\n",
title, iter) ;
fprintf(fptr, "\nmean=%20.14e rms=%20.14e test=%20.14e\n",
mean_func, rms_func, test) ;
fprintf(fptr,
"\nmse = %20.14e rms weighted error = %20.14e\n", mse, rms_data) ;
fprintf(fptr,
"\nyzero = %20.14e\nymin = %20.14e\ny-pmin = %20.14e\n\n",
yzero, ymin, ypmin) ;
fprintf(fptr,
"free parm q centroid pmin std_dev\n") ;
for (i = 0; i < nfree; i++) {
k = q.parmndx[i] ;
fprintf(fptr, "%3d %3d %17.11e %17.11e %17.11e %17.11e\n",
k, i, q.q[i], pcent.parm[k], pmin.parm[k], q.std_dev[i]) ;
}
} /* END OF FQUADPRINT */
/* print nfree x nfree matrix
calls fqprint() */
void fmatprint(fptr, g)
FILE *fptr ;
double g[][NPARM] ;
{
register int i ;
extern int nfree ;
void fqprint() ;
for (i = 0; i < nfree; i++)
fqprint(fptr, g[i]) ;
} /* END OF FMATPRINT */
void fqprint(fptr, g)
FILE *fptr ;
double *g ;
{
register int i ;
void fprintf() ;
extern int nfree ;
for (i = 0; i < nfree; i++) {
if ((i > 0) && ((i % 4) == NULL))
fprintf(fptr, "\n ") ;
fprintf(fptr, "%19.10e", g[i]) ;
}
fprintf(fptr, "\n") ;
} /* END OF FQPRINT */
void fpprint(fptr, g)
FILE *fptr ;
struct pstruct *g ;
{
register int i ;
void fprintf() ;
extern int nparm ;
for (i = 0; i < nparm; i++) {
if (i > 0 && (i % 4) == NULL)
fprintf(fptr, "\n ") ;
fprintf(fptr, "%19.10e", g->parm[i]) ;
}
fprintf(fptr, "\n") ;
} /* END OF FPPRINT */
void fsprint(fptr, string)
char *string ;
FILE *fptr ;
{
register int j ;
void fprintf() ;
void fpprint() ;
extern int nvert ;
extern struct pstruct p[] ;
fprintf(fptr, "%s", string) ;
for (j = 0; j < nvert; j++) {
fprintf(fptr, "vertex = %d function value = %20.14e\n",
j, p[j].val) ;
fpprint(fptr, &p[j]) ;
}
} /* END OF FSPRINT */