IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 24085


Ignore:
Timestamp:
May 6, 2009, 2:18:42 PM (17 years ago)
Author:
eugene
Message:

rename psMatrixLUSolve to psMatrixLUSolution, psMatrixLUD to psMatrixLUDecomposition, add psMatrixLUInvert and distinct psMatrixLUSolve vs psMatrixGJSolve

File:
1 edited

Legend:

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

    r23983 r24085  
    199199/*****************************************************************************/
    200200
    201 psImage* psMatrixLUD(psImage* out,
     201psImage* psMatrixLUDecomposition(psImage* out,
    202202                     psVector** perm,
    203203                     const psImage* in)
     
    210210
    211211
    212     #define psMatrixLUD_EXIT {psFree(out); return NULL;}
     212    #define psMatrixLUDecomposition_EXIT {psFree(out); return NULL;}
    213213
    214214    // Error checks
    215     PS_ASSERT_GENERAL_IMAGE_NON_NULL(in, psMatrixLUD_EXIT);
    216     PS_CHECK_POINTERS(in, out, psMatrixLUD_EXIT);
    217     PS_CHECK_DIMEN_AND_TYPE(in, PS_DIMEN_IMAGE, psMatrixLUD_EXIT);
    218     PS_ASSERT_GENERAL_PTR_NON_NULL(perm, psMatrixLUD_EXIT);
     215    PS_ASSERT_GENERAL_IMAGE_NON_NULL(in, psMatrixLUDecomposition_EXIT);
     216    PS_CHECK_POINTERS(in, out, psMatrixLUDecomposition_EXIT);
     217    PS_CHECK_DIMEN_AND_TYPE(in, PS_DIMEN_IMAGE, psMatrixLUDecomposition_EXIT);
     218    PS_ASSERT_GENERAL_PTR_NON_NULL(perm, psMatrixLUDecomposition_EXIT);
    219219
    220220    out = psImageRecycle(out, in->numCols, in->numRows, in->type.type);
    221221
    222     PS_CHECK_SQUARE(in, psMatrixLUD_EXIT); // gsl_linalg_LU_decomp would fail on non-square input.
    223     PS_CHECK_SQUARE(out, psMatrixLUD_EXIT);
     222    PS_CHECK_SQUARE(in, psMatrixLUDecomposition_EXIT); // gsl_linalg_LU_decomp would fail on non-square input.
     223    PS_CHECK_SQUARE(out, psMatrixLUDecomposition_EXIT);
    224224
    225225    // Initialize data
     
    237237                "Failed to allocate the permutation vector; "
    238238                "could not determine the cooresponding data type.");
    239         psMatrixLUD_EXIT;
     239        psMatrixLUDecomposition_EXIT;
    240240    }
    241241
     
    259259}
    260260
    261 psVector* psMatrixLUSolve(psVector* out,
     261psVector* psMatrixLUSolution(psVector* out,
    262262                          const psImage* LU,
    263263                          const psVector* RHS,
     
    316316}
    317317
    318 // This used to be "a temporary gauss-jordan solver based on gene's version based on the Numerical Recipes
    319 // version".  However, it's been removed due to copyright, and replaced with LU Decomposition solving.
    320 # if (0)
    321 bool psMatrixGJSolve(psImage *a,
     318psImage *psMatrixLUInvert(psImage *out,
     319                          const psImage* LU,
     320                          const psVector* perm)
     321{
     322    psS32 numRows = 0;
     323    psS32 numCols = 0;
     324    gsl_matrix *lu, *inverse;
     325    gsl_permutation permGSL;
     326
     327    #define LUSOLVE_CLEANUP {psFree(out); return NULL;}
     328
     329    // Error checks
     330    PS_ASSERT_GENERAL_IMAGE_NON_NULL(LU, LUSOLVE_CLEANUP);
     331    PS_CHECK_DIMEN_AND_TYPE(LU, PS_DIMEN_IMAGE, LUSOLVE_CLEANUP);
     332    PS_ASSERT_GENERAL_IMAGE_NON_EMPTY(LU, LUSOLVE_CLEANUP);
     333    PS_ASSERT_GENERAL_VECTOR_NON_NULL(perm, LUSOLVE_CLEANUP);
     334
     335    out = psImageRecycle(out, LU->numCols, LU->numRows, LU->type.type);
     336
     337    // Initialize data
     338    numRows = LU->numRows;
     339    numCols = LU->numCols;
     340
     341    // Initialize GSL data
     342    lu = gsl_matrix_alloc(numRows, numCols);
     343    psImageToGslMatrix(lu, LU);
     344
     345    permGSL.size = perm->n;
     346    permGSL.data = (psPtr)(perm->data.U8);
     347
     348    inverse = gsl_matrix_alloc(numRows, numCols);
     349
     350    // Solve for {x} in equation: {b} = [A]{x}
     351    gsl_linalg_LU_invert(lu, &permGSL, inverse);
     352
     353    // Copy GSL vector data to psVector data
     354    gslMatrixToPsImage(out, inverse);
     355
     356    // Free GSL data
     357    gsl_matrix_free(lu);
     358    gsl_matrix_free(inverse);
     359
     360    return out;
     361}
     362
     363// This is the LU Decomposition version of the matrix equation solver.  It solves the equation
     364// Ax = B, where A is a square matrix (NxN) and B is a vector of length N.  This solver only
     365// yields the solution for x, which is returned to the vector B.  This now DOES calculate the
     366// inverse of A.  A and B may be F32 or F64  XXX can they differ?
     367bool psMatrixLUSolve(psImage *a,
    322368                     psVector *b
    323369                    )
     
    370416    // Decompose the matrix and solve
    371417    psVector *perm = NULL;              // Permutation vector
    372     psImage *lu = psMatrixLUD(NULL, &perm, a); // LU decomposed matrix
     418    psImage *lu = psMatrixLUDecomposition(NULL, &perm, a); // LU decomposed matrix
    373419    if (!lu) {
    374420        psError(PS_ERR_UNKNOWN, false, "Unable to generate LU decomposed matrix");
     
    376422        return false;
    377423    }
    378     psVector *ans = psMatrixLUSolve(NULL, lu, b, perm); // Answer
     424    psVector *ans = psMatrixLUSolution(NULL, lu, b, perm); // Answer
     425
     426    // invert the matrix : check here for an ill-conditioned matrix?
     427    psMatrixLUInvert (a, lu, perm);
     428
    379429    psFree(lu);
    380430    psFree(perm);
     
    390440}
    391441
    392 # else
    393 
    394 // Gauss-Jordan elimination using full pivots based on Press et al's description.  Substantially
    395 // reworked for psLib style: major modifications to conform to C indexing, use a boolean to track the
    396 // completed pivot rows and catch the singular matrix early on.  Also, much cleaner control loops
    397 // than their implementation.  XXX this really needs to check on round-off errors (see version by
    398 // William Kahan
     442// This is the Gauss-Jordan elimination version of the matrix equation solver.  It solves the
     443// equation Ax = B, where A is a square matrix (NxN) and B is a vector of length N.  This
     444// solver calculates both the solution for x, which is returned to the vector B and the inverse
     445// of A (returned in A).  A and B may be F32 or F64, but must match.
     446
     447// Gauss-Jordan elimination using full pivots based on William Kahan's BASIC example and Press
     448// et al's description.  Substantially reworked for psLib style: major modifications to conform
     449// to C indexing, use a boolean to track the completed pivot rows and catch the singular matrix
     450// early on.  Also, much cleaner control loops than the Press implementation.
     451
     452// (based on version by William Kahan -- see Ohana/src/libohana/doc/kahan-gji.pdf)
     453
     454# define MAX_RANGE 1.0e7
     455// MAX_RANGE is used to test for ill-conditioned input matrices.  For an ill-conditioned
     456// matrix, one or more of the pivots trends towards zero, and growth goes to infinity.  Rather
     457// than allow this to go to the numerical precision, I am raising an error if |growth| > MAX_RANGE
    399458bool psMatrixGJSolve(psImage *a,
    400459                     psVector *b
     
    439498    }
    440499 
    441     // Following the algorithm laid out by Press et al., we loop along the matrix diagonal,
    442     // but we do not operate on the diagonal elements in order instead, we are looking for
    443     // the current max element and operating on that diagonal element.  this is effectively
    444     // column pivoting.  row pivoting is perfomed explicitly. 
     500    // Following the algorithm laid out by Press et al., we loop along the matrix diagonal, but
     501    // we do not operate on the diagonal elements in order.  Instead, we are looking for the
     502    // current max element and operating on that diagonal element.  This is effectively column
     503    // pivoting.  Row pivoting is perfomed explicitly.
    445504
    446505    int nSquare = a->numCols;
     
    457516        int *rowIndex = rowIndexV->data.S32;
    458517        int *pivot    = pivotV->data.S32;
     518        psF32 growth = 1.0;
    459519
    460520        for (int diag = 0; diag < nSquare; diag++) {
     
    493553            colIndex[diag] = maxcol;
    494554            if (A[maxcol][maxcol] == 0.0) goto escape;
    495             // XXX Kahan replaces the 0.0 pivot with epsilon*(largest element in column) + underFlow
     555            // Kahan replaces the 0.0 pivot with epsilon*(largest element in column) + underFlow.
     556            // Here we are going to raise an error if the dynamic range is too large.
    496557
    497558            /* rescale by pivot reciprocal */
     
    500561            for (int col = 0; col < nSquare; col++) A[maxcol][col] *= tmpval;
    501562            B[maxcol] *= tmpval;
    502             // XXX measure the pivot growth and trigger on over/under flow
    503             // growth *= tmpval;
    504             // fprintf (stderr, "column: %d, growth: %e, epsilon: %e\n", maxcol, growth, epsilon);
     563
     564            // check for ill-conditioned matrix: measure the pivot growth and trigger on over/under flow
     565            growth *= tmpval;
     566            psTrace ("psLib.math", 4, "growth : %e\n", growth);
     567            if (fabs(growth) > MAX_RANGE) goto escape;
    505568
    506569            /* adjust the elements above the pivot */
     
    526589        int *rowIndex = rowIndexV->data.S32;
    527590        int *pivot    = pivotV->data.S32;
     591        psF64 growth = 1.0;
    528592
    529593        for (int diag = 0; diag < nSquare; diag++) {
     
    562626            colIndex[diag] = maxcol;
    563627            if (A[maxcol][maxcol] == 0.0) goto escape;
    564             // XXX Kahan replaces the 0.0 pivot with epsilon*(largest element in column) + underFlow
     628            // Kahan replaces the 0.0 pivot with epsilon*(largest element in column) + underFlow.
     629            // Here we are going to raise an error if the dynamic range is too large.
    565630
    566631            /* rescale by pivot reciprocal */
     
    569634            for (int col = 0; col < nSquare; col++) A[maxcol][col] *= tmpval;
    570635            B[maxcol] *= tmpval;
    571             // XXX measure the pivot growth and trigger on over/under flow
    572             // growth *= tmpval;
    573             // fprintf (stderr, "column: %d, growth: %e, epsilon: %e\n", maxcol, growth, epsilon);
     636
     637            // check for ill-conditioned matrix: measure the pivot growth and trigger on over/under flow
     638            growth *= tmpval;
     639            psTrace ("psLib.math", 4, "growth : %e\n", growth);
     640            if (fabs(growth) > MAX_RANGE) goto escape;
    574641
    575642            /* adjust the elements above the pivot */
     
    602669    return false;
    603670}
    604 
    605 # endif
    606671
    607672psImage* psMatrixInvert(psImage* out,
Note: See TracChangeset for help on using the changeset viewer.