Changeset 35767
- Timestamp:
- Jul 3, 2013, 2:30:22 PM (13 years ago)
- Location:
- trunk/psLib
- Files:
-
- 7 edited
- 3 copied
-
src/imageops/psImageConvolve.c (modified) (4 diffs)
-
src/imageops/psImageConvolve.h (modified) (4 diffs)
-
src/math/psMinimizeLMM.c (modified) (6 diffs)
-
src/math/psMinimizeLMM.h (modified) (3 diffs)
-
test/imageops/Makefile.am (modified) (1 diff)
-
test/imageops/tap_psImageSmoothMask_Threaded.c (copied) (copied from branches/eam_branches/ipp-20130509/psLib/test/imageops/tap_psImageSmoothMask_Threaded.c )
-
test/math/Makefile.am (modified) (1 diff)
-
test/math/tap_psMinimizeLMM_Alt.c (copied) (copied from branches/eam_branches/ipp-20130509/psLib/test/math/tap_psMinimizeLMM_Alt.c )
-
test/math/tap_psMinimizeLMM_Trail.c (copied) (copied from branches/eam_branches/ipp-20130509/psLib/test/math/tap_psMinimizeLMM_Trail.c )
-
test/pstap/src/pstap.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/imageops/psImageConvolve.c
r34724 r35767 1231 1231 } 1232 1232 1233 /*********************** smooth with mask, threaded version ***********************/ 1234 1233 1235 bool psImageSmoothMask_ScanRows_F32(psImage *calculation, psImage *calcMask, const psImage *image, 1234 1236 const psImage *mask, psImageMaskType maskVal, psVector *gaussNorm, … … 1484 1486 1485 1487 1488 /*********************** smooth no-mask ***********************/ 1489 1490 bool psImageSmoothNoMask_ScanRows_F32(psImage *calculation, const psImage *image, 1491 psVector *gaussNorm, float minGauss, 1492 int size, int rowStart, int rowStop) 1493 { 1494 const psF32 *gauss = &gaussNorm->data.F32[size]; // Gaussian convolution kernel 1495 1496 int numCols = image->numCols; 1497 int xLast = numCols - 1; // Last index 1498 1499 for (int j = rowStart; j < rowStop; j++) { 1500 for (int i = 0; i < numCols; i++) { 1501 int xMin = PS_MAX(i - size, 0); 1502 int xMax = PS_MIN(i + size, xLast); 1503 const psF32 *imageData = &image->data.F32[j][xMin]; 1504 int uMin = - PS_MIN(i, size); /* Minimum kernel index */ 1505 const psF32 *gaussData = &gauss[uMin]; 1506 double sumIG = 0.0, sumG = 0.0; /* Sums for convolution */ 1507 for (int x = xMin; x <= xMax; x++, imageData++, gaussData++) { 1508 sumIG += *imageData * *gaussData; 1509 sumG += *gaussData; 1510 } 1511 if (sumG > minGauss) { 1512 /* BW */ 1513 calculation->data.F32[i][j] = sumIG / sumG; 1514 } 1515 } 1516 } 1517 return true; 1518 } 1519 1520 bool psImageSmoothNoMask_ScanCols_F32(psImage *output, psImage *calculation, 1521 psVector *gaussNorm, float minGauss, 1522 int size, int colStart, int colStop) 1523 { 1524 const psF32 *gauss = &gaussNorm->data.F32[size]; // Gaussian convolution kernel 1525 1526 int numRows = output->numRows; 1527 int yLast = numRows - 1; // Last index 1528 1529 for (int i = colStart; i < colStop; i++) { 1530 for (int j = 0; j < numRows; j++) { 1531 int yMin = PS_MAX(j - size, 0); 1532 int yMax = PS_MIN(j + size, yLast); 1533 const psF32 *imageData = &calculation->data.F32[i][yMin]; /* BW */ 1534 int vMin = - PS_MIN(j, size); /* Minimum kernel index */ 1535 const psF32 *gaussData = &gauss[vMin]; 1536 double sumIG = 0.0, sumG = 0.0; /* Sums for convolution */ 1537 for (int y = yMin; y <= yMax; y++, imageData++, gaussData++) { 1538 sumIG += *imageData * *gaussData; 1539 sumG += *gaussData; 1540 } 1541 output->data.F32[j][i] = (sumG > minGauss) ? sumIG / sumG : NAN; 1542 } 1543 } 1544 return true; 1545 } 1546 1547 bool psImageSmoothNoMask_ScanRows_F32_Threaded(psThreadJob *job) 1548 { 1549 PS_ASSERT_THREAD_JOB_NON_NULL(job, false); 1550 psAssert (job->args, "programming error: job args not alloced?"); 1551 psAssert (job->args->n == 7, "programming error: job Nargs mismatch"); 1552 1553 psImage *calculation = job->args->data[0]; // calculation image 1554 const psImage *image = job->args->data[1]; // input image 1555 1556 psVector *gaussNorm = job->args->data[2]; // gauss kernel 1557 float minGauss = PS_SCALAR_VALUE(job->args->data[3],F32); 1558 int size = PS_SCALAR_VALUE(job->args->data[4],S32); 1559 int rowStart = PS_SCALAR_VALUE(job->args->data[5],S32); 1560 int rowStop = PS_SCALAR_VALUE(job->args->data[6],S32); 1561 return psImageSmoothNoMask_ScanRows_F32(calculation, image, 1562 gaussNorm, minGauss, size, 1563 rowStart, rowStop); 1564 } 1565 1566 bool psImageSmoothNoMask_ScanCols_F32_Threaded(psThreadJob *job) 1567 { 1568 PS_ASSERT_THREAD_JOB_NON_NULL(job, false); 1569 psAssert (job->args, "programming error: job args not alloced?"); 1570 psAssert (job->args->n == 7, "programming error: job Nargs mismatch"); 1571 1572 psImage *output = job->args->data[0]; // input image 1573 psImage *calculation = job->args->data[1]; // calculation image 1574 1575 psVector *gaussNorm = job->args->data[2]; // gauss kernel 1576 float minGauss = PS_SCALAR_VALUE(job->args->data[3],F32); 1577 int size = PS_SCALAR_VALUE(job->args->data[4],S32); 1578 int colStart = PS_SCALAR_VALUE(job->args->data[5],S32); 1579 int colStop = PS_SCALAR_VALUE(job->args->data[6],S32); 1580 return psImageSmoothNoMask_ScanCols_F32(output, calculation, 1581 gaussNorm, minGauss, size, 1582 colStart, colStop); 1583 } 1584 1585 psImage *psImageSmoothNoMask_Threaded(psImage *output, const psImage *image, float sigma, float numSigma, float minGauss) 1586 { 1587 PS_ASSERT_IMAGE_NON_NULL(image, NULL); 1588 1589 int numCols = image->numCols, numRows = image->numRows; // Size of image 1590 1591 int nThreads = psThreadPoolSize(); 1592 int scanCols = nThreads ? (numCols / 4 / nThreads) : numCols; 1593 int scanRows = nThreads ? (numRows / 4 / nThreads) : numRows; 1594 int size = sigma * numSigma + 0.5; // Half-size of kernel 1595 1596 // Generate normalized gaussian 1597 psVector *gaussNorm = NULL; 1598 IMAGE_SMOOTH_GAUSS(gaussNorm, size, sigma, F32); 1599 1600 switch (image->type.type) { 1601 // Smooth an image with masked pixels 1602 // The calculation and calcMask images are *deliberately* backwards (row,col instead of col,row or 1603 // [col][row] instead of [row][col]) to optimise the iteration over rows; such instances are marked "BW" 1604 1605 case PS_TYPE_F32: { 1606 psImage *calculation = psImageAlloc(numRows, numCols, PS_TYPE_F32); /* Calculation image; BW */ 1607 1608 if (threaded) { 1609 /** Smooth in X direction **/ 1610 for (int rowStart = 0; rowStart < numRows; rowStart+=scanRows) { 1611 int rowStop = PS_MIN (rowStart + scanRows, numRows); 1612 1613 // allocate a job, construct the arguments for this job 1614 psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_SMOOTH_NOMASK_SCANROWS"); 1615 psArrayAdd(job->args, 0, calculation); 1616 psArrayAdd(job->args, 0, (psImage *) image); // cast away const 1617 psArrayAdd(job->args, 0, gaussNorm); 1618 PS_ARRAY_ADD_SCALAR(job->args, minGauss, PS_TYPE_F32); 1619 PS_ARRAY_ADD_SCALAR(job->args, size, PS_TYPE_S32); 1620 PS_ARRAY_ADD_SCALAR(job->args, rowStart, PS_TYPE_S32); 1621 PS_ARRAY_ADD_SCALAR(job->args, rowStop, PS_TYPE_S32); 1622 // -> psImageSmoothNoMask_ScanRows_F32 (calculation, image, gauss, minGauss, size, rowStart, rowStop); 1623 1624 // if threading is not active, we simply run the job and return 1625 if (!psThreadJobAddPending(job)) { 1626 psError(PS_ERR_UNKNOWN, false, "Unable to smooth image"); 1627 psFree(calculation); 1628 psFree(gaussNorm); 1629 return false; 1630 } 1631 } 1632 // wait here for the threaded jobs to finish (NOP if threading is not active) 1633 if (!psThreadPoolWait(true, true)) { 1634 psError(PS_ERR_UNKNOWN, false, "Unable to smooth image"); 1635 psFree(calculation); 1636 psFree(gaussNorm); 1637 return false; 1638 } 1639 } else if (!psImageSmoothNoMask_ScanRows_F32(calculation, image, gaussNorm, minGauss, size, 0, numRows)) { 1640 psError(PS_ERR_UNKNOWN, false, "Unable to smooth image"); 1641 psFree(calculation); 1642 psFree(gaussNorm); 1643 return false; 1644 } 1645 1646 output = psImageRecycle(output, numCols, numRows, PS_TYPE_F32); 1647 1648 /** Smooth in Y direction **/ 1649 if (threaded) { 1650 for (int colStart = 0; colStart < numCols; colStart+=scanCols) { 1651 int colStop = PS_MIN (colStart + scanCols, numCols); 1652 1653 // allocate a job, construct the arguments for this job 1654 psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_SMOOTH_NOMASK_SCANCOLS"); 1655 psArrayAdd(job->args, 0, output); 1656 psArrayAdd(job->args, 0, calculation); 1657 psArrayAdd(job->args, 0, gaussNorm); 1658 PS_ARRAY_ADD_SCALAR(job->args, minGauss, PS_TYPE_F32); 1659 PS_ARRAY_ADD_SCALAR(job->args, size, PS_TYPE_S32); 1660 PS_ARRAY_ADD_SCALAR(job->args, colStart, PS_TYPE_S32); 1661 PS_ARRAY_ADD_SCALAR(job->args, colStop, PS_TYPE_S32); 1662 // -> psImageSmoothMask_ScanCols_F32 (output, calculation, gauss, minGauss, size, colStart, colStop); 1663 1664 // if threading is not active, we simply run the job and return 1665 if (!psThreadJobAddPending(job)) { 1666 psError(PS_ERR_UNKNOWN, false, "Unable to smooth image"); 1667 psFree(calculation); 1668 psFree(gaussNorm); 1669 return false; 1670 } 1671 } 1672 1673 // wait here for the threaded jobs to finish (NOP if threading is not active) 1674 if (!psThreadPoolWait(true, true)) { 1675 psError(PS_ERR_UNKNOWN, false, "Unable to smooth image"); 1676 psFree(calculation); 1677 psFree(gaussNorm); 1678 return false; 1679 } 1680 } else if (!psImageSmoothNoMask_ScanCols_F32(output, calculation, gaussNorm, minGauss, size, 0, numCols)) { 1681 psError(PS_ERR_UNKNOWN, false, "Unable to smooth image"); 1682 psFree(calculation); 1683 psFree(gaussNorm); 1684 return false; 1685 } 1686 1687 psFree(calculation); 1688 psFree(gaussNorm); 1689 1690 return output; 1691 } 1692 default: 1693 psFree(gaussNorm); 1694 char *typeStr; 1695 PS_TYPE_NAME(typeStr,image->type.type); 1696 psError(PS_ERR_BAD_PARAMETER_TYPE, true, 1697 _("Specified psImage type, %s, is not supported."), 1698 typeStr); 1699 return false; 1700 } 1701 1702 psAbort("Should never reach here."); 1703 return false; 1704 } 1705 1706 /****************************************************************************************/ 1707 1486 1708 bool psImageSmoothMaskF32(psImage *image, psImage *mask, psImageMaskType maskVal, 1487 1709 double sigma, double Nsigma) … … 1900 2122 } 1901 2123 { 2124 psThreadTask *task = psThreadTaskAlloc("PSLIB_IMAGE_SMOOTH_NOMASK_SCANROWS", 7); 2125 task->function = &psImageSmoothNoMask_ScanRows_F32_Threaded; 2126 psThreadTaskAdd(task); 2127 psFree(task); 2128 } 2129 { 2130 psThreadTask *task = psThreadTaskAlloc("PSLIB_IMAGE_SMOOTH_NOMASK_SCANCOLS", 7); 2131 task->function = &psImageSmoothNoMask_ScanCols_F32_Threaded; 2132 psThreadTaskAdd(task); 2133 psFree(task); 2134 } 2135 { 1902 2136 psThreadTask *task = psThreadTaskAlloc("PSLIB_IMAGE_SMOOTHMASK_PIXELS", 9); 1903 2137 task->function = &psImageSmoothMaskPixelsThread; … … 1909 2143 psThreadTaskRemove("PSLIB_IMAGE_SMOOTHMASK_SCANROWS"); 1910 2144 psThreadTaskRemove("PSLIB_IMAGE_SMOOTHMASK_SCANCOLS"); 2145 psThreadTaskRemove("PSLIB_IMAGE_SMOOTH_NOMASK_SCANROWS"); 2146 psThreadTaskRemove("PSLIB_IMAGE_SMOOTH_NOMASK_SCANCOLS"); 1911 2147 psThreadTaskRemove("PSLIB_IMAGE_SMOOTHMASK_PIXELS"); 1912 2148 } -
trunk/psLib/src/imageops/psImageConvolve.h
r32725 r35767 242 242 ); 243 243 244 /// Smooth an image by parts using 1D Gaussian independently in x and y, allowing for masked pixels 244 /// Smooth an imageby parts using 1D Gaussian independently in x and y, allowing for 245 /// MASKED PIXELS 245 246 /// 246 247 /// Applies a circularly symmetric Gaussian smoothing first in x and then in y … … 256 257 ); 257 258 258 /// Smooth particular pixels on an image, allowing for masked pixels259 /// Smooth particular pixels on an image, allowing for MASKED PIXELS 259 260 /// 260 261 /// Applies a circularly symmetric Gaussian smoothing first in x and then in y … … 271 272 ); 272 273 274 /// Smooth an image by parts using 1D Gaussian independently in x and y, allowing for 275 /// MASKED PIXELS : THREADED VERSION 276 /// 277 /// Applies a circularly symmetric Gaussian smoothing first in x and then in y 278 /// directions with just a vector. This process is 2N faster than 2D convolutions (in general). 273 279 psImage *psImageSmoothMask_Threaded(psImage *output, 274 280 const psImage *image, … … 279 285 float minGauss); 280 286 287 /// Smooth an image by parts using 1D Gaussian independently in x and y, allowing for 288 /// MASKED PIXELS : THREADED VERSION 289 /// 290 /// Applies a circularly symmetric Gaussian smoothing first in x and then in y 291 /// directions with just a vector. This process is 2N faster than 2D convolutions (in general). 292 psImage *psImageSmoothNoMask_Threaded(psImage *output, 293 const psImage *image, 294 float sigma, 295 float numSigma, 296 float minGauss); 297 298 /// Smooth an image by parts IN-SITU using 1D Gaussian independently in x and y, allowing 299 /// for MASKED PIXELS 281 300 bool psImageSmoothMaskF32( 282 301 psImage *image, ///< the image to be smoothed -
trunk/psLib/src/math/psMinimizeLMM.c
r29542 r35767 325 325 chisq += PS_SQR(delta) * dy->data.F32[i]; 326 326 327 // XXX remove this later: 328 // psVector *tmp = x->data[i]; 329 // fprintf (stderr, "%f %f %f %f %f\n", tmp->data.F32[0], tmp->data.F32[1], y->data.F32[i], dy->data.F32[i], ymodel); 330 327 331 if (isnan(dy->data.F32[i])) goto escape; 328 332 if (isnan(delta)) goto escape; … … 360 364 } 361 365 366 /****************************************************************************** 367 psMinimizeLMChi2(): wrapper to call either _Old or _Alt 368 *****************************************************************************/ 369 bool psMinimizeLMChi2( 370 psMinimization *min, 371 psImage *covar, 372 psVector *params, 373 psMinConstraint *constraint, 374 const psArray *x, 375 const psVector *y, 376 const psVector *yWt, 377 psMinimizeLMChi2Func func) 378 { 379 bool status = psMinimizeLMChi2_Alt( 380 min, 381 covar, 382 params, 383 constraint, 384 x, 385 y, 386 yWt, 387 func); 388 return status; 389 } 362 390 363 391 /****************************************************************************** … … 370 398 XXX Make an F64 version? 371 399 *****************************************************************************/ 372 bool psMinimizeLMChi2 (400 bool psMinimizeLMChi2_Old( 373 401 psMinimization *min, 374 402 psImage *covar, … … 507 535 psF32 rho = (min->value - Chisq) / dLinear; 508 536 509 psTrace("psLib.math", 5, "last chisq: %f, new chisq %f, delta: %f, dLinear: %f, rho: %f, lambda: % f, nDOF: %d\n", min->value, Chisq, min->lastDelta, dLinear, rho, lambda, nDOF);510 511 psTrace("psLib.math.dLinear", 5, "last chisq: %f, new chisq %f, delta: %f, dLinear: %f, rho: %f, lambda: % f\n", min->value, Chisq, min->lastDelta, dLinear, rho, lambda);537 psTrace("psLib.math", 5, "last chisq: %f, new chisq %f, delta: %f, dLinear: %f, rho: %f, lambda: %g, nDOF: %d\n", min->value, Chisq, min->lastDelta, dLinear, rho, lambda, nDOF); 538 539 psTrace("psLib.math.dLinear", 5, "last chisq: %f, new chisq %f, delta: %f, dLinear: %f, rho: %f, lambda: %g\n", min->value, Chisq, min->lastDelta, dLinear, rho, lambda); 512 540 513 541 // dump some useful info if trace is defined … … 580 608 } 581 609 610 /****************************************************************************** 611 psMinimizeLMChi2(): This routine takes a function-pointer (func) which calculates an arbitrary 612 function and it's derivatives and minimizes the chi-squared match between that function at the 613 specified points and the specified value at those points. 614 615 The original version of this function used a convergence criterion based on the change in 616 chisq. this has problems since it depends on the choice of points used to measure the fit. 617 (consider a gaussian on a background : it 100 pixels are used -- and some or most contribute to 618 the chisq -- and the delta-chisq is 10%, then the same change in model fit will yield a 619 delta-chisq of 1% if 1000 pixels are used (all but the 100 measuring the background)). 620 621 This implementation uses changes to the parameters and stops if they are no longer significant. 622 623 This requires F32 input data; all internal calls use F32. 624 *****************************************************************************/ 625 bool psMinimizeLMChi2_Alt( 626 psMinimization *min, 627 psImage *covar, 628 psVector *params, 629 psMinConstraint *constraint, 630 const psArray *x, 631 const psVector *y, 632 const psVector *yWt, 633 psMinimizeLMChi2Func func) 634 { 635 psTrace("psLib.math", 3, "---- begin ----\n"); 636 PS_ASSERT_PTR_NON_NULL(min, false); 637 PS_ASSERT_VECTOR_NON_NULL(params, false); 638 PS_ASSERT_VECTOR_NON_EMPTY(params, false); 639 PS_ASSERT_VECTOR_TYPE(params, PS_TYPE_F32, false); 640 psVector *paramMask = NULL; 641 if (constraint != NULL) { 642 paramMask = constraint->paramMask; 643 if (paramMask != NULL) { 644 PS_ASSERT_VECTOR_TYPE(paramMask, PS_TYPE_VECTOR_MASK, false); 645 PS_ASSERT_VECTORS_SIZE_EQUAL(params, paramMask, false); 646 } 647 } 648 PS_ASSERT_PTR_NON_NULL(x, false); 649 for (psS32 i = 0 ; i < x->n ; i++) { 650 psVector *coord = (psVector *) (x->data[i]); 651 PS_ASSERT_VECTOR_NON_NULL(coord, false); 652 PS_ASSERT_VECTOR_TYPE(coord, PS_TYPE_F32, false); 653 } 654 PS_ASSERT_VECTOR_NON_NULL(y, false); 655 PS_ASSERT_VECTOR_NON_EMPTY(y, false); 656 PS_ASSERT_VECTOR_TYPE(y, PS_TYPE_F32, false); 657 PS_ASSERT_VECTORS_SIZE_EQUAL(x, y, false); 658 if (yWt != NULL) { 659 PS_ASSERT_VECTOR_TYPE(yWt, PS_TYPE_F32, false); 660 PS_ASSERT_VECTORS_SIZE_EQUAL(y, yWt, false); 661 } 662 PS_ASSERT_PTR_NON_NULL(func, false); 663 664 psMinimizeLMLimitFunc checkLimits = NULL; 665 if (constraint) { 666 checkLimits = constraint->checkLimits; 667 } 668 669 // this function has test and current values for several things 670 // the current best value is in lower case 671 // the next guess value is in upper case 672 673 // allocate internal arrays (current vs Guess) 674 psImage *Alpha = NULL; 675 psVector *Beta = NULL; 676 677 // Alpha & Beta only contain elements to represent the unmasked parameters 678 if (!psMinLM_AllocAB (&Alpha, &Beta, params, paramMask)) { 679 psAbort ("programming error: no unmasked parameters to be fit\n"); 680 } 681 682 int nFitParams = Beta->n; 683 psImage *alpha = psImageAlloc(nFitParams, nFitParams, PS_TYPE_F32); 684 psVector *beta = psVectorAlloc(nFitParams, PS_TYPE_F32); 685 psVector *Params = psVectorAlloc(params->n, PS_TYPE_F32); 686 687 psVector *dy = NULL; 688 psF32 Chisq = 0.0; 689 psF32 lambda = 0.001; 690 psF32 dLinear = 0.0; 691 psF32 nu = 2.0; 692 693 // the user provides the error or NULL. we need to convert 694 // to appropriate weights 695 if (yWt != NULL) { 696 dy = (psVector *) yWt; 697 } else { 698 dy = psVectorAlloc(y->n, PS_TYPE_F32); 699 psVectorInit(dy, 1.0); 700 } 701 702 // number of degrees of freedom for this fit 703 int nDOF = dy->n - nFitParams; 704 705 // calculate initial alpha and beta, set chisq (min->value) 706 min->value = psMinLM_SetABX(alpha, beta, params, paramMask, x, y, dy, func); 707 if (isnan(min->value)) { 708 min->iter = min->maxIter; 709 psFree(alpha); 710 psFree(Alpha); 711 psFree(beta); 712 psFree(Beta); 713 psFree(Params); 714 return(false); 715 } 716 // dump some useful info if trace is defined 717 if (psTraceGetLevel("psLib.math") >= 6) { 718 p_psImagePrint(psTraceGetDestination(), alpha, "alpha guess (0)"); 719 p_psVectorPrint(psTraceGetDestination(), beta, "beta guess (0)"); 720 } 721 if (psTraceGetLevel("psLib.math") >= 5) { 722 p_psVectorPrint(psTraceGetDestination(), params, "params guess (0)"); 723 } 724 725 bool done = (min->iter >= min->maxIter); 726 while (!done) { 727 psTrace("psLib.math", 5, "Iteration number %d. (max iterations is %d).\n", min->iter, min->maxIter); 728 729 if (min->chisqConvergence) { 730 psTrace("psLib.math", 5, "Last delta is %f. stop if < %f, accept if < %f\n", min->lastDelta, min->minTol, min->maxTol); 731 } else { 732 psTrace("psLib.math", 5, "Last delta is %f. stop if < %f, accept if < %f\n", min->rParSigma, min->minTol*nFitParams, min->maxTol*nFitParams); 733 } 734 735 // set a new guess for Alpha, Beta, Params 736 if (!psMinLM_GuessABP(Alpha, Beta, Params, alpha, beta, params, paramMask, checkLimits, lambda, &dLinear)) { 737 min->iter ++; 738 if (min->iter >= min->maxIter) break; 739 lambda *= 10.0; 740 // ALT? lambda *= 2.0; 741 continue; 742 } 743 744 // dump some useful info if trace is defined 745 if (psTraceGetLevel("psLib.math") >= 6) { 746 p_psImagePrint(psTraceGetDestination(), Alpha, "Alpha guess (1)"); 747 p_psVectorPrint(psTraceGetDestination(), Beta, "Beta guess (1)"); 748 p_psVectorPrint(psTraceGetDestination(), beta, "beta current (1)"); 749 } 750 if (psTraceGetLevel("psLib.math") >= 5) { 751 p_psVectorPrint(psTraceGetDestination(), Params, "params guess (1)"); 752 } 753 754 // calculate the parameter change (rParDelta) and error radius (rParSigma) 755 // rParDelta : radius of parameter change; 756 // rParSigma : radius of parameter error 757 758 // note that (before SetABX) Alpha[i][i] is the covariance matrix and 759 // Beta is the actual parameter change for this pass 760 761 // note that Alpha & Beta only represent unmasked parameters, while params and Params have all 762 763 // dParSigma = Alpha[i][i] : error (squared) on parameter i 764 // dParDelta = Params->data.F32[i] - params->data.F32[i] : change on parameter i 765 float rParSigma = 0.0; 766 for (int j = 0, J = 0; j < Params->n; j++) { 767 if (paramMask && (paramMask->data.PS_TYPE_VECTOR_MASK_DATA[j])) { 768 continue; 769 } 770 rParSigma += PS_SQR(Params->data.F32[j] - params->data.F32[j]) / Alpha->data.F32[J][J]; 771 J++; 772 } 773 rParSigma = sqrt(rParSigma); 774 psTrace("psLib.math", 5, "rParSigma: %f, Niter: %d\n", rParSigma, min->iter); 775 // fprintf (stderr, "rParSigma: %f, Niter: %d\n", rParSigma, min->iter); 776 777 // calculate Chisq for new guess, update Alpha & Beta 778 Chisq = psMinLM_SetABX(Alpha, Beta, Params, paramMask, x, y, dy, func); 779 if (isnan(Chisq)) { 780 min->iter ++; 781 if (min->iter >= min->maxIter) break; 782 lambda *= 10.0; 783 // ALT lambda *= 2.0; 784 continue; 785 } 786 787 // convergence criterion: 788 // compare the delta (min->value - Chisq) with the 789 // expected delta from the linear model (dLinear) 790 // accept new guess if it is an improvement (rho > 0), or else increase lambda 791 psF32 rho = (min->value - Chisq) / dLinear; 792 793 psTrace("psLib.math", 5, "last chisq: %f, new chisq %f, delta: %f, dLinear: %f, rho: %f, lambda: %g, nDOF: %d\n", min->value, Chisq, min->lastDelta, dLinear, rho, lambda, nDOF); 794 795 psTrace("psLib.math.dLinear", 5, "last chisq: %f, new chisq %f, delta: %f, dLinear: %f, rho: %f, lambda: %g\n", min->value, Chisq, min->lastDelta, dLinear, rho, lambda); 796 797 // dump some useful info if trace is defined 798 if (psTraceGetLevel("psLib.math") >= 6) { 799 p_psImagePrint(psTraceGetDestination(), Alpha, "alpha guess (2)"); 800 p_psVectorPrint(psTraceGetDestination(), Beta, "beta guess (2)"); 801 } 802 803 // change in chisq/nDOF since last minimum 804 min->lastDelta = (min->value - Chisq) / nDOF; 805 806 // rho is positive if the new chisq is smaller; allow for some insignificant change (slight negative rho) 807 808 // XXX the old version of lambda changes: 809 // XXX : Madsen gives suggestion for better use of rho 810 // rho is positive if the new chisq is smaller 811 if (rho >= -1e-6) { 812 min->value = Chisq; 813 alpha = psImageCopy(alpha, Alpha, PS_TYPE_F32); 814 beta = psVectorCopy(beta, Beta, PS_TYPE_F32); 815 params = psVectorCopy(params, Params, PS_TYPE_F32); 816 } 817 switch (min->gainFactorMode) { 818 case 0: 819 if (rho >= -1e-6) { 820 lambda *= 0.25; 821 } else { 822 lambda *= 10.0; 823 } 824 break; 825 826 case 1: 827 // adjust the gain ratio (lambda) based on rho 828 if (rho < 0.25) { 829 lambda *= 2.0; 830 } 831 if (rho > 0.75) { 832 lambda *= 0.333; 833 } 834 break; 835 836 case 2: 837 if (rho > 0.0) { 838 lambda *= PS_MAX(0.33, (1.0 - pow(2.0*rho - 1.0, 3.0))); 839 nu = 2.0; 840 } else { 841 lambda *= nu; 842 nu *= 2.0; 843 } 844 break; 845 } 846 min->iter++; 847 848 // ending conditions: 849 // 1) hard limit : too many iterations 850 done = (min->iter >= min->maxIter); 851 852 // 2) require deltaChi > 1e-6 (ie, chisq is decreasing, but accept an insignificant change) 853 if (min->lastDelta < -1e-6) { 854 continue; 855 } 856 857 // save this value in case we stop iterating 858 min->rParSigma = rParSigma; 859 860 // 2) require chisqDOF < maxChisqDOF (if maxChisqDOF is not NAN) 861 // keep iterating regardless of rParSigma in this case 862 float chisqDOF = Chisq / nDOF; 863 if (isfinite(min->maxChisqDOF) && (chisqDOF > min->maxChisqDOF)) { 864 continue; 865 } 866 867 // delta-chisq or rParSigma ? 868 if (min->chisqConvergence) { 869 done |= (min->lastDelta < min->minTol); 870 } else { 871 done |= (rParSigma < min->minTol*nFitParams); 872 } 873 } 874 psTrace("psLib.math", 5, "chisq: %f, last delta: %f, rParSigma: %f, Niter: %d\n", min->value, min->lastDelta, min->rParSigma, min->iter); 875 876 // construct & return the covariance matrix (if requested) 877 if (covar != NULL) { 878 if (!psMinLM_GuessABP(Alpha, Beta, Params, alpha, beta, params, paramMask, NULL, 0.0, NULL)) { 879 psTrace ("psLib.math", 5, "failure to calculate covariance matrix\n"); 880 } 881 // set covar values which are not masked 882 psImageInit (covar, 0.0); 883 for (int j = 0, J = 0; j < params->n; j++) { 884 if (paramMask && (paramMask->data.PS_TYPE_VECTOR_MASK_DATA[j])) { 885 covar->data.F32[j][j] = 1.0; 886 continue; 887 } 888 for (int k = 0, K = 0; k < params->n; k++) { 889 if (paramMask && (paramMask->data.PS_TYPE_VECTOR_MASK_DATA[k])) continue; 890 covar->data.F32[j][k] = Alpha->data.F32[J][K]; 891 K++; 892 } 893 J++; 894 } 895 } 896 897 // free the internal temporary data 898 psFree(alpha); 899 psFree(Alpha); 900 psFree(beta); 901 psFree(Beta); 902 psFree(Params); 903 if (yWt == NULL) { 904 psFree(dy); 905 } 906 907 // if the last improvement was at least as good as maxTol, accept the fit: 908 if (min->chisqConvergence) { 909 if (min->lastDelta <= min->maxTol) { 910 psTrace("psLib.math", 6, "---- end (true) ----\n"); 911 return(true); 912 } 913 } else { 914 if (min->rParSigma <= min->maxTol*nFitParams) { 915 psTrace("psLib.math", 6, "---- end (true) ----\n"); 916 return(true); 917 } 918 } 919 psTrace("psLib.math", 6, "---- end (false) ----\n"); 920 return(false); 921 } 922 582 923 bool psMinLM_AllocAB (psImage **Alpha, psVector **Beta, const psVector *params, const psVector *paramMask) { 583 924 … … 625 966 min->iter = 0; 626 967 min->lastDelta = NAN; 968 min->rParSigma = NAN; 627 969 min->maxChisqDOF = NAN; 628 970 971 // we default to the old algorithm for convergence 972 min->chisqConvergence = true; 973 min->gainFactorMode = 0; 974 629 975 return(min); 630 976 } -
trunk/psLib/src/math/psMinimizeLMM.h
r28998 r35767 30 30 #include "psConstants.h" 31 31 32 # define PS_MINIMIZE_LMM_GAIN_FACTOR_MODE 0 33 # define PS_MINIMIZE_LMM_CHISQ_CONVERGENCE 1 34 32 35 #define PS_DETERMINE_BRACKET_STEP_SIZE 0.10 33 36 #define PS_MAX_LMM_ITERATIONS 100 … … 82 85 int iter; ///< Number of iterations to date 83 86 float lastDelta; ///< The last difference for the fit 87 float rParSigma; ///< last fractional change in the parameters 84 88 float maxChisqDOF; ///< for Chisq minimization, require that we reach here before checking tolerance 89 int gainFactorMode; 90 bool chisqConvergence; 85 91 } 86 92 psMinimization; … … 124 130 */ 125 131 bool psMinimizeLMChi2( 132 psMinimization *min, ///< Minimization specification 133 psImage *covar, ///< Covariance matrix 134 psVector *params, ///< "Best Guess" for the parameters that minimize func 135 psMinConstraint *constraint, ///< Constraints on the parameters 136 const psArray *x, ///< Measurement ordinates of multiple vectors 137 const psVector *y, ///< Measurement coordinates 138 const psVector *yWt, ///< Errors in the measurement coordinates 139 psMinimizeLMChi2Func func ///< Specified function 140 ); 141 142 /** Minimizes a specified function based on the Levenberg-Marquardt method. 143 * 144 * @return bool: True if successful. 145 */ 146 bool psMinimizeLMChi2_Old( 147 psMinimization *min, ///< Minimization specification 148 psImage *covar, ///< Covariance matrix 149 psVector *params, ///< "Best Guess" for the parameters that minimize func 150 psMinConstraint *constraint, ///< Constraints on the parameters 151 const psArray *x, ///< Measurement ordinates of multiple vectors 152 const psVector *y, ///< Measurement coordinates 153 const psVector *yWt, ///< Errors in the measurement coordinates 154 psMinimizeLMChi2Func func ///< Specified function 155 ); 156 157 /** Minimizes a specified function based on the Levenberg-Marquardt method 158 Uses alternative convergence criterion. 159 * 160 * @return bool: True if successful. 161 */ 162 bool psMinimizeLMChi2_Alt( 126 163 psMinimization *min, ///< Minimization specification 127 164 psImage *covar, ///< Covariance matrix -
trunk/psLib/test/imageops/Makefile.am
r32725 r35767 17 17 tap_psImagePixelManip \ 18 18 tap_psImageSmooth \ 19 tap_psImageSmoothMask_Threaded \ 19 20 tap_psImageSmooth_PreAlloc \ 20 21 tap_psImageStructManip \ -
trunk/psLib/test/math/Makefile.am
r28998 r35767 48 48 tap_psMatrixVectorArithmetic04 \ 49 49 tap_psMinimizePowell \ 50 tap_psMinimizeLMM \ 51 tap_psMinimizeLMM_Alt \ 52 tap_psMinimizeLMM_Trail \ 50 53 tap_psSpline1D \ 51 54 tap_psPolynomialMD \ -
trunk/psLib/test/pstap/src/pstap.h
r12738 r35767 144 144 } \ 145 145 } 146 147 # define ok_float is_float 148 # define ok_float_tol is_float_tol 149 # define ok_double is_double 150 # define ok_double_tol is_double_tol 151 # define ok_str is_str 152 # define ok_strn is_strn 153 # define ok_int is_int 154 # define ok_long is_long 155 # define ok_bool is_bool
Note:
See TracChangeset
for help on using the changeset viewer.
