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

Annotation of OpenXM_contrib/gnuplot/matrix.c, Revision 1.1

1.1     ! maekawa     1: #ifndef lint
        !             2: static char *RCSid = "$Id: matrix.c,v 1.15 1998/04/14 00:16:01 drd Exp $";
        !             3: #endif
        !             4:
        !             5: /*
        !             6:  *     Matrix algebra, part of
        !             7:  *
        !             8:  *     Nonlinear least squares fit according to the
        !             9:  *     Marquardt-Levenberg-algorithm
        !            10:  *
        !            11:  *     added as Patch to Gnuplot (v3.2 and higher)
        !            12:  *     by Carsten Grammes
        !            13:  *     Experimental Physics, University of Saarbruecken, Germany
        !            14:  *
        !            15:  *     Internet address: cagr@rz.uni-sb.de
        !            16:  *
        !            17:  *     Copyright of this module:   Carsten Grammes, 1993
        !            18:  *
        !            19:  *     Permission to use, copy, and distribute this software and its
        !            20:  *     documentation for any purpose with or without fee is hereby granted,
        !            21:  *     provided that the above copyright notice appear in all copies and
        !            22:  *     that both that copyright notice and this permission notice appear
        !            23:  *     in supporting documentation.
        !            24:  *
        !            25:  *     This software is provided "as is" without express or implied warranty.
        !            26:  */
        !            27:
        !            28:
        !            29: #include "fit.h"
        !            30: #include "matrix.h"
        !            31: #include "stdfn.h"
        !            32: #include "alloc.h"
        !            33:
        !            34: /*****************************************************************/
        !            35:
        !            36: #define Swap(a,b)   {double temp = (a); (a) = (b); (b) = temp;}
        !            37: #define WINZIG       1e-30
        !            38:
        !            39:
        !            40: /*****************************************************************
        !            41:     internal prototypes
        !            42: *****************************************************************/
        !            43:
        !            44: static GP_INLINE int fsign __PROTO((double x));
        !            45:
        !            46: /*****************************************************************
        !            47:     first straightforward vector and matrix allocation functions
        !            48: *****************************************************************/
        !            49: double *vec (n)
        !            50: int n;
        !            51: {
        !            52:     /* allocates a double vector with n elements */
        !            53:     double *dp;
        !            54:     if( n < 1 )
        !            55:        return (double *) NULL;
        !            56:     dp = (double *) gp_alloc ( n * sizeof(double), "vec");
        !            57:     return dp;
        !            58: }
        !            59:
        !            60:
        !            61: double **matr (rows, cols)
        !            62: int rows;
        !            63: int cols;
        !            64: {
        !            65:     /* allocates a double matrix */
        !            66:
        !            67:     register int i;
        !            68:     register double **m;
        !            69:
        !            70:     if ( rows < 1  ||  cols < 1 )
        !            71:         return NULL;
        !            72:     m = (double **) gp_alloc ( rows * sizeof(double *) , "matrix row pointers");
        !            73:     m[0] = (double *) gp_alloc ( rows * cols * sizeof(double), "matrix elements");
        !            74:     for ( i = 1; i<rows ; i++ )
        !            75:        m[i] = m[i-1] + cols;
        !            76:     return m;
        !            77: }
        !            78:
        !            79:
        !            80: void free_matr (m)
        !            81: double **m;
        !            82: {
        !            83:     free (m[0]);
        !            84:     free (m);
        !            85: }
        !            86:
        !            87:
        !            88: double *redim_vec (v, n)
        !            89: double **v;
        !            90: int n;
        !            91: {
        !            92:     if ( n < 1 )
        !            93:       *v = NULL;
        !            94:     else
        !            95:       *v = (double *) gp_realloc (*v, n * sizeof(double), "vec");
        !            96:     return *v;
        !            97: }
        !            98:
        !            99: void redim_ivec (v, n)
        !           100: int **v;
        !           101: int n;
        !           102: {
        !           103:     if ( n < 1 ) {
        !           104:        *v = NULL;
        !           105:        return;
        !           106:     }
        !           107:     *v = (int *) gp_realloc (*v, n * sizeof(int), "ivec");
        !           108: }
        !           109:
        !           110:
        !           111: /* HBB: TODO: is there a better value for 'epsilon'? how to specify
        !           112:  * 'inline'?  is 'fsign' really not available elsewhere? use
        !           113:  * row-oriented version (p. 309) instead?
        !           114:  */
        !           115:
        !           116: static GP_INLINE int fsign(x)
        !           117:   double x;
        !           118: {
        !           119:     return( x>0 ? 1 : (x < 0) ? -1 : 0) ;
        !           120: }
        !           121:
        !           122: /*****************************************************************
        !           123:
        !           124:      Solve least squares Problem C*x+d = r, |r| = min!, by Given rotations
        !           125:      (QR-decomposition). Direct implementation of the algorithm
        !           126:      presented in H.R.Schwarz: Numerische Mathematik, 'equation'
        !           127:      number (7.33)
        !           128:
        !           129:      If 'd == NULL', d is not accesed: the routine just computes the QR
        !           130:      decomposition of C and exits.
        !           131:
        !           132:      If 'want_r == 0', r is not rotated back (\hat{r} is returned
        !           133:      instead).
        !           134:
        !           135: *****************************************************************/
        !           136:
        !           137: void Givens (C, d, x, r, N, n, want_r)
        !           138: double **C;
        !           139: double *d;
        !           140: double *x;
        !           141: double *r;
        !           142: int N;
        !           143: int n;
        !           144: int want_r;
        !           145: {
        !           146:     int i, j, k;
        !           147:     double w, gamma, sigma, rho, temp;
        !           148:     double epsilon = DBL_EPSILON; /* FIXME (?)*/
        !           149:
        !           150: /*
        !           151:  * First, construct QR decomposition of C, by 'rotating away'
        !           152:  * all elements of C below the diagonal. The rotations are
        !           153:  * stored in place as Givens coefficients rho.
        !           154:  * Vector d is also rotated in this same turn, if it exists
        !           155:  */
        !           156:     for (j = 0; j<n; j++)
        !           157:        for (i = j+1; i<N; i++)
        !           158:            if (C[i][j]) {
        !           159:                if (fabs(C[j][j])<epsilon*fabs(C[i][j])) { /* find the rotation parameters */
        !           160:                    w = -C[i][j];
        !           161:                    gamma = 0;
        !           162:                    sigma = 1;
        !           163:                    rho = 1;
        !           164:                } else {
        !           165:                    w = fsign(C[j][j])*sqrt(C[j][j]*C[j][j] + C[i][j]*C[i][j]);
        !           166:                    if (w == 0)
        !           167:                        Eex3 ( "w = 0 in Givens();  Cjj = %g,  Cij = %g", C[j][j], C[i][j]);
        !           168:                    gamma = C[j][j]/w;
        !           169:                    sigma = -C[i][j]/w;
        !           170:                    rho = (fabs(sigma)<gamma) ? sigma : fsign(sigma)/gamma;
        !           171:                }
        !           172:                C[j][j] = w;
        !           173:                C[i][j] = rho;           /* store rho in place, for later use */
        !           174:                for (k = j+1; k<n; k++) {   /* rotation on index pair (i,j) */
        !           175:                    temp =    gamma*C[j][k] - sigma*C[i][k];
        !           176:                    C[i][k] = sigma*C[j][k] + gamma*C[i][k];
        !           177:                    C[j][k] = temp;
        !           178:
        !           179:                }
        !           180:                if (d) {               /* if no d vector given, don't use it */
        !           181:                    temp = gamma*d[j] - sigma*d[i];  /* rotate d */
        !           182:                    d[i] = sigma*d[j] + gamma*d[i];
        !           183:                    d[j] = temp;
        !           184:                }
        !           185:            }
        !           186:     if (!d)               /* stop here if no d was specified */
        !           187:          return;
        !           188:
        !           189:     for (i = n-1; i >= 0; i--) {   /* solve R*x+d = 0, by backsubstitution */
        !           190:         double s = d[i];
        !           191:         r[i] = 0;              /* ... and also set r[i] = 0 for i<n */
        !           192:         for (k = i+1; k<n; k++)
        !           193:             s += C[i][k]*x[k];
        !           194:        if (C[i][i] == 0)
        !           195:          Eex ( "Singular matrix in Givens()");
        !           196:         x[i] = - s / C[i][i];
        !           197:        }
        !           198:     for (i = n; i < N; i++)
        !           199:        r[i] = d[i];            /* set the other r[i] to d[i] */
        !           200:
        !           201:     if (!want_r)               /* if r isn't needed, stop here */
        !           202:        return;
        !           203:
        !           204:     /* rotate back the r vector */
        !           205:     for (j = n-1; j >= 0; j--)
        !           206:        for (i = N-1; i >= 0; i--) {
        !           207:            if ((rho = C[i][j]) == 1) { /* reconstruct gamma, sigma from stored rho */
        !           208:                gamma = 0;
        !           209:                sigma = 1;
        !           210:            } else if (fabs(rho)<1) {
        !           211:                sigma = rho;
        !           212:                gamma = sqrt(1-sigma*sigma);
        !           213:            } else {
        !           214:                gamma = 1/fabs(rho);
        !           215:                sigma = fsign(rho)*sqrt(1-gamma*gamma);
        !           216:            }
        !           217:            temp = gamma*r[j] + sigma*r[i];     /* rotate back indices (i,j) */
        !           218:            r[i] = -sigma*r[j] + gamma*r[i];
        !           219:            r[j] = temp;
        !           220:     }
        !           221: }
        !           222:
        !           223:
        !           224: /* Given a triangular Matrix R, compute (R^T * R)^(-1), by forward
        !           225:  * then back substitution
        !           226:  *
        !           227:  * R, I are n x n Matrices, I is for the result. Both must already be
        !           228:  * allocated.
        !           229:  *
        !           230:  * Will only calculate the lower triangle of I, as it is symmetric
        !           231:  */
        !           232:
        !           233: void Invert_RtR ( R, I, n)
        !           234: double **R;
        !           235: double **I;
        !           236: int n;
        !           237: {
        !           238:   int i, j, k;
        !           239:
        !           240:   /* fill in the I matrix, and check R for regularity : */
        !           241:
        !           242:   for (i = 0; i<n; i++) {
        !           243:     for (j = 0; j<i; j++)  /* upper triangle isn't needed */
        !           244:       I[i][j] = 0;
        !           245:     I[i][i] = 1;
        !           246:     if (! R[i][i])
        !           247:       Eex ("Singular matrix in Invert_RtR")
        !           248: }
        !           249:
        !           250:   /* Forward substitution: Solve R^T * B = I, store B in place of I */
        !           251:
        !           252:   for (k = 0; k<n; k++)
        !           253:     for (i = k; i<n; i++) {  /* upper half needn't be computed */
        !           254:       double s = I[i][k];
        !           255:       for (j = k; j<i; j++)  /* for j<k, I[j][k] always stays zero! */
        !           256:        s -= R[j][i] * I[j][k];
        !           257:       I[i][k] = s / R[i][i];
        !           258: }
        !           259:
        !           260:   /* Backward substitution: Solve R * A = B, store A in place of B */
        !           261:
        !           262:   for (k = 0; k<n; k++)
        !           263:     for (i = n-1; i >= k; i--) {  /* don't compute upper triangle of A */
        !           264:       double s = I[i][k];
        !           265:       for (j = i+1; j<n; j++)
        !           266:        s -= R[i][j] * I[j][k];
        !           267:       I[i][k] = s / R[i][i];
        !           268:     }
        !           269: }

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