IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Apr 28, 2005, 11:17:02 PM (21 years ago)
Author:
magnier
Message:

checking in the versions of the files below, incorporating the changes
I made and have already submitted to bugzilla. these files should be
replaced with the versions contributed on the main trunk by MHPCC.
I will tag this state with eam-psphot-1

src/astronomy/psMetadata.c src/astronomy/psMetadata.h
src/collections/psVector.c src/collections/psVector.h
src/dataManip/psMinimize.c src/dataManip/psMinimize.h
src/image/psImage.c src/image/psImage.h src/sysUtils/psTrace.c
src/sysUtils/psTrace.h

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/eam-psphot-branch/psLib/src/dataManip/psMinimize.c

    r3578 r3788  
    99 *  @author GLG, MHPCC
    1010 *
    11  *  @version $Revision: 1.110 $ $Name: not supported by cvs2svn $
    12  *  @date $Date: 2005-03-31 01:02:15 $
     11 *  @version $Revision: 1.110.6.1 $ $Name: not supported by cvs2svn $
     12 *  @date $Date: 2005-04-29 09:17:02 $
    1313 *
    1414 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
     
    557557}
    558558
    559 /******************************************************************************
    560 psMinimizeLMChi2():  This routine will take an procedure which calculates
    561 an arbitrary function and it's derivative and minimize the chi-squared match
    562 between that function at the specified coords and the specified value at
    563 those coords.
    564  
    565 XXX: Do this:
    566  After checking that all entries in the paramMask are 1 or 0, when
    567  forming the A matrix from alpha, try this:
    568  
    569      A[i][i] = (1 + lambda*paramask[i]) * alpha[i][i];
    570  
    571 XXX: This is very different from what is specified in the SDR.  Must
    572 coordinate with IfA on new SDR.
    573  
    574 XXX: Do vector/image recycles.
    575  
    576 XXX: probably yErr will be part of the SDR.
    577  
    578 XXX: This must work for both F32 and F64.  F32 is currently implemented.
    579      Note: since the LUD routines are only implemented in F64, then we
    580      will have to convert all F32 input vectors to F64 regardless.  So,
    581      the F64 port might be.
    582  
    583 XXX: Must update the covar matrix.
    584  *****************************************************************************/
     559// XXX EAM this is my re-implementation of MinLM
    585560psBool psMinimizeLMChi2(psMinimization *min,
    586561                        psImage *covar,
     
    601576    PS_PTR_CHECK_NULL(func, NULL);
    602577
     578    // this function has test and current values for several things
     579    // the current best value is in lower case
     580    // the next guess value is in upper case
     581
     582    // allocate internal arrays (current vs Guess)
     583    psImage *alpha   = psImageAlloc (params->n, params->n, PS_TYPE_F64);
     584    psImage *Alpha   = psImageAlloc (params->n, params->n, PS_TYPE_F64);
     585    psVector *beta   = psVectorAlloc (params->n, PS_TYPE_F64);
     586    psVector *Beta   = psVectorAlloc (params->n, PS_TYPE_F64);
     587    psVector *Params = psVectorAlloc (params->n, PS_TYPE_F64);
     588    psVector *dy     = NULL;
     589    psF64 chisq = 0.0;
     590    psF64 Chisq = 0.0;
     591    psF64 lambda = 0.001;
     592
     593    // the initial guess on params is provided by the user
     594    Params = psVectorCopy (Params, params, PS_TYPE_F32);
     595
     596    // the user provides the error or NULL.  we need to convert
     597    // to appropriate weights
     598    dy = psVectorAlloc (y->n, PS_TYPE_F32);
     599    if (yErr != NULL) {
     600        for (int i = 0; i < dy->n; i++) {
     601            dy->data.F32[i] = 1.0 / PS_SQR (yErr->data.F32[i]);
     602        }
     603    } else {
     604        for (int i = 0; i < dy->n; i++) {
     605            dy->data.F32[i] = 1.0;
     606        }
     607    }
     608
     609    // calculate initial alpha and beta, set chisq (min->value)
     610    min->value = p_psMinLM_SetABX (alpha, beta, params, x, y, dy, func);
     611    # ifndef PS_NO_TRACE
     612    // dump some useful info if trace is defined
     613    if (psTraceGetLevel (".psLib.dataManip.psMinimizeLMChi2") > 4) {
     614        p_psImagePrint  (psTraceGetDestination(), alpha, "alpha guess");
     615        p_psVectorPrint (psTraceGetDestination(), beta, "beta guess");
     616        p_psVectorPrint (psTraceGetDestination(), params, "params guess");
     617    }
     618    # endif /* PS_NO_TRACE */
     619
     620
     621    // iterate until the tolerance is reached, or give up
     622    while ((min->lastDelta > min->tol) && (min->iter < min->maxIter)) {
     623
     624        // set a new guess for Alpha, Beta, Params
     625        p_psMinLM_GuessABP (Alpha, Beta, Params, alpha, beta, params, lambda);
     626
     627        # ifndef PS_NO_TRACE
     628        // dump some useful info if trace is defined
     629        if (psTraceGetLevel (".psLib.dataManip.psMinimizeLMChi2") > 4) {
     630            p_psImagePrint  (psTraceGetDestination(), Alpha, "alpha guess");
     631            p_psVectorPrint (psTraceGetDestination(), Beta, "beta guess");
     632            p_psVectorPrint (psTraceGetDestination(), Params, "params guess");
     633        }
     634        # endif /* PS_NO_TRACE */
     635
     636        // calculate Chisq for new guess, update Alpha & Beta
     637        Chisq = p_psMinLM_SetABX (Alpha, Beta, Params, x, y, dy, func);
     638        psTrace (".psLib.dataManip.psMinimizeLMChi2", 3, "chisq: %f, Chisq %f, delta: %f\n", chisq, Chisq, min->lastDelta);
     639
     640        // accept new guess (if improvement), or increase lambda
     641        if (Chisq < min->value) {
     642            min->lastDelta = (min->value - Chisq) / (dy->n - params->n);
     643            min->value = Chisq;
     644            alpha  = psImageCopy (alpha, Alpha, PS_TYPE_F64);
     645            beta   = psVectorCopy (beta, Beta, PS_TYPE_F64);
     646            params = psVectorCopy (params, Params, PS_TYPE_F32);
     647            lambda *= 0.1;
     648        } else {
     649            lambda *= 10.0;
     650        }
     651        min->iter ++;
     652    }
     653    psTrace (".psLib.dataManip.psMinimizeLMChi2", 3, "chisq: %f, Chisq %f, delta: %f\n", chisq, Chisq, min->lastDelta);
     654
     655    // free the internal temporary data
     656    psFree (alpha);
     657    psFree (Alpha);
     658    psFree (beta);
     659    psFree (Beta);
     660    psFree (Params);
     661    psFree (dy);
     662    return (true);
     663}
     664
     665// XXX EAM: this needs to respect the mask on params
     666// XXX EAM: check not NULL on alpha, beta, params
     667// alpha, beta, params are already allocated
     668psF64 p_psMinLM_SetABX (psImage  *alpha,
     669                        psVector *beta,
     670                        psVector *params,
     671                        const psArray  *x,
     672                        const psVector *y,
     673                        const psVector *dy,
     674                        psMinimizeLMChi2Func func)
     675{
     676
     677    psF64 chisq;
     678    psF64 delta;
     679    psF64 weight;
     680    psF64 ymodel;
     681    psVector *deriv = psVectorAlloc (params->n, PS_TYPE_F32);
     682
     683    // zero alpha and beta for summing below
     684    for (int j = 0; j < params->n; j++) {
     685        for (int k = 0; k < params->n; k++) {
     686            alpha->data.F64[j][k] = 0;
     687        }
     688        beta->data.F64[j] = 0;
     689    }
     690    chisq = 0.0;
     691
     692    // calculate chisq, alpha, beta
     693    for (int i = 0; i < y->n; i++) {
     694        ymodel = func (deriv, params, (psVector *) x->data[i]);
     695
     696        delta = ymodel - y->data.F32[i];
     697        chisq += PS_SQR (delta) * dy->data.F32[i];
     698
     699        for (int j = 0; j < params->n; j++) {
     700            weight = deriv->data.F32[j] * dy->data.F32[i];
     701            for (int k = 0; k <= j; k++) {
     702                alpha->data.F64[j][k] += weight * deriv->data.F32[k];
     703            }
     704            beta->data.F64[j] += weight * delta;
     705        }
     706    }
     707
     708    // calculate lower-left half of alpha
     709    for (int j = 1; j < params->n; j++) {
     710        for (int k = 0; k < j; k++) {
     711            alpha->data.F64[k][j] = alpha->data.F64[j][k];
     712        }
     713    }
     714    psFree (deriv);
     715    return (chisq);
     716}
     717
     718// XXX EAM : can we use static copies of LUv, LUm, A?
     719psBool p_psMinLM_GuessABP (psImage  *Alpha,
     720                           psVector *Beta,
     721                           psVector *Params,
     722                           psImage  *alpha,
     723                           psVector *beta,
     724                           psVector *params,
     725                           psF64 lambda)
     726{
     727
     728    # define USE_LU_DECOMP 1
     729    # if (USE_LU_DECOMP)
     730        psVector *LUv = NULL;
     731    psImage  *LUm = NULL;
     732    psImage  *A   = NULL;
     733    psF32    det;
     734
     735    // LU decomposition version
     736    psTrace (".pslib.dataManip.psMinLM_GuessABP", 3, "using LUD version");
     737
     738    // set new guess values (creates matrix A)
     739    A = psImageCopy (NULL, alpha, PS_TYPE_F64);
     740    for (int j = 0; j < params->n; j++) {
     741        A->data.F64[j][j] = alpha->data.F64[j][j] * (1.0 + lambda);
     742    }
     743
     744    // solve A*beta = Beta (Alpha = 1/A)
     745    // these operations do not modify the input values (creates LUm, LUv)
     746    LUm   = psMatrixLUD (NULL, &LUv, A);
     747    Beta  = psMatrixLUSolve (Beta, LUm, beta, LUv);
     748    Alpha = psMatrixInvert (Alpha, A, &det);
     749
     750    # else
     751        // gauss-jordan version
     752        psTrace (".pslib.dataManip.psMinLM_GuessABP", 3, "using Gauss-J version");
     753
     754    // set new guess values (creates matrix A)
     755    Beta = psVectorCopy (Beta, beta, PS_TYPE_F64);
     756    Alpha = psImageCopy (Alpha, alpha, PS_TYPE_F64);
     757    for (int j = 0; j < params->n; j++) {
     758        Alpha->data.F64[j][j] = alpha->data.F64[j][j] * (1.0 + lambda);
     759    }
     760
     761    psGaussJordan (Alpha, Beta);
     762    # endif
     763
     764    // apply beta to get new params values
     765    for (int j = 0; j < params->n; j++) {
     766        Params->data.F32[j] = params->data.F32[j] - Beta->data.F64[j];
     767    }
     768
     769    # if (USE_LU_DECOMP)
     770        psFree (A);
     771    psFree (LUm);
     772    psFree (LUv);
     773    # endif
     774
     775    return true;
     776}
     777
     778# define SWAP(X,Y) {double tmp=(X); (X) = (Y); (Y) = tmp;}
     779
     780// XXX EAM : temporary gauss-jordan solver based on gene's
     781// version based on the Numerical Recipes version
     782bool psGaussJordan (psImage *a, psVector *b)
     783{
     784
     785    int *indxc,*indxr,*ipiv;
     786    int Nx, icol, irow;
     787    int i, j, k, l, ll;
     788    float big, dum, pivinv;
     789    psF64 *vector;
     790    psF64 **matrix;
     791
     792    Nx = a->numCols;
     793    matrix = a->data.F64;
     794    vector = b->data.F64;
     795
     796    indxc = psAlloc (Nx*sizeof(int));
     797    indxr = psAlloc (Nx*sizeof(int));
     798    ipiv  = psAlloc (Nx*sizeof(int));
     799    for (j = 0; j < Nx; j++)
     800        ipiv[j] = 0;
     801
     802    irow = icol = 0;
     803    big = fabs(matrix[0][0]);
     804
     805    for (i = 0; i < Nx; i++) {
     806        big = 0.0;
     807        for (j = 0; j < Nx; j++) {
     808            if (!finite(matrix[i][j])) {
     809                // XXX EAM: this should use the psError stack
     810                fprintf (stderr, "GAUSSJ: NaN\n");
     811                goto fescape;
     812            }
     813            if (ipiv[j] != 1) {
     814                for (k = 0; k < Nx; k++) {
     815                    if (ipiv[k] == 0) {
     816                        if (fabs (matrix[j][k]) >= big) {
     817                            big  = fabs (matrix[j][k]);
     818                            irow = j;
     819                            icol = k;
     820                        }
     821                    } else {
     822                        if (ipiv[k] > 1) {
     823                            // XXX EAM: this should use the psError stack
     824                            fprintf (stderr, "GAUSSJ: Singular Matrix! (1)\n");
     825                            goto fescape;
     826                        }
     827                    }
     828                }
     829            }
     830        }
     831        ipiv[icol]++;
     832        if (irow != icol) {
     833            for (l = 0; l < Nx; l++) {
     834                SWAP (matrix[irow][l], matrix[icol][l]);
     835            }
     836            SWAP (vector[irow], vector[icol]);
     837        }
     838        indxr[i] = irow;
     839        indxc[i] = icol;
     840        if (matrix[icol][icol] == 0.0) {
     841            // XXX EAM: this should use the psError stack
     842            fprintf (stderr, "GAUSSJ: Singular Matrix! (2)\n");
     843            goto fescape;
     844        }
     845        pivinv = 1.0 / matrix[icol][icol];
     846        matrix[icol][icol] = 1.0;
     847        for (l = 0; l < Nx; l++) {
     848            matrix[icol][l] *= pivinv;
     849        }
     850        vector[icol] *= pivinv;
     851
     852        for (ll = 0; ll < Nx; ll++) {
     853            if (ll != icol) {
     854                dum = matrix[ll][icol];
     855                matrix[ll][icol] = 0.0;
     856                for (l = 0; l < Nx; l++)
     857                    matrix[ll][l] -= matrix[icol][l]*dum;
     858                vector[ll] -= vector[icol]*dum;
     859            }
     860        }
     861    }
     862
     863    for (l = Nx - 1; l >= 0; l--) {
     864        if (indxr[l] != indxc[l])
     865            for (k = 0; k < Nx; k++)
     866                SWAP (matrix[k][indxr[l]], matrix[k][indxc[l]]);
     867    }
     868    psFree (ipiv);
     869    psFree (indxr);
     870    psFree (indxc);
     871    return (true);
     872
     873fescape:
     874    psFree (ipiv);
     875    psFree (indxr);
     876    psFree (indxc);
     877    return (false);
     878}
     879
     880/******************************************************************************
     881psMinimizeLMChi2():  This routine will take an procedure which calculates
     882an arbitrary function and it's derivative and minimize the chi-squared match
     883between that function at the specified coords and the specified value at
     884those coords.
     885 
     886XXX: Do this:
     887 After checking that all entries in the paramMask are 1 or 0, when
     888 forming the A matrix from alpha, try this:
     889 
     890     A[i][i] = (1 + lambda*paramask[i]) * alpha[i][i];
     891 
     892XXX: This is very different from what is specified in the SDR.  Must
     893coordinate with IfA on new SDR.
     894 
     895XXX: Do vector/image recycles.
     896 
     897XXX: probably yErr will be part of the SDR.
     898 
     899XXX: This must work for both F32 and F64.  F32 is currently implemented.
     900     Note: since the LUD routines are only implemented in F64, then we
     901     will have to convert all F32 input vectors to F64 regardless.  So,
     902     the F64 port might be.
     903 
     904XXX: Must update the covar matrix.
     905 *****************************************************************************/
     906psBool psMinimizeLMChi2Old(psMinimization *min,
     907                           psImage *covar,
     908                           psVector *params,
     909                           const psVector *paramMask,
     910                           const psArray *x,
     911                           const psVector *y,
     912                           const psVector *yErr,
     913                           psMinimizeLMChi2Func func)
     914{
     915    PS_PTR_CHECK_NULL(min, NULL);
     916    PS_VECTOR_CHECK_NULL(params, NULL);
     917    PS_VECTOR_CHECK_EMPTY(params, NULL);
     918    PS_PTR_CHECK_NULL(x, NULL);
     919    PS_VECTOR_CHECK_NULL(y, NULL);
     920    PS_VECTOR_CHECK_EMPTY(y, NULL);
     921    PS_VECTOR_CHECK_SIZE_EQUAL(x, y, NULL);
     922    PS_PTR_CHECK_NULL(func, NULL);
     923
    603924    if (paramMask != NULL) {
    604925        PS_VECTOR_CHECK_SIZE_EQUAL(params, paramMask, NULL);
     
    636957    psF32 currChi2 = 0.0;
    637958    psF32 newChi2 = 0.0;
    638     psF32 lamda = 0.00005;
    639     lamda = 0.05;
     959    psF32 lamda = 0.00005;  // XXX EAM : this starting value is VERY small (lamda is mis-spelt)
     960    lamda = 0.05;  // XXX EAM : this starting value is quite large (lamda is mis-spelt)
    640961
    641962    psTrace(".psLib.dataManip.psMinimize", 6,
     
    661982        //
    662983        currChi2 = 0.0;
    663         currValueVec = func(deriv, params, x);
     984        // currValueVec = func(deriv, params, x);
     985
     986        // XXX EAM: use BinaryOp ?
     987        // t1 = BinaryOp (NULL, currValueVec, "-", y);
     988        // t1 = BinaryOp (t1, t1, "*", t1);
     989
     990        // XXX EAM: this ignores yErr
    664991        for (n=0;n<numData;n++) {
    665992            currChi2+= (currValueVec->data.F32[n] - y->data.F32[n]) *
     
    670997        }
    671998
     999        // XXX EAM: this is just for tracing
    6721000        for (p=0;p<numParams;p++) {
    6731001            psTrace(".psLib.dataManip.psMinimize", 6,
     
    6791007        //
    6801008        // Mask elements of the derivative for each data point.
    681         //
     1009        // XXX EAM : is this necessary?  probably not...
    6821010        for (p=0;p<numParams;p++) {
    6831011            if ((paramMask != NULL) && (paramMask->data.U8[p] != 0)) {
     
    6901018        //
    6911019        // Calculate the BETA vector.
    692         //
     1020        // XXX EAM: I think this is wrong
    6931021        for (p=0;p<numParams;p++) {
     1022            if ((paramMask != NULL) && (paramMask->data.U8[p] != 0)) {
     1023                continue;
     1024            }
    6941025            beta->data.F64[p] = 0.0;
    6951026            for (n=0;n<numData;n++) {
     
    7071038        //
    7081039        // Calculate the ALPHA matrix.
    709         //
     1040        // XXX EAM: also wrong? (missing yErr)
    7101041        for (k=0;k<numParams;k++) {
    7111042            for (l=0;l<numParams;l++) {
     
    7731104        //
    7741105        newChi2 = 0.0;
    775         newValueVec = func(deriv, newParams, x);
     1106        // newValueVec = func(deriv, newParams, x);
    7761107        for (n=0;n<numData;n++) {
    7771108            newChi2+= (newValueVec->data.F32[n] - y->data.F32[n]) *
     
    10981429    min->value = 0.0;
    10991430    min->iter = 0;
    1100     min->lastDelta = 0.0;
     1431    min->lastDelta = tol + 1;
    11011432
    11021433    return(min);
Note: See TracChangeset for help on using the changeset viewer.