IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Aug 7, 2009, 4:08:25 PM (17 years ago)
Author:
Paul Price
Message:

Merging trunk (r25026) to get up-to-date on old branch.

Location:
branches/pap
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/pap

  • branches/pap/psLib/src/math/psMatrix.c

    r19843 r25027  
    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 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,
    321368                     psVector *b
    322369                    )
     
    328375    PS_ASSERT_INT_EQUAL(a->numCols, a->numRows, false);
    329376    PS_ASSERT_VECTOR_SIZE(b, (long int)a->numCols, false);
    330 
    331 # if (0)
    332     // XXX expand this out explicitly below
    333     // Check for non-finite entries
    334 #define MATRIX_CHECK_NONFINITE_CASE(TYPE,MATRIX) \
    335   case PS_TYPE_##TYPE: { \
    336       ps##TYPE **values = MATRIX->data.TYPE; /* Dereference */ \
    337       int numCols = (MATRIX)->numCols, numRows = (MATRIX)->numRows; /* Size of matrix */ \
    338       for (int i = 0; i < numRows; i++) { \
    339           for (int j = 0; j < numCols; j++) { \
    340               if (!isfinite(values[i][j])) { \
    341                   // psError(PS_ERR_BAD_PARAMETER_VALUE, 3,             
    342                   // "Input matrix contains non-finite elements: matrix[%d][%d] is %.2f\n",
    343                   // i, j, values[i][j]);                               
    344                   return false; \
    345               } \
    346           } \
    347       } \
    348       break; \
    349   }
    350 # endif
    351377
    352378    // Check for non-finite entries in matrix
     
    390416    // Decompose the matrix and solve
    391417    psVector *perm = NULL;              // Permutation vector
    392     psImage *lu = psMatrixLUD(NULL, &perm, a); // LU decomposed matrix
     418    psImage *lu = psMatrixLUDecomposition(NULL, &perm, a); // LU decomposed matrix
    393419    if (!lu) {
    394420        psError(PS_ERR_UNKNOWN, false, "Unable to generate LU decomposed matrix");
     
    396422        return false;
    397423    }
    398     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
    399429    psFree(lu);
    400430    psFree(perm);
     
    410440}
    411441
     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
     458bool psMatrixGJSolve(psImage *a,
     459                     psVector *b
     460    )
     461{
     462    PS_ASSERT_IMAGE_NON_NULL(a, false);
     463    PS_ASSERT_VECTOR_NON_NULL(b, false);
     464    PS_ASSERT_IMAGE_TYPE_F32_OR_F64(a, false);
     465    PS_ASSERT_VECTOR_TYPE_F32_OR_F64(b, false);
     466    psAssert (a->type.type == b->type.type, "types must match for now");
     467    PS_ASSERT_INT_EQUAL(a->numCols, a->numRows, false);
     468    PS_ASSERT_VECTOR_SIZE(b, (long int)a->numCols, false);
     469
     470    // Check for non-finite entries in matrix
     471    switch (a->type.type) {
     472      case PS_TYPE_F32: {
     473          psF32 **values = a->data.F32; /* Dereference */
     474          int numCols = a->numCols, numRows = a->numRows; /* Size of matrix */
     475          for (int i = 0; i < numRows; i++) {
     476              for (int j = 0; j < numCols; j++) {
     477                  if (!isfinite(values[i][j])) {
     478                      return false;
     479                  }
     480              }
     481          }
     482          break;
     483      }
     484      case PS_TYPE_F64: {
     485          psF64 **values = a->data.F64; /* Dereference */
     486          int numCols = a->numCols, numRows = a->numRows; /* Size of matrix */
     487          for (int i = 0; i < numRows; i++) {
     488              for (int j = 0; j < numCols; j++) {
     489                  if (!isfinite(values[i][j])) {
     490                      return false;
     491                  }
     492              }
     493          }
     494          break;
     495      }
     496      default:
     497        psAbort("Should never get here.");
     498    }
     499 
     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.
     504
     505    int nSquare = a->numCols;
     506
     507    psVector *colIndexV = psVectorAlloc(nSquare, PS_TYPE_S32);
     508    psVector *rowIndexV = psVectorAlloc(nSquare, PS_TYPE_S32);
     509    psVector *pivotV    = psVectorAlloc(nSquare, PS_TYPE_S32);
     510    psVectorInit (pivotV, 0.0);
     511
     512    if (a->type.type == PS_TYPE_F32) {
     513        psF32 **A = a->data.F32;
     514        psF32  *B = b->data.F32;
     515        int *colIndex = colIndexV->data.S32;
     516        int *rowIndex = rowIndexV->data.S32;
     517        int *pivot    = pivotV->data.S32;
     518        psF32 growth = 1.0;
     519
     520        for (int diag = 0; diag < nSquare; diag++) {
     521
     522            psF32 maxval = 0.0;
     523            int maxrow = 0;
     524            int maxcol = 0;
     525
     526            // search for the next pivot
     527            for (int row = 0; row < nSquare; row++) {
     528                if (!isfinite(A[row][diag])) goto escape;
     529
     530                // if we have already operated on this row (pivot[row] is true), skip it
     531                if (pivot[row]) continue;
     532
     533                // if we have not yet operated on this row (pivot[row] is false), look for pivot for this row
     534                for (int col = 0; col < nSquare; col++) {
     535                    if (pivot[col]) continue;
     536                    if (fabs (A[row][col]) < maxval) continue;
     537                    maxval = fabs (A[row][col]);
     538                    maxrow = row;
     539                    maxcol = col;
     540                }
     541            }
     542
     543            // if pivot[maxcol] is set, we have already done this row: this implies a singular matrix
     544            if (pivot[maxcol]) goto escape;
     545            pivot[maxcol] = 1;
     546
     547            // if the selected pivot is off the diagonal, do a row swap
     548            if (maxrow != maxcol) {
     549                for (int col = 0; col < nSquare; col++) PS_SWAP (A[maxrow][col], A[maxcol][col]);
     550                PS_SWAP (B[maxrow], B[maxcol]);
     551            }
     552            rowIndex[diag] = maxrow;
     553            colIndex[diag] = maxcol;
     554            if (A[maxcol][maxcol] == 0.0) goto escape;
     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.
     557
     558            /* rescale by pivot reciprocal */
     559            psF32 tmpval = 1.0 / A[maxcol][maxcol];
     560            A[maxcol][maxcol] = 1.0;
     561            for (int col = 0; col < nSquare; col++) A[maxcol][col] *= tmpval;
     562            B[maxcol] *= tmpval;
     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;
     568
     569            /* adjust the elements above the pivot */
     570            for (int row = 0; row < nSquare; row++) {
     571                if (row == maxcol) continue;
     572                tmpval = A[row][maxcol];
     573                A[row][maxcol] = 0.0;
     574                for (int col = 0; col < nSquare; col++) A[row][col] -= A[maxcol][col]*tmpval;
     575                B[row] -= B[maxcol]*tmpval;
     576            }
     577        }
     578
     579        // swap back the inverse matrix based on the row swaps above
     580        for (int col = nSquare - 1; col >= 0; col--) {
     581            if (rowIndex[col] != colIndex[col]) {
     582                for (int row = 0; row < nSquare; row++) PS_SWAP (A[row][rowIndex[col]], A[row][colIndex[col]]);
     583            }
     584        }
     585    } else {
     586        psF64 **A = a->data.F64;
     587        psF64  *B = b->data.F64;
     588        int *colIndex = colIndexV->data.S32;
     589        int *rowIndex = rowIndexV->data.S32;
     590        int *pivot    = pivotV->data.S32;
     591        psF64 growth = 1.0;
     592
     593        for (int diag = 0; diag < nSquare; diag++) {
     594
     595            psF64 maxval = 0.0;
     596            int maxrow = 0;
     597            int maxcol = 0;
     598
     599            // search for the next pivot
     600            for (int row = 0; row < nSquare; row++) {
     601                if (!isfinite(A[row][diag])) goto escape;
     602
     603                // if we have already operated on this row (pivot[row] is true), skip it
     604                if (pivot[row]) continue;
     605
     606                // if we have not yet operated on this row (pivot[row] is false), look for pivot for this row
     607                for (int col = 0; col < nSquare; col++) {
     608                    if (pivot[col]) continue;
     609                    if (fabs (A[row][col]) < maxval) continue;
     610                    maxval = fabs (A[row][col]);
     611                    maxrow = row;
     612                    maxcol = col;
     613                }
     614            }
     615
     616            // if pivot[maxcol] is set, we have already done this row: this implies a singular matrix
     617            if (pivot[maxcol]) goto escape;
     618            pivot[maxcol] = 1;
     619
     620            // if the selected pivot is off the diagonal, do a row swap
     621            if (maxrow != maxcol) {
     622                for (int col = 0; col < nSquare; col++) PS_SWAP (A[maxrow][col], A[maxcol][col]);
     623                PS_SWAP (B[maxrow], B[maxcol]);
     624            }
     625            rowIndex[diag] = maxrow;
     626            colIndex[diag] = maxcol;
     627            if (A[maxcol][maxcol] == 0.0) goto escape;
     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.
     630
     631            /* rescale by pivot reciprocal */
     632            psF64 tmpval = 1.0 / A[maxcol][maxcol];
     633            A[maxcol][maxcol] = 1.0;
     634            for (int col = 0; col < nSquare; col++) A[maxcol][col] *= tmpval;
     635            B[maxcol] *= tmpval;
     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;
     641
     642            /* adjust the elements above the pivot */
     643            for (int row = 0; row < nSquare; row++) {
     644                if (row == maxcol) continue;
     645                tmpval = A[row][maxcol];
     646                A[row][maxcol] = 0.0;
     647                for (int col = 0; col < nSquare; col++) A[row][col] -= A[maxcol][col]*tmpval;
     648                B[row] -= B[maxcol]*tmpval;
     649            }
     650        }
     651
     652        // swap back the inverse matrix based on the row swaps above
     653        for (int col = nSquare - 1; col >= 0; col--) {
     654            if (rowIndex[col] != colIndex[col]) {
     655                for (int row = 0; row < nSquare; row++) PS_SWAP (A[row][rowIndex[col]], A[row][colIndex[col]]);
     656            }
     657        }
     658    }
     659
     660    psFree (pivotV);
     661    psFree (rowIndexV);
     662    psFree (colIndexV);
     663    return true;
     664
     665escape:
     666    psFree (pivotV);
     667    psFree (rowIndexV);
     668    psFree (colIndexV);
     669    return false;
     670}
    412671
    413672psImage* psMatrixInvert(psImage* out,
Note: See TracChangeset for help on using the changeset viewer.