[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.1

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

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