Changeset 25027 for branches/pap/psLib/src/math/psMatrix.c
- Timestamp:
- Aug 7, 2009, 4:08:25 PM (17 years ago)
- Location:
- branches/pap
- Files:
-
- 2 edited
-
. (modified) (1 prop)
-
psLib/src/math/psMatrix.c (modified) (9 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/pap
- Property svn:mergeinfo changed
-
branches/pap/psLib/src/math/psMatrix.c
r19843 r25027 199 199 /*****************************************************************************/ 200 200 201 psImage* psMatrixLUD (psImage* out,201 psImage* psMatrixLUDecomposition(psImage* out, 202 202 psVector** perm, 203 203 const psImage* in) … … 210 210 211 211 212 #define psMatrixLUD _EXIT {psFree(out); return NULL;}212 #define psMatrixLUDecomposition_EXIT {psFree(out); return NULL;} 213 213 214 214 // 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); 219 219 220 220 out = psImageRecycle(out, in->numCols, in->numRows, in->type.type); 221 221 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); 224 224 225 225 // Initialize data … … 237 237 "Failed to allocate the permutation vector; " 238 238 "could not determine the cooresponding data type."); 239 psMatrixLUD _EXIT;239 psMatrixLUDecomposition_EXIT; 240 240 } 241 241 … … 259 259 } 260 260 261 psVector* psMatrixLUSol ve(psVector* out,261 psVector* psMatrixLUSolution(psVector* out, 262 262 const psImage* LU, 263 263 const psVector* RHS, … … 316 316 } 317 317 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, 318 psImage *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? 367 bool psMatrixLUSolve(psImage *a, 321 368 psVector *b 322 369 ) … … 328 375 PS_ASSERT_INT_EQUAL(a->numCols, a->numRows, false); 329 376 PS_ASSERT_VECTOR_SIZE(b, (long int)a->numCols, false); 330 331 # if (0)332 // XXX expand this out explicitly below333 // Check for non-finite entries334 #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 # endif351 377 352 378 // Check for non-finite entries in matrix … … 390 416 // Decompose the matrix and solve 391 417 psVector *perm = NULL; // Permutation vector 392 psImage *lu = psMatrixLUD (NULL, &perm, a); // LU decomposed matrix418 psImage *lu = psMatrixLUDecomposition(NULL, &perm, a); // LU decomposed matrix 393 419 if (!lu) { 394 420 psError(PS_ERR_UNKNOWN, false, "Unable to generate LU decomposed matrix"); … … 396 422 return false; 397 423 } 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 399 429 psFree(lu); 400 430 psFree(perm); … … 410 440 } 411 441 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 458 bool 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 665 escape: 666 psFree (pivotV); 667 psFree (rowIndexV); 668 psFree (colIndexV); 669 return false; 670 } 412 671 413 672 psImage* psMatrixInvert(psImage* out,
Note:
See TracChangeset
for help on using the changeset viewer.
