home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 June
/
SIMTEL_0692.cdr
/
msdos
/
educatin
/
polysim.arc
/
POLYSIM.C
next >
Wrap
Text File
|
1989-05-21
|
9KB
|
275 lines
/* Program POLYSIM.C
(c) D.J. Murphy 1989 Borland TurboC v1.5
Room 213
Chemistry Dept.
University of Edinburgh
King's Buildings
West Mains Road
Edinburgh
Scotland
EH9 3JJ
JANET: djm@uk.ac.etive ARPA:djm%ed.etive@nsfnet-relay.ac.uk
Murff@uk.ac.edinburgh Murff%ed@nsfnet-relay.ac.uk
trinity@uk.ac.ed.cs.tardis trinity%ed.cs.tardis@nsfnet-relay.ac.uk
Description:
Uses a modified simplex method to optimize a best-fit polynomial
function to a set of input x,y data pairs. The polynomial is of the form:
y = ax^5 + bx^4 + cx^3 + dx^2 + ex + f + g/x + h/x^2
and POLYSIM optimizes the coefficients a through h to minimize the mean
deviation of y(calculated) from y(given).
Note that, since the optimization is based on MEAN deviations within the
range of the given dataset, it is not recommended that this be used for
extrapolations greatly outwith the input range.
Reference :
S.N. Deming & S.L. Morgan Anal. Chem. 45, 278A(1973)
*/
/************ HEADERS **************/
#include <stdio.h>
#include <process.h>
#include <math.h>
#include <stdlib.h>
/************ DEFINES **************/
#define MAXDAT 100 /* Max # of data points */
#define BOUNDARY 0.01 /* Boundary condition = lowest mean dev
BOUNDARY * y-data range */
/***********************************/
main(argc, argv)
int argc;
char *argv[];
{
double xinput[MAXDAT], yinput[MAXDAT], meandev[9], md2[9];
double ycalc[MAXDAT][9], cf1[8], yrange;
double coeff[9][8];
double adump, bdump, cdump[MAXDAT];
int count = 0;
int sortdump[9];
int acount, bcount, ccount, flag;
unsigned long dcount = 0;
char xin[20], yin[20];
FILE *infile, *temp;
/* Initialize starting coefficients */
for (acount = 0; acount < 8; acount++) {
for (bcount = 0; bcount < 9; bcount++)
coeff[bcount][acount] = 0;
}
for (acount = 0; acount < 9; acount++) {
for (bcount = 0; bcount < acount; bcount++)
coeff[acount][bcount] = 1;
}
/* Check command line parameters and get input file */
if (argc != 3) {
fprintf(stdout, "Usage: polysim inputfile.ext outputfile.ext");
exit(1);
}
if ((infile = fopen(argv[1], "r")) == NULL) {
fprintf(stdout, "Cannot open data file %s\n", argv[1]);
exit(1);
}
while (fscanf(infile, "%s %s", xin, yin) != EOF) {
xinput[count] = atof(xin);
yinput[count] = atof(yin);
/* Vet data to get rid of values likely to lead to overflow or
divide by zero errors */
if (fabs(xinput[count]) > 1e-150)
count++;
}
fclose(infile);
/* Find range of y-data for termination check later on */
adump = 1e300; /* Will become lowest y */
bdump = -1e300; /* Will become highest y */
for (ccount = 0; ccount < count; ccount++) {
if (yinput[ccount] < adump)
adump = yinput[ccount];
if (yinput[ccount] > bdump)
bdump = yinput[ccount];
}
yrange = bdump - adump;
/* Set up simplex */
flag = 1;
/* Flush ycalc */
for (acount = 0; acount < count; acount++) {
for (bcount = 0; bcount < 9; bcount++)
ycalc[acount][bcount] = 0;
}
/* Evaluate first ycalc */
for (ccount = 0; ccount < count; ccount++) { /* Data point */
for (acount = 0; acount < 9; acount++) { /* Vertex 0 - 8 */
for (bcount = 7; bcount >= 0; bcount--) /* Coefficient 0 - 7 */
ycalc[ccount][acount] += (coeff[acount][bcount] * pow(xinput[ccount], (bcount - 2)));
}
}
for (acount = 0; acount < 9; acount++) { /* Evaluate mean deviations */
meandev[acount] = 0; /* flush meandev */
for (bcount = 0; bcount < count; bcount++) /* for each vertex */
meandev[acount] += (ycalc[bcount][acount] - yinput[bcount]);
meandev[acount] = fabs((meandev[acount] / count));
}
/* Start running simplex */
while (flag) {
++dcount;
for (acount = 0; acount < 9; acount++)
md2[acount] = meandev[acount];
/* Sort results by meandev (lowest to highest) into index array */
for (acount = 0; acount < 9; ++acount) {
adump = 1e300;
for (bcount = 0; bcount < 9; ++bcount) {
if (md2[bcount] < adump) {
ccount = bcount;
adump = md2[bcount];
}
}
md2[ccount] = 2e300;
sortdump[acount] = ccount;
}
/* Flush md2 */
for (acount = 0; acount < 9; acount++)
md2[acount] = 0;
/* Find centroid of first 8 points and flush cf1 */
for (acount = 0; acount < 8; acount++) {
for (bcount = 0; bcount < 8; bcount++)
md2[acount] += coeff[(sortdump[bcount])][acount];
md2[acount] /= 8; /* md2 now contains coordinates of centroid */
cf1[acount] = 0;
}
/* Then reflect last point through it and flush cdump */
for (acount = 0; acount < 8; acount++) {
cf1[acount] = 2 * md2[acount] - coeff[(sortdump[8])][acount];
cdump[acount] = 0;
}
/* Then evaluate response */
for (acount = 0; acount < count; acount++) {
bdump = 0;
for (bcount = 7; bcount >= 0; bcount--)
bdump += cf1[bcount] * pow(xinput[acount], (bcount - 2));
cdump[acount] += (bdump - yinput[acount]);
}
for (acount = 0; acount < count; acount++)
bdump += cdump[acount];
bdump = fabs((bdump / count)); /* bdump now = response of new point */
/* See how new response compares with what we already have and act
accordingly:
if bdump < meandev[(sortdump[0])] then double point translation
if bdump > meandev[(sortdump[8])] then quarter point translation
if bdump > meandev[(sortdump[0])] && bdump < meandev[(sortdump[4])]
then 75% translation
otherwise keep translation.
Variable status:
coeff .... coefficients from last cycle
cf1 ...... coefficients from simple reflection of worst point
meandev .. mean deviations from last cycle
dbump .... mean deviation of cf1
sortdump . index to meandev & coeff of quality of solutions sorted
lowest to highest in meandev
md2 ...... coordinates of centroid of best 8 functions
*/
if (bdump < meandev[(sortdump[0])]) {
for (acount = 0; acount < 8; acount++)
coeff[(sortdump[8])][acount] = 4 * md2[acount] - 2 * coeff[(sortdump[8])][acount];
} else if (bdump > meandev[(sortdump[8])]) {
for (acount = 0; acount < 8; acount++)
coeff[(sortdump[8])][acount] = ((md2[acount]/2) - (coeff[(sortdump[8])][acount]/4));
} else if ((bdump > meandev[(sortdump[0])]) && (bdump < meandev[(sortdump[4])])) {
for (acount = 0; acount < 8; acount++)
coeff[(sortdump[8])][acount] = ((6 * md2[acount] - 3 * coeff[(sortdump[8])][acount]) / 4);
} else {
for (acount = 0; acount < 8; acount++)
coeff[(sortdump[8])][acount] = cf1[acount];
}
/* Recalculate point */
for (acount = 0; acount < count; acount++) {
bdump = 0;
for (bcount = 7; bcount >= 0; bcount--)
bdump += coeff[(sortdump[8])][bcount] * pow(xinput[acount], (bcount - 2));
meandev[(sortdump[8])] += (bdump - yinput[acount]);
}
meandev[(sortdump[8])] = fabs((meandev[(sortdump[8])] / count));
/* Check for termination */
adump = fabs((meandev[(sortdump[0])]/yrange));
if (adump < BOUNDARY)
flag = 0;
/* Loop on flag = 1 */
}
/* report results */
if ((infile = fopen(argv[2], "w")) == NULL) {
fprintf(stdout, "\nCannot write to output file %s", argv[2]);
exit(1);
}
fprintf(infile, "Results of analysis of data file : %s after %u iterations\n", argv[1], dcount);
fprintf(infile, "\nCoefficients :");
for (acount = 0; acount < 8; acount++) {
if (fabs(coeff[0][acount]) < 1e-20)
coeff[0][acount] = 0;
fprintf(infile, "\n%c %15g", (acount + 97), coeff[0][acount]);
}
fprintf(infile, "\n\nMean deviation = %15g", meandev[(sortdump[0])]);
fprintf(infile, "\n\nPoint X-given Y-given Y-calculated Difference");
for (acount = 0; acount < count; acount++) {
adump = fabs((yinput[acount] - ycalc[acount][(sortdump[0])]));
fprintf(infile, "\n%5d %15g %15g %15g %15g", (acount + 1), xinput[acount], yinput[acount], ycalc[acount][(sortdump[0])], adump);
}
fclose(infile);
}