home *** CD-ROM | disk | FTP | other *** search
- /* 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);
-
- }