[BACK]Return to fit.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gnuplot

Annotation of OpenXM_contrib/gnuplot/fit.c, Revision 1.1.1.3

1.1       maekawa     1: #ifndef lint
1.1.1.3 ! ohara       2: static char *RCSid = "$Id: fit.c,v 1.23.2.6 2002/11/04 14:50:04 broeker Exp $";
1.1       maekawa     3: #endif
                      4:
1.1.1.3 ! ohara       5: /*  NOTICE: Change of Copyright Status
        !             6:  *
        !             7:  *  The author of this module, Carsten Grammes, has expressed in
        !             8:  *  personal email that he has no more interest in this code, and
        !             9:  *  doesn't claim any copyright. He has agreed to put this module
        !            10:  *  into the public domain.
        !            11:  *
        !            12:  *  Lars Hecking  15-02-1999
        !            13:  */
        !            14:
1.1       maekawa    15: /*
                     16:  *    Nonlinear least squares fit according to the
                     17:  *      Marquardt-Levenberg-algorithm
                     18:  *
                     19:  *      added as Patch to Gnuplot (v3.2 and higher)
                     20:  *      by Carsten Grammes
                     21:  *      Experimental Physics, University of Saarbruecken, Germany
                     22:  *
                     23:  *      Internet address: cagr@rz.uni-sb.de
                     24:  *
                     25:  *      Copyright of this module:  1993, 1998  Carsten Grammes
                     26:  *
                     27:  *      Permission to use, copy, and distribute this software and its
                     28:  *      documentation for any purpose with or without fee is hereby granted,
                     29:  *      provided that the above copyright notice appear in all copies and
                     30:  *      that both that copyright notice and this permission notice appear
                     31:  *      in supporting documentation.
                     32:  *
                     33:  *      This software is provided "as is" without express or implied warranty.
                     34:  *
                     35:  *      930726:     Recoding of the Unix-like raw console I/O routines by:
                     36:  *                  Michele Marziani (marziani@ferrara.infn.it)
                     37:  * drd: start unitialised variables at 1 rather than NEARLY_ZERO
                     38:  *  (fit is more likely to converge if started from 1 than 1e-30 ?)
                     39:  *
                     40:  * HBB (Broeker@physik.rwth-aachen.de) : fit didn't calculate the errors
                     41:  * in the 'physically correct' (:-) way, if a third data column containing
                     42:  * the errors (or 'uncertainties') of the input data was given. I think
                     43:  * I've fixed that, but I'm not sure I really understood the M-L-algo well
                     44:  * enough to get it right. I deduced my change from the final steps of the
                     45:  * equivalent algorithm for the linear case, which is much easier to
                     46:  * understand. (I also made some minor, mostly cosmetic changes)
                     47:  *
                     48:  * HBB (again): added error checking for negative covar[i][i] values and
                     49:  * for too many parameters being specified.
                     50:  *
                     51:  * drd: allow 3d fitting. Data value is now called fit_z internally,
                     52:  * ie a 2d fit is z vs x, and a 3d fit is z vs x and y.
                     53:  *
                     54:  * Lars Hecking : review update command, for VMS in particular, where
                     55:  * it is not necessary to rename the old file.
                     56:  *
                     57:  * HBB, 971023: lifted fixed limit on number of datapoints, and number
                     58:  * of parameters.
                     59:  */
                     60:
                     61:
                     62: #define FIT_MAIN
                     63:
                     64: #include <signal.h>
                     65:
                     66: #include "plot.h"
                     67: #include "matrix.h"
                     68: #include "fit.h"
                     69: #include "setshow.h"           /* for load_range */
                     70: #include "alloc.h"
                     71:
                     72: #if defined(MSDOS) || defined(DOS386)  /* non-blocking IO stuff */
                     73: # include <io.h>
                     74: # ifndef _Windows              /* WIN16 does define MSDOS .... */
                     75: #  include <conio.h>
                     76: # endif
                     77: # include <dos.h>
                     78: #else /* !(MSDOS || DOS386) */
                     79: # ifndef VMS
                     80: #  include <fcntl.h>
                     81: # endif                                /* !VMS */
                     82: #endif /* !(MSDOS || DOS386) */
                     83:
                     84: #if defined(ATARI) || defined(MTOS)
                     85: # define getchx() Crawcin()
                     86: static int kbhit(void);
                     87: #endif
                     88:
                     89: #define STANDARD    stderr     /* compatible with gnuplot philosophy */
                     90:
                     91: #define BACKUP_SUFFIX ".old"
                     92:
                     93:
                     94: /* access external global variables  (ought to make a globals.h someday) */
                     95:
                     96: extern struct udft_entry *dummy_func;
                     97: extern char dummy_var[MAX_NUM_VAR][MAX_ID_LEN+1];
                     98: extern char c_dummy_var[MAX_NUM_VAR][MAX_ID_LEN+1];
                     99: extern int c_token;
                    100: extern int df_datum, df_line_number;
                    101:
1.1.1.2   maekawa   102: /* following 2 external arrays are needed to use time data */
                    103: extern int datatype[];
                    104: extern int df_timecol[];
1.1       maekawa   105:
                    106: enum marq_res {
                    107:     OK, ERROR, BETTER, WORSE
                    108: };
                    109: typedef enum marq_res marq_res_t;
                    110:
                    111: #ifdef INFINITY
                    112: # undef INFINITY
                    113: #endif
                    114:
                    115: #define INFINITY    1e30
                    116: #define NEARLY_ZERO 1e-30
                    117:
                    118: /* create new variables with this value (was NEARLY_ZERO) */
                    119: #define INITIAL_VALUE 1.0
                    120:
                    121: /* Relative change for derivatives */
                    122: #define DELTA      0.001
                    123:
                    124: #define MAX_DATA    2048
                    125: #define MAX_PARAMS  32
                    126: #define MAX_LAMBDA  1e20
                    127: #define MIN_LAMBDA  1e-20
                    128: #define LAMBDA_UP_FACTOR 10
                    129: #define LAMBDA_DOWN_FACTOR 10
                    130:
                    131: #if defined(MSDOS) || defined(OS2) || defined(DOS386)
                    132: # define PLUSMINUS   "\xF1"    /* plusminus sign */
                    133: #else
                    134: # define PLUSMINUS   "+/-"
                    135: #endif
                    136:
                    137: #define LASTFITCMDLENGTH 511
                    138:
                    139: /* HBB 971023: new, allow for dynamic adjustment of these: */
                    140: static int max_data;
                    141: static int max_params;
                    142:
                    143: static double epsilon = 1e-5;  /* convergence limit */
                    144: static int maxiter = 0;                /* HBB 970304: maxiter patch */
                    145:
                    146: static char fit_script[128];
                    147: static char logfile[128] = "fit.log";
                    148: static char *FIXED = "# FIXED";
                    149: static char *GNUFITLOG = "FIT_LOG";
                    150: static char *FITLIMIT = "FIT_LIMIT";
                    151: static char *FITSTARTLAMBDA = "FIT_START_LAMBDA";
                    152: static char *FITLAMBDAFACTOR = "FIT_LAMBDA_FACTOR";
                    153: static char *FITMAXITER = "FIT_MAXITER";       /* HBB 970304: maxiter patch */
                    154: static char *FITSCRIPT = "FIT_SCRIPT";
                    155: static char *DEFAULT_CMD = "replot";   /* if no fitscript spec. */
                    156: static char last_fit_command[LASTFITCMDLENGTH+1] = "";
                    157:
                    158:
                    159: static FILE *log_f = NULL;
                    160:
                    161: static int num_data, num_params;
                    162: static int columns;
                    163: static double *fit_x = 0, *fit_y = 0, *fit_z = 0, *err_data = 0, *a = 0;
                    164: static TBOOLEAN ctrlc_flag = FALSE;
                    165: static TBOOLEAN user_stop = FALSE;
                    166:
                    167: static struct udft_entry func;
                    168:
                    169: typedef char fixstr[MAX_ID_LEN+1];
                    170:
                    171: static fixstr *par_name;
                    172:
                    173: static double startup_lambda = 0, lambda_down_factor = LAMBDA_DOWN_FACTOR,
                    174:  lambda_up_factor = LAMBDA_UP_FACTOR;
                    175:
                    176: /*****************************************************************
                    177:                         internal Prototypes
                    178: *****************************************************************/
                    179:
                    180: static RETSIGTYPE ctrlc_handle __PROTO((int an_int));
                    181: static void ctrlc_setup __PROTO((void));
                    182: static void printmatrix __PROTO((double **C, int m, int n));
                    183: static void print_matrix_and_vectors __PROTO((double **C, double *d, double *r, int m, int n));
                    184: static marq_res_t marquardt __PROTO((double a[], double **alpha, double *chisq,
                    185:                                     double *lambda));
                    186: static TBOOLEAN analyze __PROTO((double a[], double **alpha, double beta[],
                    187:                                 double *chisq));
                    188: static void calculate __PROTO((double *zfunc, double **dzda, double a[]));
                    189: static void call_gnuplot __PROTO((double *par, double *data));
                    190: static TBOOLEAN fit_interrupt __PROTO((void));
                    191: static TBOOLEAN regress __PROTO((double a[]));
                    192: static void show_fit __PROTO((int i, double chisq, double last_chisq, double *a,
                    193:                              double lambda, FILE * device));
                    194: static TBOOLEAN is_empty __PROTO((char *s));
                    195: static TBOOLEAN is_variable __PROTO((char *s));
                    196: static double getdvar __PROTO((char *varname));
                    197: static double createdvar __PROTO((char *varname, double value));
                    198: static void splitpath __PROTO((char *s, char *p, char *f));
                    199: static void backup_file __PROTO((char *, const char *));
                    200:
                    201:
                    202: /*****************************************************************
                    203:     Small function to write the last fit command into a file
                    204:     Arg: Pointer to the file; if NULL, nothing is written,
                    205:          but only the size of the string is returned.
                    206: *****************************************************************/
                    207:
                    208: size_t wri_to_fil_last_fit_cmd(fp)
                    209: FILE *fp;
                    210: {
                    211:     if (fp == NULL)
                    212:        return strlen(last_fit_command);
                    213:     else
                    214:        return (size_t) fputs(last_fit_command, fp);
                    215: }
                    216:
                    217:
                    218: /*****************************************************************
                    219:     This is called when a SIGINT occurs during fit
                    220: *****************************************************************/
                    221:
                    222: static RETSIGTYPE ctrlc_handle(an_int)
                    223: int an_int;
                    224: {
                    225: #ifdef OS2
                    226:     (void) signal(an_int, SIG_ACK);
                    227: #else
                    228:     /* reinstall signal handler (necessary on SysV) */
                    229:     (void) signal(SIGINT, (sigfunc) ctrlc_handle);
                    230: #endif
                    231:     ctrlc_flag = TRUE;
                    232: }
                    233:
                    234:
                    235: /*****************************************************************
                    236:     setup the ctrl_c signal handler
                    237: *****************************************************************/
                    238: static void ctrlc_setup()
                    239: {
                    240: /*
                    241:  *  MSDOS defines signal(SIGINT) but doesn't handle it through
                    242:  *  real interrupts. So there remain cases in which a ctrl-c may
                    243:  *  be uncaught by signal. We must use kbhit() instead that really
                    244:  *  serves the keyboard interrupt (or write an own interrupt func
                    245:  *  which also generates #ifdefs)
                    246:  *
                    247:  *  I hope that other OSes do it better, if not... add #ifdefs :-(
                    248:  */
                    249: #if (defined(__EMX__) || !defined(MSDOS) && !defined(DOS386)) && !defined(ATARI) && !defined(MTOS)
                    250:     (void) signal(SIGINT, (sigfunc) ctrlc_handle);
                    251: #endif
                    252: }
                    253:
                    254:
                    255: /*****************************************************************
                    256:     getch that handles also function keys etc.
                    257: *****************************************************************/
                    258: #if defined(MSDOS) || defined(DOS386)
                    259:
                    260: /* HBB 980317: added a prototype... */
                    261: int getchx __PROTO((void));
                    262:
                    263: int getchx()
                    264: {
                    265:     register int c = getch();
                    266:     if (!c || c == 0xE0) {
                    267:        c <<= 8;
                    268:        c |= getch();
                    269:     }
                    270:     return c;
                    271: }
                    272: #endif
                    273:
                    274: /*****************************************************************
                    275:     in case of fatal errors
                    276: *****************************************************************/
                    277: void error_ex()
                    278: {
                    279:     char *sp;
                    280:
                    281:     strncpy(fitbuf, "         ", 9);           /* start after GNUPLOT> */
                    282:     sp = strchr(fitbuf, NUL);
                    283:     while (*--sp == '\n')
                    284:        ;
                    285:     strcpy(sp + 1, "\n\n");    /* terminate with exactly 2 newlines */
                    286:     fputs(fitbuf, STANDARD);
                    287:     if (log_f) {
                    288:        fprintf(log_f, "BREAK: %s", fitbuf);
                    289:        (void) fclose(log_f);
                    290:        log_f = NULL;
                    291:     }
                    292:     if (func.at) {
                    293:        free(func.at);          /* release perm. action table */
                    294:        func.at = (struct at_type *) NULL;
                    295:     }
                    296:     /* restore original SIGINT function */
                    297: #if !defined(ATARI) && !defined(MTOS)
                    298:     interrupt_setup();
                    299: #endif
                    300:
                    301:     bail_to_command_line();
                    302: }
                    303:
                    304:
                    305: /*****************************************************************
                    306:     New utility routine: print a matrix (for debugging the alg.)
                    307: *****************************************************************/
                    308: static void printmatrix(C, m, n)
                    309: double **C;
                    310: int m, n;
                    311: {
                    312:     int i, j;
                    313:
                    314:     for (i = 0; i < m; i++) {
                    315:        for (j = 0; j < n - 1; j++)
                    316:            Dblf2("%.8g |", C[i][j]);
                    317:        Dblf2("%.8g\n", C[i][j]);
                    318:     }
                    319:     Dblf("\n");
                    320: }
                    321:
                    322: /**************************************************************************
                    323:     Yet another debugging aid: print matrix, with diff. and residue vector
                    324: **************************************************************************/
                    325: static void print_matrix_and_vectors(C, d, r, m, n)
                    326: double **C;
                    327: double *d, *r;
                    328: int m, n;
                    329: {
                    330:     int i, j;
                    331:
                    332:     for (i = 0; i < m; i++) {
                    333:        for (j = 0; j < n; j++)
                    334:            Dblf2("%8g ", C[i][j]);
                    335:        Dblf3("| %8g | %8g\n", d[i], r[i]);
                    336:     }
                    337:     Dblf("\n");
                    338: }
                    339:
                    340:
                    341: /*****************************************************************
                    342:     Marquardt's nonlinear least squares fit
                    343: *****************************************************************/
                    344: static marq_res_t marquardt(a, C, chisq, lambda)
                    345: double a[];
                    346: double **C;
                    347: double *chisq;
                    348: double *lambda;
                    349: {
                    350:     int i, j;
                    351:     static double *da = 0,     /* delta-step of the parameter */
                    352:     *temp_a = 0,               /* temptative new params set   */
                    353:     *d = 0, *tmp_d = 0, **tmp_C = 0, *residues = 0;
                    354:     double tmp_chisq;
                    355:
                    356:     /* Initialization when lambda == -1 */
                    357:
                    358:     if (*lambda == -1) {       /* Get first chi-square check */
                    359:        TBOOLEAN analyze_ret;
                    360:
                    361:        temp_a = vec(num_params);
                    362:        d = vec(num_data + num_params);
                    363:        tmp_d = vec(num_data + num_params);
                    364:        da = vec(num_params);
                    365:        residues = vec(num_data + num_params);
                    366:        tmp_C = matr(num_data + num_params, num_params);
                    367:
                    368:        analyze_ret = analyze(a, C, d, chisq);
                    369:
                    370:        /* Calculate a useful startup value for lambda, as given by Schwarz */
                    371:        /* FIXME: this is doesn't turn out to be much better, really... */
                    372:        if (startup_lambda != 0)
                    373:            *lambda = startup_lambda;
                    374:        else {
                    375:            *lambda = 0;
                    376:            for (i = 0; i < num_data; i++)
                    377:                for (j = 0; j < num_params; j++)
                    378:                    *lambda += C[i][j] * C[i][j];
                    379:            *lambda = sqrt(*lambda / num_data / num_params);
                    380:        }
                    381:
                    382:        /* Fill in the lower square part of C (the diagonal is filled in on
                    383:           each iteration, see below) */
                    384:        for (i = 0; i < num_params; i++)
                    385:            for (j = 0; j < i; j++)
                    386:                C[num_data + i][j] = 0, C[num_data + j][i] = 0;
                    387:        /*printmatrix(C, num_data+num_params, num_params); */
                    388:        return analyze_ret ? OK : ERROR;
                    389:     }
                    390:     /* once converged, free dynamic allocated vars */
                    391:
                    392:     if (*lambda == -2) {
                    393:        free(d);
                    394:        free(tmp_d);
                    395:        free(da);
                    396:        free(temp_a);
                    397:        free(residues);
                    398:        free_matr(tmp_C);
                    399:        return OK;
                    400:     }
                    401:     /* Givens calculates in-place, so make working copies of C and d */
                    402:
                    403:     for (j = 0; j < num_data + num_params; j++)
                    404:        memcpy(tmp_C[j], C[j], num_params * sizeof(double));
                    405:     memcpy(tmp_d, d, num_data * sizeof(double));
                    406:
                    407:     /* fill in additional parts of tmp_C, tmp_d */
                    408:
                    409:     for (i = 0; i < num_params; i++) {
                    410:        /* fill in low diag. of tmp_C ... */
                    411:        tmp_C[num_data + i][i] = *lambda;
                    412:        /* ... and low part of tmp_d */
                    413:        tmp_d[num_data + i] = 0;
                    414:     }
                    415:     /* printmatrix(tmp_C, num_data+num_params, num_params); */
                    416:
                    417:     /* FIXME: residues[] isn't used at all. Why? Should it be used? */
                    418:
                    419:     Givens(tmp_C, tmp_d, da, residues, num_params + num_data, num_params, 1);
                    420:     /*print_matrix_and_vectors (tmp_C, tmp_d, residues,
                    421:        num_params+num_data, num_params); */
                    422:
                    423:     /* check if trial did ameliorate sum of squares */
                    424:
                    425:     for (j = 0; j < num_params; j++)
                    426:        temp_a[j] = a[j] + da[j];
                    427:
                    428:     if (!analyze(temp_a, tmp_C, tmp_d, &tmp_chisq)) {
                    429:        /* FIXME: will never be reached: always returns TRUE */
                    430:        return ERROR;
                    431:     }
                    432:
                    433:     if (tmp_chisq < *chisq) {  /* Success, accept new solution */
                    434:        if (*lambda > MIN_LAMBDA) {
                    435:            (void) putc('/', stderr);
                    436:            *lambda /= lambda_down_factor;
                    437:        }
                    438:        *chisq = tmp_chisq;
                    439:        for (j = 0; j < num_data; j++) {
                    440:            memcpy(C[j], tmp_C[j], num_params * sizeof(double));
                    441:            d[j] = tmp_d[j];
                    442:        }
                    443:        for (j = 0; j < num_params; j++)
                    444:            a[j] = temp_a[j];
                    445:        return BETTER;
                    446:     } else {                   /* failure, increase lambda and return */
                    447:        (void) putc('*', stderr);
                    448:        *lambda *= lambda_up_factor;
                    449:        return WORSE;
                    450:     }
                    451: }
                    452:
                    453:
                    454: /* FIXME: in the new code, this function doesn't really do enough to be
                    455:  * useful. Maybe it ought to be deleted, i.e. integrated with
                    456:  * calculate() ?
                    457:  */
                    458: /*****************************************************************
                    459:     compute chi-square and numeric derivations
                    460: *****************************************************************/
                    461: static TBOOLEAN analyze(a, C, d, chisq)
                    462: double a[];
                    463: double **C;
                    464: double d[];
                    465: double *chisq;
                    466: {
                    467: /*
                    468:  *  used by marquardt to evaluate the linearized fitting matrix C
                    469:  *  and vector d, fills in only the top part of C and d
                    470:  *  I don't use a temporary array zfunc[] any more. Just use
                    471:  *  d[] instead.
                    472:  */
                    473:     int i, j;
                    474:
                    475:     *chisq = 0;
                    476:     calculate(d, C, a);
                    477:
                    478:     for (i = 0; i < num_data; i++) {
                    479:        /* note: order reversed, as used by Schwarz */
                    480:        d[i] = (d[i] - fit_z[i]) / err_data[i];
                    481:        *chisq += d[i] * d[i];
                    482:        for (j = 0; j < num_params; j++)
                    483:            C[i][j] /= err_data[i];
                    484:     }
                    485:     /* FIXME: why return a value that is always TRUE ? */
                    486:     return TRUE;
                    487: }
                    488:
                    489:
                    490: /* To use the more exact, but slower two-side formula, activate the
                    491:    following line: */
                    492: /*#define TWO_SIDE_DIFFERENTIATION */
                    493: /*****************************************************************
                    494:     compute function values and partial derivatives of chi-square
                    495: *****************************************************************/
                    496: static void calculate(zfunc, dzda, a)
                    497: double *zfunc;
                    498: double **dzda;
                    499: double a[];
                    500: {
                    501:     int k, p;
                    502:     double tmp_a;
                    503:     double *tmp_high, *tmp_pars;
                    504: #ifdef TWO_SIDE_DIFFERENTIATION
                    505:     double *tmp_low;
                    506: #endif
                    507:
                    508:     tmp_high = vec(num_data);  /* numeric derivations */
                    509: #ifdef TWO_SIDE_DIFFERENTIATION
                    510:     tmp_low = vec(num_data);
                    511: #endif
                    512:     tmp_pars = vec(num_params);
                    513:
                    514:     /* first function values */
                    515:
                    516:     call_gnuplot(a, zfunc);
                    517:
                    518:     /* then derivatives */
                    519:
                    520:     for (p = 0; p < num_params; p++)
                    521:        tmp_pars[p] = a[p];
                    522:     for (p = 0; p < num_params; p++) {
                    523:        tmp_a = fabs(a[p]) < NEARLY_ZERO ? NEARLY_ZERO : a[p];
                    524:        tmp_pars[p] = tmp_a * (1 + DELTA);
                    525:        call_gnuplot(tmp_pars, tmp_high);
                    526: #ifdef TWO_SIDE_DIFFERENTIATION
                    527:        tmp_pars[p] = tmp_a * (1 - DELTA);
                    528:        call_gnuplot(tmp_pars, tmp_low);
                    529: #endif
                    530:        for (k = 0; k < num_data; k++)
                    531: #ifdef TWO_SIDE_DIFFERENTIATION
                    532:            dzda[k][p] = (tmp_high[k] - tmp_low[k]) / (2 * tmp_a * DELTA);
                    533: #else
                    534:            dzda[k][p] = (tmp_high[k] - zfunc[k]) / (tmp_a * DELTA);
                    535: #endif
                    536:        tmp_pars[p] = a[p];
                    537:     }
                    538:
                    539: #ifdef TWO_SIDE_DIFFERENTIATION
                    540:     free(tmp_low);
                    541: #endif
                    542:     free(tmp_high);
                    543:     free(tmp_pars);
                    544: }
                    545:
                    546:
                    547: /*****************************************************************
                    548:     call internal gnuplot functions
                    549: *****************************************************************/
                    550: static void call_gnuplot(par, data)
                    551: double *par;
                    552: double *data;
                    553: {
                    554:     int i;
                    555:     struct value v;
                    556:
                    557:     /* set parameters first */
                    558:     for (i = 0; i < num_params; i++) {
                    559:        (void) Gcomplex(&v, par[i], 0.0);
                    560:        setvar(par_name[i], v);
                    561:     }
                    562:
                    563:     for (i = 0; i < num_data; i++) {
                    564:        /* calculate fit-function value */
                    565:        (void) Gcomplex(&func.dummy_values[0], fit_x[i], 0.0);
                    566:        (void) Gcomplex(&func.dummy_values[1], fit_y[i], 0.0);
                    567:        evaluate_at(func.at, &v);
                    568:        if (undefined)
                    569:            Eex("Undefined value during function evaluation");
                    570:        data[i] = real(&v);
                    571:     }
                    572: }
                    573:
                    574:
                    575: /*****************************************************************
                    576:     handle user interrupts during fit
                    577: *****************************************************************/
                    578: static TBOOLEAN fit_interrupt()
                    579: {
                    580:     while (TRUE) {
                    581:        fputs("\n\n(S)top fit, (C)ontinue, (E)xecute FIT_SCRIPT:  ", STANDARD);
                    582:        switch (getc(stdin)) {
                    583:
                    584:        case EOF:
                    585:        case 's':
                    586:        case 'S':
                    587:            fputs("Stop.", STANDARD);
                    588:            user_stop = TRUE;
                    589:            return FALSE;
                    590:
                    591:        case 'c':
                    592:        case 'C':
                    593:            fputs("Continue.", STANDARD);
                    594:            return TRUE;
                    595:
                    596:        case 'e':
                    597:        case 'E':{
                    598:                int i;
                    599:                struct value v;
                    600:                char *tmp;
                    601:
                    602:                tmp = (fit_script != 0 && *fit_script) ? fit_script : DEFAULT_CMD;
                    603:                fprintf(STANDARD, "executing: %s", tmp);
                    604:                /* set parameters visible to gnuplot */
                    605:                for (i = 0; i < num_params; i++) {
                    606:                    (void) Gcomplex(&v, a[i], 0.0);
                    607:                    setvar(par_name[i], v);
                    608:                }
                    609:                sprintf(input_line, tmp);
                    610:                (void) do_line();
                    611:            }
                    612:        }
                    613:     }
                    614:     return TRUE;
                    615: }
                    616:
                    617:
                    618: /*****************************************************************
                    619:     frame routine for the marquardt-fit
                    620: *****************************************************************/
                    621: static TBOOLEAN regress(a)
1.1.1.3 ! ohara     622:     double a[];
1.1       maekawa   623: {
                    624:     double **covar, *dpar, **C, chisq, last_chisq, lambda;
                    625:     int iter, i, j;
                    626:     marq_res_t res;
                    627:
                    628:     chisq = last_chisq = INFINITY;
                    629:     C = matr(num_data + num_params, num_params);
                    630:     lambda = -1;               /* use sign as flag */
                    631:     iter = 0;                  /* iteration counter  */
                    632:
                    633:     /* ctrlc now serves as Hotkey */
                    634:     ctrlc_setup();
                    635:
                    636:     /* Initialize internal variables and 1st chi-square check */
                    637:     if ((res = marquardt(a, C, &chisq, &lambda)) == ERROR)
1.1.1.3 ! ohara     638:        Eex("FIT: error occurred during fit");
1.1       maekawa   639:     res = BETTER;
                    640:
                    641:     show_fit(iter, chisq, chisq, a, lambda, STANDARD);
                    642:     show_fit(iter, chisq, chisq, a, lambda, log_f);
                    643:
                    644:     /* MAIN FIT LOOP: do the regression iteration */
                    645:
                    646:     /* HBB 981118: initialize new variable 'user_break' */
                    647:     user_stop = FALSE;
                    648:
                    649:     do {
                    650: /*
                    651:  *  MSDOS defines signal(SIGINT) but doesn't handle it through
                    652:  *  real interrupts. So there remain cases in which a ctrl-c may
                    653:  *  be uncaught by signal. We must use kbhit() instead that really
                    654:  *  serves the keyboard interrupt (or write an own interrupt func
                    655:  *  which also generates #ifdefs)
                    656:  *
                    657:  *  I hope that other OSes do it better, if not... add #ifdefs :-(
                    658:  *  EMX does not have kbhit.
                    659:  *
                    660:  *  HBB: I think this can be enabled for DJGPP V2. SIGINT is actually
                    661:  *  handled there, AFAIK.
                    662:  */
                    663: #if ((defined(MSDOS) || defined(DOS386)) && !defined(__EMX__)) || defined(ATARI) || defined(MTOS)
                    664:        if (kbhit()) {
                    665:            do {
                    666:                getchx();
                    667:            } while (kbhit());
                    668:            ctrlc_flag = TRUE;
                    669:        }
                    670: #endif
                    671:
                    672:        if (ctrlc_flag) {
                    673:            show_fit(iter, chisq, last_chisq, a, lambda, STANDARD);
                    674:            ctrlc_flag = FALSE;
                    675:            if (!fit_interrupt())       /* handle keys */
                    676:                break;
                    677:        }
                    678:        if (res == BETTER) {
                    679:            iter++;
                    680:            last_chisq = chisq;
                    681:        }
                    682:        if ((res = marquardt(a, C, &chisq, &lambda)) == BETTER)
                    683:            show_fit(iter, chisq, last_chisq, a, lambda, STANDARD);
                    684:     } while ((res != ERROR)
                    685:             && (lambda < MAX_LAMBDA)
                    686:             && ((maxiter == 0) || (iter <= maxiter))
                    687:             && (res == WORSE
                    688:                 || ((chisq > NEARLY_ZERO)
                    689:                     ? ((last_chisq - chisq) / chisq)
                    690:                     : (last_chisq - chisq)) > epsilon
                    691:             )
                    692:        );
                    693:
                    694:     /* fit done */
                    695:
                    696: #if !defined(ATARI) && !defined(MTOS)
                    697:     /* restore original SIGINT function */
                    698:     interrupt_setup();
                    699: #endif
                    700:
                    701:     /* HBB 970304: the maxiter patch: */
                    702:     if ((maxiter > 0) && (iter > maxiter)) {
                    703:        Dblf2("\nMaximum iteration count (%d) reached. Fit stopped.\n", maxiter);
                    704:     } else if (user_stop) {
                    705:        Dblf2("\nThe fit was stopped by the user after %d iterations.\n", iter);
                    706:     } else {
                    707:        Dblf2("\nAfter %d iterations the fit converged.\n", iter);
                    708:     }
                    709:
                    710:     Dblf2("final sum of squares of residuals : %g\n", chisq);
                    711:     if (chisq > NEARLY_ZERO) {
                    712:        Dblf2("rel. change during last iteration : %g\n\n", (chisq - last_chisq) / chisq);
                    713:     } else {
                    714:        Dblf2("abs. change during last iteration : %g\n\n", (chisq - last_chisq));
                    715:     }
                    716:
                    717:     if (res == ERROR)
1.1.1.3 ! ohara     718:        Eex("FIT: error occurred during fit");
1.1       maekawa   719:
                    720:     /* compute errors in the parameters */
                    721:
                    722:     if (num_data == num_params) {
                    723:        int i;
                    724:
                    725:        Dblf("\nExactly as many data points as there are parameters.\n");
                    726:        Dblf("In this degenerate case, all errors are zero by definition.\n\n");
                    727:        Dblf("Final set of parameters \n");
                    728:        Dblf("======================= \n\n");
                    729:        for (i = 0; i < num_params; i++)
                    730:            Dblf3("%-15.15s = %-15g\n", par_name[i], a[i]);
                    731:     } else if (chisq < NEARLY_ZERO) {
                    732:        int i;
                    733:
                    734:        Dblf("\nHmmmm.... Sum of squared residuals is zero. Can't compute errors.\n\n");
                    735:        Dblf("Final set of parameters \n");
                    736:        Dblf("======================= \n\n");
                    737:        for (i = 0; i < num_params; i++)
                    738:            Dblf3("%-15.15s = %-15g\n", par_name[i], a[i]);
                    739:     } else {
1.1.1.2   maekawa   740:        Dblf2("degrees of freedom (ndf) : %d\n",  num_data - num_params);
                    741:        Dblf2("rms of residuals      (stdfit) = sqrt(WSSR/ndf)      : %g\n", sqrt(chisq / (num_data - num_params)));
                    742:        Dblf2("variance of residuals (reduced chisquare) = WSSR/ndf : %g\n\n", chisq / (num_data - num_params));
1.1       maekawa   743:
                    744:        /* get covariance-, Korrelations- and Kurvature-Matrix */
                    745:        /* and errors in the parameters                     */
                    746:
                    747:        /* compute covar[][] directly from C */
                    748:        Givens(C, 0, 0, 0, num_data, num_params, 0);
                    749:        /*printmatrix(C, num_params, num_params); */
                    750:
                    751:        /* Use lower square of C for covar */
                    752:        covar = C + num_data;
                    753:        Invert_RtR(C, covar, num_params);
                    754:        /*printmatrix(covar, num_params, num_params); */
                    755:
                    756:        /* calculate unscaled parameter errors in dpar[]: */
                    757:        dpar = vec(num_params);
                    758:        for (i = 0; i < num_params; i++) {
                    759:            /* FIXME: can this still happen ? */
                    760:            if (covar[i][i] <= 0.0)     /* HBB: prevent floating point exception later on */
                    761:                Eex("Calculation error: non-positive diagonal element in covar. matrix");
                    762:            dpar[i] = sqrt(covar[i][i]);
                    763:        }
                    764:
                    765:        /* transform covariances into correlations */
                    766:        for (i = 0; i < num_params; i++) {
                    767:            /* only lower triangle needs to be handled */
                    768:            for (j = 0; j <= i; j++)
                    769:                covar[i][j] /= dpar[i] * dpar[j];
                    770:        }
                    771:
                    772:        /* scale parameter errors based on chisq */
                    773:        chisq = sqrt(chisq / (num_data - num_params));
                    774:        for (i = 0; i < num_params; i++)
                    775:            dpar[i] *= chisq;
                    776:
                    777:        Dblf("Final set of parameters            Asymptotic Standard Error\n");
                    778:        Dblf("=======================            ==========================\n\n");
                    779:
                    780:        for (i = 0; i < num_params; i++) {
                    781:            double temp =
                    782:            (fabs(a[i]) < NEARLY_ZERO) ? 0.0 : fabs(100.0 * dpar[i] / a[i]);
                    783:            Dblf6("%-15.15s = %-15g  %-3.3s %-12.4g (%.4g%%)\n",
                    784:                  par_name[i], a[i], PLUSMINUS, dpar[i], temp);
                    785:        }
                    786:
                    787:        Dblf("\n\ncorrelation matrix of the fit parameters:\n\n");
                    788:        Dblf("               ");
                    789:
                    790:        for (j = 0; j < num_params; j++)
                    791:            Dblf2("%-6.6s ", par_name[j]);
                    792:
                    793:        Dblf("\n");
                    794:        for (i = 0; i < num_params; i++) {
                    795:            Dblf2("%-15.15s", par_name[i]);
                    796:            for (j = 0; j <= i; j++) {
                    797:                /* Only print lower triangle of symmetric matrix */
                    798:                Dblf2("%6.3f ", covar[i][j]);
                    799:            }
                    800:            Dblf("\n");
                    801:        }
                    802:
                    803:        free(dpar);
                    804:     }
                    805:
1.1.1.2   maekawa   806:     /* HBB 990220: re-imported this snippet from older versions. Finally,
                    807:      * some user noticed that it *is* necessary, after all. Not even
                    808:      * Carsten Grammes himself remembered what it was for... :-(
                    809:      * The thing is: the value of the last parameter is not reset to
                    810:      * its original one after the derivatives have been calculated
                    811:      */
                    812:     /* restore last parameter's value (not done by calculate) */
                    813:     {
                    814:        struct value val;
                    815:        Gcomplex (&val, a[num_params-1], 0.0);
                    816:        setvar (par_name[num_params-1], val);
                    817:      }
                    818:
1.1       maekawa   819:     /* call destructor for allocated vars */
                    820:     lambda = -2;               /* flag value, meaning 'destruct!' */
                    821:     (void) marquardt(a, C, &chisq, &lambda);
                    822:
                    823:     free_matr(C);
                    824:     return TRUE;
                    825: }
                    826:
                    827:
                    828: /*****************************************************************
                    829:     display actual state of the fit
                    830: *****************************************************************/
                    831: static void show_fit(i, chisq, last_chisq, a, lambda, device)
                    832: int i;
                    833: double chisq;
                    834: double last_chisq;
                    835: double *a;
                    836: double lambda;
                    837: FILE *device;
                    838: {
                    839:     int k;
                    840:
                    841:     fprintf(device, "\n\n\
                    842: Iteration %d\n\
                    843: WSSR        : %-15g   delta(WSSR)/WSSR   : %g\n\
                    844: delta(WSSR) : %-15g   limit for stopping : %g\n\
                    845: lambda   : %g\n\n%s parameter values\n\n",
                    846:       i, chisq, chisq > NEARLY_ZERO ? (chisq - last_chisq) / chisq : 0.0,
                    847:            chisq - last_chisq, epsilon, lambda,
                    848:            (i > 0 ? "resultant" : "initial set of free"));
                    849:     for (k = 0; k < num_params; k++)
                    850:        fprintf(device, "%-15.15s = %g\n", par_name[k], a[k]);
                    851: }
                    852:
                    853:
                    854:
                    855: /*****************************************************************
                    856:     is_empty: check for valid string entries
                    857: *****************************************************************/
                    858: static TBOOLEAN is_empty(s)
                    859: char *s;
                    860: {
                    861:     while (*s == ' ' || *s == '\t' || *s == '\n')
                    862:        s++;
                    863:     return (TBOOLEAN) (*s == '#' || *s == '\0');
                    864: }
                    865:
                    866:
                    867: /*****************************************************************
                    868:     get next word of a multi-word string, advance pointer
                    869: *****************************************************************/
                    870: char *get_next_word(s, subst)
                    871: char **s;
                    872: char *subst;
                    873: {
                    874:     char *tmp = *s;
                    875:
                    876:     while (*tmp == ' ' || *tmp == '\t' || *tmp == '=')
                    877:        tmp++;
                    878:     if (*tmp == '\n' || *tmp == '\0')  /* not found */
                    879:        return NULL;
                    880:     if ((*s = strpbrk(tmp, " =\t\n")) == NULL)
                    881:        *s = tmp + strlen(tmp);
                    882:     *subst = **s;
                    883:     *(*s)++ = '\0';
                    884:     return tmp;
                    885: }
                    886:
                    887:
                    888: /*****************************************************************
                    889:     check for variable identifiers
                    890: *****************************************************************/
                    891: static TBOOLEAN is_variable(s)
                    892: char *s;
                    893: {
                    894:     while (*s != '\0') {
                    895:        if (!isalnum((int) *s) && *s != '_')
                    896:            return FALSE;
                    897:        s++;
                    898:     }
                    899:     return TRUE;
                    900: }
                    901:
                    902: /*****************************************************************
                    903:     first time settings
                    904: *****************************************************************/
                    905: void init_fit()
                    906: {
                    907:     func.at = (struct at_type *) NULL; /* need to parse 1 time */
                    908: }
                    909:
                    910:
                    911: /*****************************************************************
                    912:            Set a GNUPLOT user-defined variable
                    913: ******************************************************************/
                    914:
                    915: void setvar(varname, data)
                    916: char *varname;
                    917: struct value data;
                    918: {
                    919:     register struct udvt_entry *udv_ptr = first_udv, *last = first_udv;
                    920:
                    921:     /* check if it's already in the table... */
                    922:
                    923:     while (udv_ptr) {
                    924:        last = udv_ptr;
                    925:        if (!strcmp(varname, udv_ptr->udv_name))
                    926:            break;
                    927:        udv_ptr = udv_ptr->next_udv;
                    928:     }
                    929:
                    930:     if (!udv_ptr) {            /* generate new entry */
                    931:        last->next_udv = udv_ptr = (struct udvt_entry *)
1.1.1.2   maekawa   932:            gp_alloc(sizeof(struct udvt_entry), "fit setvar");
1.1       maekawa   933:        udv_ptr->next_udv = NULL;
                    934:     }
                    935:     safe_strncpy(udv_ptr->udv_name, varname, sizeof(udv_ptr->udv_name));
                    936:     udv_ptr->udv_value = data;
                    937:     udv_ptr->udv_undef = FALSE;
                    938: }
                    939:
                    940:
                    941:
                    942: /*****************************************************************
                    943:     Read INTGR Variable value, return 0 if undefined or wrong type
                    944: *****************************************************************/
                    945: int getivar(varname)
                    946: char *varname;
                    947: {
                    948:     register struct udvt_entry *udv_ptr = first_udv;
                    949:
                    950:     while (udv_ptr) {
                    951:        if (!strcmp(varname, udv_ptr->udv_name))
                    952:            return udv_ptr->udv_value.type == INTGR
                    953:                ? udv_ptr->udv_value.v.int_val  /* valid */
                    954:                : 0;            /* wrong type */
                    955:        udv_ptr = udv_ptr->next_udv;
                    956:     }
                    957:     return 0;                  /* not in table */
                    958: }
                    959:
                    960:
                    961: /*****************************************************************
                    962:     Read DOUBLE Variable value, return 0 if undefined or wrong type
                    963:    I dont think it's a problem that it's an integer - div
                    964: *****************************************************************/
                    965: static double getdvar(varname)
                    966: char *varname;
                    967: {
                    968:     register struct udvt_entry *udv_ptr = first_udv;
                    969:
                    970:     for (; udv_ptr; udv_ptr = udv_ptr->next_udv)
                    971:        if (strcmp(varname, udv_ptr->udv_name) == 0)
                    972:            return real(&(udv_ptr->udv_value));
                    973:
                    974:     /* get here => not found */
                    975:     return 0;
                    976: }
                    977:
                    978: /*****************************************************************
                    979:    like getdvar, but
                    980:    - convert it from integer to real if necessary
                    981:    - create it with value INITIAL_VALUE if not found or undefined
                    982: *****************************************************************/
                    983: static double createdvar(varname, value)
                    984: char *varname;
                    985: double value;
                    986: {
                    987:     register struct udvt_entry *udv_ptr = first_udv;
                    988:
                    989:     for (; udv_ptr; udv_ptr = udv_ptr->next_udv)
                    990:        if (strcmp(varname, udv_ptr->udv_name) == 0) {
                    991:            if (udv_ptr->udv_undef) {
                    992:                udv_ptr->udv_undef = 0;
                    993:                (void) Gcomplex(&udv_ptr->udv_value, value, 0.0);
                    994:            } else if (udv_ptr->udv_value.type == INTGR) {
                    995:                (void) Gcomplex(&udv_ptr->udv_value, (double) udv_ptr->udv_value.v.int_val, 0.0);
                    996:            }
                    997:            return real(&(udv_ptr->udv_value));
                    998:        }
                    999:     /* get here => not found */
                   1000:
                   1001:     {
                   1002:        struct value tempval;
                   1003:        (void) Gcomplex(&tempval, value, 0.0);
                   1004:        setvar(varname, tempval);
                   1005:     }
                   1006:
                   1007:     return value;
                   1008: }
                   1009:
                   1010:
                   1011: /*****************************************************************
                   1012:     Split Identifier into path and filename
                   1013: *****************************************************************/
                   1014: static void splitpath(s, p, f)
                   1015: char *s;
                   1016: char *p;
                   1017: char *f;
                   1018: {
                   1019:     register char *tmp;
                   1020:     tmp = s + strlen(s) - 1;
                   1021:     while (*tmp != '\\' && *tmp != '/' && *tmp != ':' && tmp - s >= 0)
                   1022:        tmp--;
                   1023:     strcpy(f, tmp + 1);
                   1024:     safe_strncpy(p, s, (size_t) (tmp - s + 1));
                   1025:     p[tmp - s + 1] = NUL;
                   1026: }
                   1027:
                   1028:
                   1029: /*****************************************************************
                   1030:     write the actual parameters to start parameter file
                   1031: *****************************************************************/
                   1032: void update(pfile, npfile)
                   1033: char *pfile, *npfile;
                   1034: {
                   1035:     char fnam[256], path[256], sstr[256], pname[64], tail[127], *s = sstr,
                   1036:     *tmp, c;
                   1037:     char ifilename[256], *ofilename;
                   1038:     FILE *of, *nf;
                   1039:     double pval;
                   1040:
                   1041:
                   1042:     /* update pfile npfile:
                   1043:        if npfile is a valid file name,
                   1044:        take pfile as input file and
                   1045:        npfile as output file
                   1046:      */
                   1047:     if (VALID_FILENAME(npfile)) {
                   1048:        safe_strncpy(ifilename, pfile, sizeof(ifilename));
                   1049:        ofilename = npfile;
                   1050:     } else {
                   1051: #ifdef BACKUP_FILESYSTEM
                   1052:        /* filesystem will keep original as previous version */
                   1053:        safe_strncpy(ifilename, pfile, sizeof(ifilename));
                   1054: #else
                   1055:        backup_file(ifilename, pfile);  /* will Eex if it fails */
                   1056: #endif
                   1057:        ofilename = pfile;
                   1058:     }
                   1059:
                   1060:     /* split into path and filename */
                   1061:     splitpath(ifilename, path, fnam);
                   1062:     if (!(of = fopen(ifilename, "r")))
                   1063:        Eex2("parameter file %s could not be read", ifilename);
                   1064:
                   1065:     if (!(nf = fopen(ofilename, "w")))
                   1066:        Eex2("new parameter file %s could not be created", ofilename);
                   1067:
                   1068:     while (fgets(s = sstr, sizeof(sstr), of) != NULL) {
                   1069:
                   1070:        if (is_empty(s)) {
                   1071:            fputs(s, nf);       /* preserve comments */
                   1072:            continue;
                   1073:        }
                   1074:        if ((tmp = strchr(s, '#')) != NULL) {
                   1075:            safe_strncpy(tail, tmp, sizeof(tail));
                   1076:            *tmp = NUL;
                   1077:        } else
                   1078:            strcpy(tail, "\n");
                   1079:
                   1080:        tmp = get_next_word(&s, &c);
                   1081:        if (!is_variable(tmp) || strlen(tmp) > MAX_ID_LEN) {
                   1082:            (void) fclose(nf);
                   1083:            (void) fclose(of);
                   1084:            Eex2("syntax error in parameter file %s", fnam);
                   1085:        }
                   1086:        safe_strncpy(pname, tmp, sizeof(pname));
                   1087:        /* next must be '=' */
                   1088:        if (c != '=') {
                   1089:            tmp = strchr(s, '=');
                   1090:            if (tmp == NULL) {
                   1091:                (void) fclose(nf);
                   1092:                (void) fclose(of);
                   1093:                Eex2("syntax error in parameter file %s", fnam);
                   1094:            }
                   1095:            s = tmp + 1;
                   1096:        }
                   1097:        tmp = get_next_word(&s, &c);
                   1098:        if (!sscanf(tmp, "%lf", &pval)) {
                   1099:            (void) fclose(nf);
                   1100:            (void) fclose(of);
                   1101:            Eex2("syntax error in parameter file %s", fnam);
                   1102:        }
                   1103:        if ((tmp = get_next_word(&s, &c)) != NULL) {
                   1104:            (void) fclose(nf);
                   1105:            (void) fclose(of);
                   1106:            Eex2("syntax error in parameter file %s", fnam);
                   1107:        }
                   1108:        /* now modify */
                   1109:
                   1110:        if ((pval = getdvar(pname)) == 0)
                   1111:            pval = (double) getivar(pname);
                   1112:
                   1113:        sprintf(sstr, "%g", pval);
                   1114:        if (!strchr(sstr, '.') && !strchr(sstr, 'e'))
                   1115:            strcat(sstr, ".0"); /* assure CMPLX-type */
                   1116:
                   1117:        fprintf(nf, "%-15.15s = %-15.15s   %s", pname, sstr, tail);
                   1118:     }
                   1119:
                   1120:     if (fclose(nf) || fclose(of))
                   1121:        Eex("I/O error during update");
                   1122:
                   1123: }
                   1124:
                   1125:
                   1126: /*****************************************************************
                   1127:     Backup a file by renaming it to something useful. Return
                   1128:     the new name in tofile
                   1129: *****************************************************************/
                   1130: static void backup_file(tofile, fromfile)
                   1131: char *tofile;
                   1132: const char *fromfile;
                   1133: /* tofile must point to a char array[] or allocated data. See update() */
                   1134: {
                   1135: #if defined (WIN32) || defined(MSDOS) || defined(VMS)
                   1136:     char *tmpn;
                   1137: #endif
                   1138:
                   1139:     /* win32 needs to have two attempts at the rename, since it may
                   1140:      * be running on win32s with msdos 8.3 names
                   1141:      */
                   1142:
                   1143: /* first attempt, for all o/s other than MSDOS */
                   1144:
                   1145: #ifndef MSDOS
                   1146:
                   1147:     strcpy(tofile, fromfile);
                   1148:
                   1149: #ifdef VMS
                   1150:     /* replace all dots with _, since we will be adding the only
                   1151:      * dot allowed in VMS names
                   1152:      */
                   1153:     while ((tmpn = strchr(tofile, '.')) != NULL)
                   1154:        *tmpn = '_';
                   1155: #endif /*VMS */
                   1156:
                   1157:     strcat(tofile, BACKUP_SUFFIX);
                   1158:
                   1159:     if (rename(fromfile, tofile) == 0)
                   1160:        return;                 /* hurrah */
                   1161: #endif
                   1162:
                   1163:
                   1164: #if defined (WIN32) || defined(MSDOS)
                   1165:
                   1166:     /* first attempt for msdos. Second attempt for win32s */
                   1167:
                   1168:     /* beware : strncpy is very dangerous since it does not guarantee
                   1169:      * to terminate the string. Copy up to 8 characters. If exactly
                   1170:      * chars were copied, the string is not terminated. If the
                   1171:      * source string was shorter than 8 chars, no harm is done
                   1172:      * (here) by writing to offset 8.
                   1173:      */
                   1174:     safe_strncpy(tofile, fromfile, 8);
                   1175:     /* tofile[8] = NUL; */
                   1176:
                   1177:     while ((tmpn = strchr(tofile, '.')) != NULL)
                   1178:        *tmpn = '_';
                   1179:
                   1180:     strcat(tofile, BACKUP_SUFFIX);
                   1181:
                   1182:     if (rename(fromfile, tofile) == 0)
                   1183:        return;                 /* success */
                   1184:
                   1185: #endif /* win32 || msdos */
                   1186:
                   1187:     /* get here => rename failed. */
                   1188:     Eex3("Could not rename file %s to %s", fromfile, tofile);
                   1189: }
                   1190:
                   1191:
                   1192: /*****************************************************************
                   1193:     Interface to the classic gnuplot-software
                   1194: *****************************************************************/
                   1195:
                   1196: void do_fit()
                   1197: {
                   1198:     TBOOLEAN autorange_x = 3, autorange_y = 3; /* yes */
                   1199:     /* HBB 980401: new: z range specification */
                   1200:     TBOOLEAN autorange_z = 3;
                   1201:     double min_x, max_x;       /* range to fit */
                   1202:     double min_y, max_y;       /* range to fit */
                   1203:     /* HBB 980401: new: z range specification */
                   1204:     double min_z, max_z;       /* range to fit */
                   1205:     int dummy_x = -1, dummy_y = -1;    /* eg  fit [u=...] [v=...] */
                   1206:     /* HBB 981210: memorize position of possible third [ : ] spec: */
                   1207:     int zrange_token = -1;
                   1208:
                   1209:     int i;
                   1210:     double v[4];
                   1211:     double tmpd;
                   1212:     time_t timer;
                   1213:     int token1, token2, token3;
                   1214:     char *tmp;
                   1215:
                   1216:     /* first look for a restricted x fit range... */
                   1217:
                   1218:     if (equals(c_token, "[")) {
                   1219:        c_token++;
                   1220:        if (isletter(c_token)) {
                   1221:            if (equals(c_token + 1, "=")) {
                   1222:                dummy_x = c_token;
                   1223:                c_token += 2;
                   1224:            }
                   1225:            /* else parse it as a xmin expression */
                   1226:        }
                   1227:        autorange_x = load_range(FIRST_X_AXIS, &min_x, &max_x, autorange_x);
                   1228:        if (!equals(c_token, "]"))
                   1229:            int_error("']' expected", c_token);
                   1230:        c_token++;
                   1231:     }
                   1232:     /* ... and y */
                   1233:
                   1234:     if (equals(c_token, "[")) {
                   1235:        c_token++;
                   1236:        if (isletter(c_token)) {
                   1237:            if (equals(c_token + 1, "=")) {
                   1238:                dummy_y = c_token;
                   1239:                c_token += 2;
                   1240:            }
                   1241:            /* else parse it as a ymin expression */
                   1242:        }
                   1243:        autorange_y = load_range(FIRST_Y_AXIS, &min_y, &max_y, autorange_y);
                   1244:        if (!equals(c_token, "]"))
                   1245:            int_error("']' expected", c_token);
                   1246:        c_token++;
                   1247:     }
                   1248:     /* HBB 980401: new: allow restricting the z range as well */
                   1249:     /* ... and z */
                   1250:
                   1251:     if (equals(c_token, "[")) {
                   1252:        zrange_token = c_token++;
                   1253:        if (isletter(c_token))
                   1254:            /* do *not* allow the z range being given with a variable name */
                   1255:            int_error("Can't re-name dependent variable", c_token);
                   1256:        autorange_z = load_range(FIRST_Z_AXIS, &min_z, &max_z, autorange_z);
                   1257:        if (!equals(c_token, "]"))
                   1258:            int_error("']' expected", c_token);
                   1259:        c_token++;
                   1260: #if 0 /* HBB 981210: move this to a later point */
                   1261:     } else {
                   1262:        /* Just in case I muck up things below: make sure that the z
                   1263:         * range is the same as the y range, if it didn't get specified
                   1264:         */
                   1265:        autorange_z = autorange_y;
                   1266:        min_z = min_y;
                   1267:        max_z = max_y;
                   1268: #endif
                   1269:     }
                   1270:
                   1271:
                   1272:     /* now compile the function */
                   1273:
                   1274:     token1 = c_token;
                   1275:
                   1276:     if (func.at) {
                   1277:        free(func.at);
                   1278:        func.at = NULL;         /* in case perm_at() does int_error */
                   1279:     }
                   1280:     dummy_func = &func;
                   1281:
                   1282:
                   1283:     /* set the dummy variable names */
                   1284:
                   1285:     if (dummy_x >= 0)
                   1286:        copy_str(c_dummy_var[0], dummy_x, MAX_ID_LEN);
                   1287:     else
                   1288:        strcpy(c_dummy_var[0], dummy_var[0]);
                   1289:
                   1290:     if (dummy_y >= 0)
                   1291:        copy_str(c_dummy_var[0], dummy_y, MAX_ID_LEN);
                   1292:     else
                   1293:        strcpy(c_dummy_var[1], dummy_var[1]);
                   1294:
                   1295:     func.at = perm_at();
                   1296:     dummy_func = NULL;
                   1297:
                   1298:     token2 = c_token;
                   1299:
                   1300:     /* use datafile module to parse the datafile and qualifiers */
                   1301:
                   1302:     columns = df_open(4);      /* up to 4 using specs allowed */
                   1303:     if (columns == 1)
                   1304:        int_error("Need 2 to 4 using specs", c_token);
                   1305:
1.1.1.2   maekawa  1306:     /* The following patch was made by Remko Scharroo, 25-Mar-1999
                   1307:      * We need to check if one of the columns is time data, like
                   1308:      * in plot2d and plot3d */
                   1309:
                   1310:     if (datatype[FIRST_X_AXIS] == TIME) {
                   1311:        if (columns < 2)
                   1312:            int_error("Need full using spec for x time data", c_token);
                   1313:        df_timecol[0] = 1;
                   1314:     }
                   1315:     if (datatype[FIRST_Y_AXIS] == TIME) {
                   1316:        if (columns < 1)
                   1317:            int_error("Need using spec for y time data", c_token);
                   1318:        df_timecol[1] = 1;
                   1319:     }
                   1320:     /* HBB 990326: added this check. Just in case some wants to fit
                   1321:      * time/date data depending on two other variables ... */
                   1322:     if (datatype[FIRST_Z_AXIS] == TIME) {
                   1323:        if (columns < 4)
                   1324:            int_error("Need full using spec for z time data", c_token);
                   1325:        else
                   1326:            df_timecol[2] = 1;
                   1327:     }
                   1328:     /* End of patch by Remko Scharroo */
                   1329:
1.1       maekawa  1330:     /* HBB 980401: if this is a single-variable fit, we shouldn't have
                   1331:      * allowed a variable name specifier for 'y': */
                   1332:     if ((dummy_y >= 0) && (columns < 4))
                   1333:        int_error("Can't re-name 'y' in a one-variable fit", dummy_y);
                   1334:
                   1335:     /* HBB 981210: two range specs mean different things, depending
                   1336:      * on wether this is a 2D or 3D fit */
1.1.1.2   maekawa  1337:     if (columns < 4) {
                   1338:        if (zrange_token != -1)
                   1339:            int_error("Three range-specs not allowed in on-variable fit", zrange_token);
                   1340:        else {
                   1341:            /* 2D fit, 2 ranges: second range is for *z*, not y: */
                   1342:            autorange_z = autorange_y;
1.1.1.3 ! ohara    1343:            /* HBB 20010926: Bug fixed. Checks were the wrong way round */
        !          1344:            if (! (autorange_y & 1))
1.1.1.2   maekawa  1345:                min_z = min_y;
1.1.1.3 ! ohara    1346:            if (! (autorange_y & 2))
1.1.1.2   maekawa  1347:                max_z = max_y;
                   1348:        }
1.1       maekawa  1349:     }
                   1350:
                   1351:     /* defer actually reading the data until we have parsed the rest
                   1352:      * of the line */
                   1353:
                   1354:     token3 = c_token;
                   1355:
                   1356:     tmpd = getdvar(FITLIMIT);  /* get epsilon if given explicitly */
                   1357:     if (tmpd < 1.0 && tmpd > 0.0)
                   1358:        epsilon = tmpd;
                   1359:
                   1360:     /* HBB 970304: maxiter patch */
                   1361:     maxiter = getivar(FITMAXITER);
                   1362:
                   1363:     /* get startup value for lambda, if given */
                   1364:     tmpd = getdvar(FITSTARTLAMBDA);
                   1365:
                   1366:     if (tmpd > 0.0) {
                   1367:        startup_lambda = tmpd;
                   1368:        printf("Lambda Start value set: %g\n", startup_lambda);
                   1369:     }
                   1370:
                   1371:     /* get lambda up/down factor, if given */
                   1372:     tmpd = getdvar(FITLAMBDAFACTOR);
                   1373:
                   1374:     if (tmpd > 0.0) {
                   1375:        lambda_up_factor = lambda_down_factor = tmpd;
                   1376:        printf("Lambda scaling factors reset:  %g\n", lambda_up_factor);
                   1377:     }
                   1378:     *fit_script = NUL;
                   1379:     if ((tmp = getenv(FITSCRIPT)) != NULL)
                   1380:        strcpy(fit_script, tmp);
                   1381:
                   1382:     tmp = getenv(GNUFITLOG);   /* open logfile */
                   1383:     if (tmp != NULL) {
                   1384:        char *tmp2 = &tmp[strlen(tmp) - 1];
                   1385:        if (*tmp2 == '/' || *tmp2 == '\\')
                   1386:            sprintf(logfile, "%s%s", tmp, logfile);
                   1387:        else
                   1388:            strcpy(logfile, tmp);
                   1389:     }
                   1390:     if (!log_f && /* div */ !(log_f = fopen(logfile, "a")))
                   1391:        Eex2("could not open log-file %s", logfile);
                   1392:     fputs("\n\n*******************************************************************************\n", log_f);
                   1393:     (void) time(&timer);
                   1394:     fprintf(log_f, "%s\n\n", ctime(&timer));
                   1395:     {
                   1396:        char *line = NULL;
                   1397:
                   1398:        m_capture(&line, token2, token3 - 1);
                   1399:        fprintf(log_f, "FIT:    data read from %s\n", line);
                   1400:        free(line);
                   1401:     }
                   1402:
                   1403:     max_data = MAX_DATA;
                   1404:     fit_x = vec(max_data);     /* start with max. value */
                   1405:     fit_y = vec(max_data);
                   1406:     fit_z = vec(max_data);
                   1407:
                   1408:     /* first read in experimental data */
                   1409:
                   1410:     err_data = vec(max_data);
                   1411:     num_data = 0;
                   1412:
                   1413:     while ((i = df_readline(v, 4)) != EOF) {
                   1414:        if (num_data >= max_data) {
                   1415:            /* increase max_data by factor of 1.5 */
                   1416:            max_data = (max_data * 3) / 2;
                   1417:            if (0
                   1418:                || !redim_vec(&fit_x, max_data)
                   1419:                || !redim_vec(&fit_y, max_data)
                   1420:                || !redim_vec(&fit_z, max_data)
                   1421:                || !redim_vec(&err_data, max_data)
                   1422:                ) {
                   1423:                /* Some of the reallocations went bad: */
                   1424:                df_close();
                   1425:                Eex2("Out of memory in fit: too many datapoints (%d)?", max_data);
                   1426:            } else {
                   1427:                /* Just so we know that the routine is at work: */
                   1428:                fprintf(STANDARD, "Max. number of data points scaled up to: %d\n",
                   1429:                        max_data);
                   1430:            }
                   1431:        }
                   1432:        switch (i) {
                   1433:        case DF_UNDEFINED:
                   1434:        case DF_FIRST_BLANK:
                   1435:        case DF_SECOND_BLANK:
                   1436:            continue;
                   1437:        case 0:
                   1438:            Eex2("bad data on line %d of datafile", df_line_number);
                   1439:            break;
                   1440:        case 1:         /* only z provided */
                   1441:            v[2] = v[0];
                   1442:            v[0] = (double) df_datum;
                   1443:            break;
                   1444:        case 2:         /* x and z */
                   1445:            v[2] = v[1];
                   1446:            break;
                   1447:
                   1448:            /* only if the explicitly asked for 4 columns do we
                   1449:             * do a 3d fit. (We can get here if they didn't
                   1450:             * specify a using spec, and the file has 4 columns
                   1451:             */
                   1452:        case 4:         /* x, y, z, error */
                   1453:            if (columns == 4)
                   1454:                break;
                   1455:            /* else fall through */
                   1456:        case 3:         /* x, z, error */
                   1457:            v[3] = v[2];        /* error */
                   1458:            v[2] = v[1];        /* z */
                   1459:            break;
                   1460:
                   1461:        }
                   1462:
                   1463:        /* skip this point if it is out of range */
                   1464:        if (!(autorange_x & 1) && (v[0] < min_x))
                   1465:            continue;
                   1466:        if (!(autorange_x & 2) && (v[0] > max_x))
                   1467:            continue;
                   1468:        /* HBB 980401: yrange is only relevant for 3d-fits! */
                   1469:        if (columns == 4) {
                   1470:            if (!(autorange_y & 1) && (v[1] < min_y))
                   1471:                continue;
                   1472:            if (!(autorange_y & 2) && (v[1] > max_y))
                   1473:                continue;
                   1474:        }
                   1475:        /* HBB 980401: check *z* range for all fits */
                   1476:        if (!(autorange_z & 1) && (v[2] < min_z))
                   1477:            continue;
                   1478:        if (!(autorange_z & 2) && (v[2] > max_z))
                   1479:            continue;
                   1480:
                   1481:        fit_x[num_data] = v[0];
                   1482:        fit_y[num_data] = v[1];
                   1483:        fit_z[num_data] = v[2];
                   1484:
                   1485:        /* we only use error if _explicitly_ asked for by a
                   1486:         * using spec
                   1487:         */
                   1488:        err_data[num_data++] = (columns > 2) ? v[3] : 1;
                   1489:     }
                   1490:     df_close();
                   1491:
                   1492:     if (num_data <= 1)
                   1493:        Eex("No data to fit ");
                   1494:
                   1495:     /* now resize fields to actual length: */
                   1496:     redim_vec(&fit_x, num_data);
                   1497:     redim_vec(&fit_y, num_data);
                   1498:     redim_vec(&fit_z, num_data);
                   1499:     redim_vec(&err_data, num_data);
                   1500:
                   1501:     fprintf(log_f, "        #datapoints = %d\n", num_data);
                   1502:
                   1503:     if (columns < 3)
                   1504:        fputs("        residuals are weighted equally (unit weight)\n\n", log_f);
                   1505:
                   1506:     {
                   1507:        char *line = NULL;
                   1508:
                   1509:        m_capture(&line, token1, token2 - 1);
                   1510:        fprintf(log_f, "function used for fitting: %s\n", line);
                   1511:        free(line);
                   1512:     }
                   1513:
                   1514:     /* read in parameters */
                   1515:
                   1516:     max_params = MAX_PARAMS;   /* HBB 971023: make this resizeable */
                   1517:
                   1518:     if (!equals(c_token, "via"))
                   1519:        int_error("Need via and either parameter list or file", c_token);
                   1520:
                   1521:     a = vec(max_params);
                   1522:     par_name = (fixstr *) gp_alloc((max_params + 1) * sizeof(fixstr), "fit param");
                   1523:     num_params = 0;
                   1524:
                   1525:     if (isstring(++c_token)) { /* It's a parameter *file* */
                   1526:        TBOOLEAN fixed;
                   1527:        double tmp_par;
                   1528:        char c, *s;
1.1.1.2   maekawa  1529:        char sstr[MAX_LINE_LEN+1];
1.1       maekawa  1530:        FILE *f;
                   1531:
                   1532:        quote_str(sstr, c_token++, MAX_LINE_LEN);
                   1533:
                   1534:        /* get parameters and values out of file and ignore fixed ones */
                   1535:
                   1536:        fprintf(log_f, "fitted parameters and initial values from file: %s\n\n", sstr);
                   1537:        if (!(f = fopen(sstr, "r")))
                   1538:            Eex2("could not read parameter-file %s", sstr);
                   1539:        while (TRUE) {
                   1540:            if (!fgets(s = sstr, (int) sizeof(sstr), f))        /* EOF found */
                   1541:                break;
                   1542:            if ((tmp = strstr(s, FIXED)) != NULL) {     /* ignore fixed params */
                   1543:                *tmp = NUL;
                   1544:                fprintf(log_f, "FIXED:  %s\n", s);
                   1545:                fixed = TRUE;
                   1546:            } else
                   1547:                fixed = FALSE;
                   1548:            if ((tmp = strchr(s, '#')) != NULL)
                   1549:                *tmp = NUL;
                   1550:            if (is_empty(s))
                   1551:                continue;
                   1552:            tmp = get_next_word(&s, &c);
                   1553:            if (!is_variable(tmp) || strlen(tmp) > MAX_ID_LEN) {
                   1554:                (void) fclose(f);
                   1555:                Eex("syntax error in parameter file");
                   1556:            }
                   1557:            safe_strncpy(par_name[num_params], tmp, sizeof(fixstr));
                   1558:            /* next must be '=' */
                   1559:            if (c != '=') {
                   1560:                tmp = strchr(s, '=');
                   1561:                if (tmp == NULL) {
                   1562:                    (void) fclose(f);
                   1563:                    Eex("syntax error in parameter file");
                   1564:                }
                   1565:                s = tmp + 1;
                   1566:            }
                   1567:            tmp = get_next_word(&s, &c);
                   1568:            if (sscanf(tmp, "%lf", &tmp_par) != 1) {
                   1569:                (void) fclose(f);
                   1570:                Eex("syntax error in parameter file");
                   1571:            }
                   1572:            /* make fixed params visible to GNUPLOT */
                   1573:            if (fixed) {
                   1574:                struct value tempval;
                   1575:                (void) Gcomplex(&tempval, tmp_par, 0.0);
                   1576:                /* use parname as temp */
                   1577:                setvar(par_name[num_params], tempval);
                   1578:            } else {
                   1579:                if (num_params >= max_params) {
                   1580:                    max_params = (max_params * 3) / 2;
                   1581:                    if (0
                   1582:                        || !redim_vec(&a, max_params)
                   1583:                        || !(par_name = gp_realloc(par_name, (max_params + 1) * sizeof(fixstr), "fit param resize"))
                   1584:                        ) {
                   1585:                        (void) fclose(f);
                   1586:                        Eex("Out of memory in fit: too many parameters?");
                   1587:                    }
                   1588:                }
                   1589:                a[num_params++] = tmp_par;
                   1590:            }
                   1591:
                   1592:            if ((tmp = get_next_word(&s, &c)) != NULL) {
                   1593:                (void) fclose(f);
                   1594:                Eex("syntax error in parameter file");
                   1595:            }
                   1596:        }
                   1597:        (void) fclose(f);
                   1598:
                   1599:     } else {
                   1600:        /* not a string after via: it's a variable listing */
                   1601:
                   1602:        fputs("fitted parameters initialized with current variable values\n\n", log_f);
                   1603:        do {
                   1604:            if (!isletter(c_token))
                   1605:                Eex("no parameter specified");
                   1606:            capture(par_name[num_params], c_token, c_token, (int) sizeof(par_name[0]));
                   1607:            if (num_params >= max_params) {
                   1608:                max_params = (max_params * 3) / 2;
                   1609:                if (0
                   1610:                    || !redim_vec(&a, max_params)
                   1611:                    || !(par_name = gp_realloc(par_name, (max_params + 1) * sizeof(fixstr), "fit param resize"))
                   1612:                    ) {
                   1613:                    Eex("Out of memory in fit: too many parameters?");
                   1614:                }
                   1615:            }
                   1616:            /* create variable if it doesn't exist */
                   1617:            a[num_params] = createdvar(par_name[num_params], INITIAL_VALUE);
                   1618:            ++num_params;
                   1619:        } while (equals(++c_token, ",") && ++c_token);
                   1620:     }
                   1621:
                   1622:     redim_vec(&a, num_params);
                   1623:     par_name = (fixstr *) gp_realloc(par_name, (num_params + 1) * sizeof(fixstr), "fit param");
                   1624:
                   1625:     if (num_data < num_params)
                   1626:        Eex("Number of data points smaller than number of parameters");
                   1627:
                   1628:     /* avoid parameters being equal to zero */
                   1629:     for (i = 0; i < num_params; i++)
                   1630:        if (a[i] == 0)
                   1631:            a[i] = NEARLY_ZERO;
                   1632:
                   1633:     (void) regress(a);
                   1634:
                   1635:     (void) fclose(log_f);
                   1636:     log_f = NULL;
                   1637:     free(fit_x);
                   1638:     free(fit_y);
                   1639:     free(fit_z);
                   1640:     free(err_data);
                   1641:     free(a);
                   1642:     free(par_name);
                   1643:     if (func.at) {
                   1644:        free(func.at);          /* release perm. action table */
                   1645:        func.at = (struct at_type *) NULL;
                   1646:     }
                   1647:     safe_strncpy(last_fit_command, input_line, sizeof(last_fit_command));
                   1648: }
                   1649:
                   1650: #if defined(ATARI) || defined(MTOS)
                   1651: static int kbhit()
                   1652: {
                   1653:     fd_set rfds;
                   1654:     struct timeval timeout;
                   1655:
                   1656:     timeout.tv_sec = 0;
                   1657:     timeout.tv_usec = 0;
                   1658:     rfds = (fd_set) (1L << fileno(stdin));
                   1659:     return ((select(0, &rfds, NULL, NULL, &timeout) > 0) ? 1 : 0);
                   1660: }
                   1661: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>