IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Jan 25, 2006, 2:31:19 PM (20 years ago)
Author:
gusciora
Message:

Several mods mostly to the psPolynomial fitting routines.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/psLib/src/math/psMinimizePolyFit.c

    r6186 r6193  
    1010 *  @author EAM, IfA
    1111 *
    12  *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
    13  *  @date $Date: 2006-01-23 22:25:31 $
     12 *  @version $Revision: 1.4 $ $Name: not supported by cvs2svn $
     13 *  @date $Date: 2006-01-26 00:31:19 $
    1414 *
    1515 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
     16 *
     17 *  XXX: psMatrixLUSolve() does not return error codes when the results are NANs.
    1618 *
    1719 *  XXX: For clip-fit functions, what should we do if the mask is NULL?
     
    279281 *****************************************************************************/
    280282
     283static psPolynomial1D* VectorFitPolynomial1DOrd(
     284    psPolynomial1D* myPoly,
     285    const psVector *mask,
     286    psMaskType maskValue,
     287    const psVector *f,
     288    const psVector *fErr,
     289    const psVector *x);
     290
     291/******************************************************************************
     292vectorFitPolynomial1DCheb():  This routine will fit a Chebyshev
     293polynomial of degree myPoly->nX to the data points (x, y) and return the
     294coefficients of that polynomial.
     295 
     296    NOTE: We currently have implemented three algorithms.  This one is
     297    non-standard.  It ignores the orthogonal properties of the Chebyshev
     298    polys, and their known zero values.  Instead, we first fit a regular
     299    ordinary polynomial to the data.  This produces the coefficients for the
     300    various x^i terms.  We then "reverse-engineer" those coefficients to
     301    determine the coefficients of the Chebyshev polys: basically for each
     302    c_ix^i term in the ordinary polynomial, we sum all x^i terms in the
     303    Chebshev polys: these must be equal.  This creates a set of nOrder+1
     304    linear equations which can be easily solved.  The resulting vector is the
     305    coefficients of the Chebyshev polys.
     306   
     307    This method is significantly slower than the standard NR algorithm.  It
     308    was explicitly requested that we not use the NR algorithm.
     309 
     310 Matrix A[[][]:
     311     Element A[i][j] is the coefficient of the x^i term in the j-th cheby poly.
     312 
     313    XXX: This can be improved significantly, performance-wise.  The second set
     314    of linear equations which must be "solved" are already in upper-triangular
     315    form.  One must only perform the reverse-substitution, LUD decomposition.
     316 
     317    XXX: Also, we don't really need to generate the chebPolys data structure.
     318    We simply need the matrix which corresponds to a transpose of each Cheby
     319    polys coefficients.
     320*****************************************************************************/
     321static psPolynomial1D *vectorFitPolynomial1DCheb(
     322    psPolynomial1D* myPoly,
     323    const psVector *mask,
     324    psMaskType maskValue,
     325    const psVector* y,
     326    const psVector* yErr,
     327    const psVector* x)
     328{
     329    PS_ASSERT_POLY_NON_NULL(myPoly, NULL);
     330    PS_ASSERT_INT_LARGER_THAN_OR_EQUAL(myPoly->nX, 0, NULL);
     331    PS_ASSERT_VECTOR_NON_NULL(y, NULL);
     332    PS_ASSERT_VECTOR_TYPE(y, PS_TYPE_F64, NULL);
     333    if (yErr != NULL) {
     334        PS_ASSERT_VECTORS_SIZE_EQUAL(y, yErr, NULL);
     335        PS_ASSERT_VECTOR_TYPE(yErr, PS_TYPE_F64, NULL);
     336    }
     337    if (x != NULL) {
     338        PS_ASSERT_VECTORS_SIZE_EQUAL(y, x, NULL);
     339        PS_ASSERT_VECTOR_TYPE(x, PS_TYPE_F64, NULL);
     340    }
     341    if (mask != NULL) {
     342        PS_ASSERT_VECTORS_SIZE_EQUAL(y, mask, NULL);
     343        PS_ASSERT_VECTOR_TYPE(mask, PS_TYPE_U8, NULL);
     344    }
     345
     346    psS32 polyOrder = myPoly->nX;
     347    psS32 numPoly = polyOrder + 1;
     348
     349    //
     350    // We first fit an ordinary polynomial to the data.
     351    //
     352    psPolynomial1D *ordPoly = psPolynomial1DAlloc(polyOrder, PS_POLYNOMIAL_ORD);
     353    psPolynomial1D *rc = VectorFitPolynomial1DOrd(ordPoly, mask, maskValue, y, yErr, x);
     354    if (rc == NULL) {
     355        psError(PS_ERR_UNKNOWN, false, "Could not fit a preliminary polynomial to the data vector.  Returning NULL.\n");
     356        psFree(myPoly);
     357        return(NULL);
     358    }
     359
     360    //
     361    // Create the A-matrix and B-vector which correspond to the linear equations
     362    // which will be solved and will then yield the Cheby poly coefficients.
     363    //
     364    psPolynomial1D **chebPolys = p_psCreateChebyshevPolys(numPoly);
     365    psImage *A = psImageAlloc(numPoly, numPoly, PS_TYPE_F64);
     366    psVector *B = psVectorAlloc(numPoly, PS_TYPE_F64);
     367    for (psS32 i = 0 ; i < numPoly ; i++) {
     368        for (psS32 j = 0 ; j < numPoly ; j++) {
     369            A->data.F64[i][j] = 0.0;
     370        }
     371        B->data.F64[i] = ordPoly->coeff[i];
     372    }
     373
     374    for (psS32 i = 0 ; i < numPoly ; i++) {
     375        for (psS32 j = 0 ; j < numPoly ; j++) {
     376            if (i <= chebPolys[j]->nX)
     377                A->data.F64[i][j]+= chebPolys[j]->coeff[i];
     378        }
     379    }
     380    // The following statement is essential.  It derives from (5.8.8) NR.
     381    A->data.F64[0][0] = 0.5;
     382    psFree(ordPoly);
     383    if (psTraceGetLevel(__func__) >= 6) {
     384        PS_IMAGE_PRINT_F64(A);
     385        PS_VECTOR_PRINT_F64(B);
     386    }
     387
     388    if (0) {
     389        // GaussJordan version
     390        if (false == psGaussJordan(A, B)) {
     391            psError(PS_ERR_UNKNOWN, false, "Could not solve linear equations.  Returning NULL.\n");
     392            psFree(myPoly);
     393            myPoly = NULL;
     394        } else {
     395            // the first nTerm entries in B correspond directly to the desired
     396            // polynomial coefficients.  this is only true for the 1D case
     397            for (psS32 k = 0; k < numPoly; k++) {
     398                myPoly->coeff[k] = B->data.F64[k];
     399            }
     400        }
     401    } else {
     402        // LUD version of the fit
     403        psImage *ALUD = NULL;
     404        psVector* outPerm = NULL;
     405        psVector* coeffs = NULL;
     406
     407        ALUD = psImageAlloc(numPoly, numPoly, PS_TYPE_F64);
     408        ALUD = psMatrixLUD(ALUD, &outPerm, A);
     409        if (ALUD == NULL) {
     410            psError(PS_ERR_UNKNOWN, false, "Could not do LUD decomposition on matrix.  Returning NULL.\n");
     411            psFree(myPoly);
     412            myPoly = NULL;
     413        } else {
     414            coeffs = psMatrixLUSolve(coeffs, ALUD, B, outPerm);
     415            if (coeffs == NULL) {
     416                psError(PS_ERR_UNKNOWN, false, "Could not solve LUD matrix.  Returning NULL.\n");
     417                psFree(myPoly);
     418                myPoly = NULL;
     419            } else {
     420                for (psS32 k = 0; k < numPoly; k++) {
     421                    myPoly->coeff[k] = coeffs->data.F64[k];
     422                }
     423            }
     424        }
     425
     426
     427        psFree(ALUD);
     428        psFree(coeffs);
     429        psFree(outPerm);
     430    }
     431
     432    psFree(A);
     433    psFree(B);
     434    for (psS32 i=0;i<numPoly;i++) {
     435        psFree(chebPolys[i]);
     436    }
     437    psFree(chebPolys);
     438
     439    return(myPoly);
     440}
     441
     442
    281443/******************************************************************************
    282444vectorFitPolynomial1DChebSlow():  This routine will fit a Chebyshev polynomial
     
    284446polynomial.
    285447 
    286     NOTE: We currently have implemented two algorithms.  This one is
     448    NOTE: We currently have implemented three algorithms.  This one is
    287449    non-standard.  It ignores the orthogonal properties of the Chebyshev
    288450    polys, and their known zero values.  Instead, we do build a system of
    289451    linear equations based on minimizing the chi-squared for all data points
    290452    and we then solve those equations.  This method is significantly slower
    291     than the other algorithm.  It was explicitly requested that we implement
     453    than the other algorithms.  It was explicitly requested that we implement
    292454    this algorithm.
    293  
    294455*****************************************************************************/
    295456static psPolynomial1D *vectorFitPolynomial1DChebySlow(
     
    329490        NUM_DATA = x->n;
    330491    }
    331     // psTrace    printf("vectorFitPolynomial1DChebySlow(): NUM_DATA is %d\n", NUM_DATA);
    332492
    333493    psPolynomial1D **chebPolys = p_psCreateChebyshevPolys(NUM_POLY);
     
    408568        psVector* coeffs = NULL;
    409569
    410         // XXX: Check return codes.
    411570        ALUD = psImageAlloc(NUM_POLY, NUM_POLY, PS_TYPE_F64);
    412571        ALUD = psMatrixLUD(ALUD, &outPerm, A);
    413         coeffs = psMatrixLUSolve(coeffs, ALUD, B, outPerm);
    414         for (psS32 k = 0; k < NUM_POLY; k++) {
    415             myPoly->coeff[k] = coeffs->data.F64[k];
     572        if (ALUD == NULL) {
     573            psError(PS_ERR_UNKNOWN, false, "Could not do LUD decomposition on matrix.  Returning NULL.\n");
     574            psFree(myPoly);
     575            myPoly = NULL;
     576        } else {
     577            coeffs = psMatrixLUSolve(coeffs, ALUD, B, outPerm);
     578            if (coeffs == NULL) {
     579                psError(PS_ERR_UNKNOWN, false, "Could not solve LUD matrix.  Returning NULL.\n");
     580                psFree(myPoly);
     581                myPoly = NULL;
     582            } else {
     583                for (psS32 k = 0; k < NUM_POLY; k++) {
     584                    myPoly->coeff[k] = coeffs->data.F64[k];
     585                }
     586            }
    416587        }
    417588
     
    437608polynomial.
    438609 
    439     NOTE: We currently have two algorithms.  This is standard method which
     610    NOTE: We currently have three algorithms.  This is standard method which
    440611    uses the orthogonal properties of the Chebyshev polys, and their known
    441     zero values.  This is significantly faster than the chi-squared approach.
     612    zero values.  This is significantly faster than the chi-squared
     613    approaches.
    442614 
    443615    NOTE: This function will not work properly if the x-vector does not fully span
     
    621793    // Build the B and A data structs.
    622794    // XXX EAM : use temp pointers eg vB = B->data.F64 to save redirects
    623     // XXX EAM : this function is only valid for data vectors of F64
    624795    for (psS32 k = 0; k < f->n; k++) {
    625796        if ((mask != NULL) && (mask->data.U8[k] && maskValue)) {
     
    671842        psVector* coeffs = NULL;
    672843
    673         // XXX: Check return codes.
    674844        ALUD = psImageAlloc(nTerm, nTerm, PS_TYPE_F64);
    675845        ALUD = psMatrixLUD(ALUD, &outPerm, A);
    676         coeffs = psMatrixLUSolve(coeffs, ALUD, B, outPerm);
    677         for (psS32 k = 0; k < nTerm; k++) {
    678             myPoly->coeff[k] = coeffs->data.F64[k];
    679         }
     846        if (ALUD == NULL) {
     847            psError(PS_ERR_UNKNOWN, false, "Could not do LUD decomposition on matrix.  Returning NULL.\n");
     848            psFree(myPoly);
     849            myPoly = NULL;
     850        } else {
     851            coeffs = psMatrixLUSolve(coeffs, ALUD, B, outPerm);
     852            if (coeffs == NULL) {
     853                psError(PS_ERR_UNKNOWN, false, "Could not solve LUD matrix.  Returning NULL.\n");
     854                psFree(myPoly);
     855                myPoly = NULL;
     856            } else {
     857                for (psS32 k = 0; k < nTerm; k++) {
     858                    myPoly->coeff[k] = coeffs->data.F64[k];
     859                }
     860            }
     861        }
     862
    680863        psFree(ALUD);
    681864        psFree(coeffs);
     
    771954
    772955        if (1) {
    773             poly = vectorFitPolynomial1DChebySlow(poly, mask, maskValue, f64, fErr64, x64);
     956            poly = vectorFitPolynomial1DCheb(poly, mask, maskValue, f64, fErr64, x64);
    774957        } else {
    775             poly = vectorFitPolynomial1DChebyFast(poly, mask, maskValue, f64, fErr64, x64);
     958            if (0) {
     959                poly = vectorFitPolynomial1DChebySlow(poly, mask, maskValue, f64, fErr64, x64);
     960                poly = vectorFitPolynomial1DChebyFast(poly, mask, maskValue, f64, fErr64, x64);
     961            }
    776962        }
    777963        if (x == NULL) {
     
    9891175    PS_ASSERT_INT_NONNEGATIVE(myPoly->nX, NULL);
    9901176    PS_ASSERT_INT_NONNEGATIVE(myPoly->nY, NULL);
    991 
    9921177    PS_ASSERT_VECTOR_NON_NULL(f, NULL);
    9931178    PS_ASSERT_VECTOR_TYPE(f, PS_TYPE_F64, NULL);
     
    15601745        psVector* coeffs = NULL;
    15611746
    1562         // XXX: Check return codes.
    15631747        ALUD = psImageAlloc(nTerm, nTerm, PS_TYPE_F64);
    15641748        ALUD = psMatrixLUD(ALUD, &outPerm, A);
    1565         coeffs = psMatrixLUSolve(coeffs, ALUD, B, outPerm);
    1566 
    1567         // select the appropriate solution entries
    1568         for (psS32 ix = 0; ix < nXterm; ix++) {
    1569             for (psS32 iy = 0; iy < nYterm; iy++) {
    1570                 for (psS32 iz = 0; iz < nZterm; iz++) {
    1571                     psS32 nx = ix+iy*nXterm+iz*nXterm*nYterm;
    1572                     myPoly->coeff[ix][iy][iz] = coeffs->data.F64[nx];
    1573                     myPoly->coeffErr[ix][iy][iz] = sqrt(A->data.F64[nx][nx]);
     1749        if (ALUD == NULL) {
     1750            psError(PS_ERR_UNKNOWN, false, "Could not do LUD decomposition on matrix.  Returning NULL.\n");
     1751            psFree(myPoly);
     1752            myPoly = NULL;
     1753        } else {
     1754            coeffs = psMatrixLUSolve(coeffs, ALUD, B, outPerm);
     1755            if (coeffs == NULL) {
     1756                psError(PS_ERR_UNKNOWN, false, "Could not solve LUD matrix.  Returning NULL.\n");
     1757                psFree(myPoly);
     1758                myPoly = NULL;
     1759            } else {
     1760                // select the appropriate solution entries
     1761                for (psS32 ix = 0; ix < nXterm; ix++) {
     1762                    for (psS32 iy = 0; iy < nYterm; iy++) {
     1763                        for (psS32 iz = 0; iz < nZterm; iz++) {
     1764                            psS32 nx = ix+iy*nXterm+iz*nXterm*nYterm;
     1765                            myPoly->coeff[ix][iy][iz] = coeffs->data.F64[nx];
     1766                            myPoly->coeffErr[ix][iy][iz] = sqrt(A->data.F64[nx][nx]);
     1767                        }
     1768                    }
    15741769                }
    15751770            }
     
    21082303        psVector* coeffs = NULL;
    21092304
    2110         // XXX: Check return codes.
    21112305        ALUD = psImageAlloc(nTerm, nTerm, PS_TYPE_F64);
    21122306        ALUD = psMatrixLUD(ALUD, &outPerm, A);
    2113         coeffs = psMatrixLUSolve(coeffs, ALUD, B, outPerm);
    2114 
    2115         // select the appropriate solution entries
    2116         for (psS32 ix = 0; ix < nXterm; ix++) {
    2117             for (psS32 iy = 0; iy < nYterm; iy++) {
    2118                 for (psS32 iz = 0; iz < nZterm; iz++) {
    2119                     for (psS32 it = 0; it < nTterm; it++) {
    2120                         psS32 nx = ix+iy*nXterm+iz*nXterm*nYterm+it*nXterm*nYterm*nZterm;
    2121                         myPoly->coeff[ix][iy][iz][it] = coeffs->data.F64[nx];
    2122                         myPoly->coeffErr[ix][iy][iz][it] = sqrt(A->data.F64[nx][nx]);
     2307        if (ALUD == NULL) {
     2308            psError(PS_ERR_UNKNOWN, false, "Could not do LUD decomposition on matrix.  Returning NULL.\n");
     2309            psFree(myPoly);
     2310            myPoly = NULL;
     2311        } else {
     2312            coeffs = psMatrixLUSolve(coeffs, ALUD, B, outPerm);
     2313            if (coeffs == NULL) {
     2314                psError(PS_ERR_UNKNOWN, false, "Could not solve LUD matrix.  Returning NULL.\n");
     2315                psFree(myPoly);
     2316                myPoly = NULL;
     2317            } else {
     2318                // select the appropriate solution entries
     2319                for (psS32 ix = 0; ix < nXterm; ix++) {
     2320                    for (psS32 iy = 0; iy < nYterm; iy++) {
     2321                        for (psS32 iz = 0; iz < nZterm; iz++) {
     2322                            for (psS32 it = 0; it < nTterm; it++) {
     2323                                psS32 nx = ix+iy*nXterm+iz*nXterm*nYterm+it*nXterm*nYterm*nZterm;
     2324                                myPoly->coeff[ix][iy][iz][it] = coeffs->data.F64[nx];
     2325                                myPoly->coeffErr[ix][iy][iz][it] = sqrt(A->data.F64[nx][nx]);
     2326                            }
     2327                        }
    21232328                    }
    21242329                }
Note: See TracChangeset for help on using the changeset viewer.