File indexing completed on 2026-09-28 09:20:52
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef _MathRoot_MultipleUtils_HeaderFile
0015 #define _MathRoot_MultipleUtils_HeaderFile
0016
0017 #include <MathUtils_Types.hxx>
0018 #include <MathUtils_Config.hxx>
0019 #include <MathRoot_Brent.hxx>
0020 #include <math_Vector.hxx>
0021
0022 #include <NCollection_DynamicArray.hxx>
0023
0024 #include <algorithm>
0025 #include <cmath>
0026
0027
0028
0029
0030
0031
0032
0033 namespace MathRoot
0034 {
0035 using namespace MathUtils;
0036
0037
0038
0039
0040
0041
0042
0043 struct MultipleResult
0044 {
0045 MathUtils::Status Status = MathUtils::Status::NotConverged;
0046 size_t NbIterations = 0;
0047 NCollection_DynamicArray<double> Roots;
0048 NCollection_DynamicArray<double> Values;
0049 bool IsAllNull = false;
0050
0051
0052 bool IsDone() const { return Status == MathUtils::Status::OK; }
0053
0054
0055 explicit operator bool() const { return IsDone(); }
0056
0057
0058 int NbRoots() const { return Roots.Length(); }
0059
0060
0061 double operator[](int theIndex) const { return Roots.Value(theIndex); }
0062 };
0063
0064
0065 struct MultipleConfig
0066 {
0067 int NbSamples = 100;
0068 double XTolerance = 1e-10;
0069 double FTolerance = 1e-10;
0070 double NullTolerance = 1e-12;
0071 int MaxIterations = 100;
0072 double Offset = 0.0;
0073 };
0074
0075
0076
0077
0078
0079
0080 inline void SortRoots(MultipleResult& theResult)
0081 {
0082 for (int i = 1; i < theResult.Roots.Length(); ++i)
0083 {
0084 const double aKeyRoot = theResult.Roots[i];
0085 const double aKeyVal = theResult.Values[i];
0086 int j = i - 1;
0087 while (j >= 0 && theResult.Roots[j] > aKeyRoot)
0088 {
0089 theResult.Roots[j + 1] = theResult.Roots[j];
0090 theResult.Values[j + 1] = theResult.Values[j];
0091 --j;
0092 }
0093 theResult.Roots[j + 1] = aKeyRoot;
0094 theResult.Values[j + 1] = aKeyVal;
0095 }
0096 }
0097
0098
0099 inline void AddRoot(MultipleResult& theResult, double theEpsX, double theRoot, double theValue)
0100 {
0101 for (int k = 0; k < theResult.Roots.Length(); ++k)
0102 {
0103 if (std::abs(theRoot - theResult.Roots.Value(k)) < theEpsX)
0104 {
0105 return;
0106 }
0107 }
0108 theResult.Roots.Append(theRoot);
0109 theResult.Values.Append(theValue);
0110 }
0111
0112
0113 inline double EffectiveXTolerance(double theLower, double theUpper, double theXTolerance)
0114 {
0115 const double aMinEpsX = 1.0e-10 * (std::abs(theLower) + std::abs(theUpper));
0116 return std::max(theXTolerance, aMinEpsX);
0117 }
0118
0119
0120
0121
0122
0123
0124
0125 template <typename Function>
0126 struct MultipleSampleValueFn
0127 {
0128 Function& myFunc;
0129 math_Vector& mySamples;
0130 const double myOffset;
0131
0132 bool operator()(int theIndex, double theX) const
0133 {
0134 double aF = 0.0;
0135 if (!myFunc.Value(theX, aF))
0136 return false;
0137 mySamples(theIndex) = aF - myOffset;
0138 return true;
0139 }
0140 };
0141
0142
0143 struct MultipleGetValueFn
0144 {
0145 const math_Vector& mySamples;
0146
0147 double operator()(int theIndex) const { return mySamples(theIndex); }
0148 };
0149
0150
0151
0152 template <typename Function>
0153 struct MultipleBrentValueWrapper
0154 {
0155 Function& myFunc;
0156 double myOffset;
0157
0158 bool Value(double theX, double& theY) const
0159 {
0160 if (!myFunc.Value(theX, theY))
0161 return false;
0162 theY -= myOffset;
0163 return true;
0164 }
0165 };
0166
0167
0168
0169 template <typename Function>
0170 struct MultipleGetRootValueFn
0171 {
0172 Function& myFunc;
0173
0174 double operator()(double theX) const
0175 {
0176 double aF = 0.0;
0177 myFunc.Value(theX, aF);
0178 return aF;
0179 }
0180 };
0181
0182
0183
0184
0185
0186
0187
0188 template <typename Function>
0189 struct MultipleDerivativeValueWrapper
0190 {
0191 Function& myFunc;
0192
0193 bool Value(double theX, double& theY) const
0194 {
0195 double aF = 0.0;
0196 return myFunc.Values(theX, aF, theY);
0197 }
0198 };
0199
0200
0201
0202 template <typename Function>
0203 bool EvaluateValue(Function& theFunc, double theX, double& theValue)
0204 {
0205 return theFunc.Value(theX, theValue);
0206 }
0207
0208
0209
0210 template <typename Function>
0211 bool EvaluateShiftedValue(Function& theFunc, double theX, double theOffset, double& theValue)
0212 {
0213 if (!theFunc.Value(theX, theValue))
0214 {
0215 return false;
0216 }
0217
0218 theValue -= theOffset;
0219 return true;
0220 }
0221
0222
0223
0224 template <typename Function>
0225 bool EvaluateShiftedValues(Function& theFunc,
0226 double theX,
0227 double theOffset,
0228 double& theValue,
0229 double& theDerivative)
0230 {
0231 if (!theFunc.Values(theX, theValue, theDerivative))
0232 {
0233 return false;
0234 }
0235
0236 theValue -= theOffset;
0237 return true;
0238 }
0239
0240
0241
0242 template <typename Function>
0243 bool RefineBracketedRoot(Function& theFunc,
0244 double theOffset,
0245 double theX1,
0246 double theY1,
0247 double theX2,
0248 double theY2,
0249 double theTolerance,
0250 double theEpsX,
0251 MultipleResult& theResult)
0252 {
0253 constexpr int THE_MAX_ITERATIONS = 100;
0254 constexpr double THE_EPS2 = 2.0e-14;
0255 constexpr double THE_DERIV_EPS = 1.0e-10;
0256
0257 int anIter = 0;
0258 double aTol2 = 0.5 * theTolerance;
0259 double aA = theX1;
0260 double aB = theX2;
0261 double aC = theX2;
0262 double aD = 0.0;
0263 double anE = 0.0;
0264 double aFa = theY1;
0265 double aFb = theY2;
0266 double aFc = theY2;
0267
0268 for (anIter = 1; anIter <= THE_MAX_ITERATIONS; ++anIter)
0269 {
0270 if ((aFb > 0.0 && aFc > 0.0) || (aFb < 0.0 && aFc < 0.0))
0271 {
0272 aC = aA;
0273 aFc = aFa;
0274 anE = aD = aB - aA;
0275 }
0276
0277 if (std::abs(aFc) < std::abs(aFb))
0278 {
0279 const double aPrevA = aA;
0280 const double aPrevFa = aFa;
0281 aA = aB;
0282 aB = aC;
0283 aC = aPrevA;
0284 aFa = aFb;
0285 aFb = aFc;
0286 aFc = aPrevFa;
0287 }
0288
0289 const double aTol1 = THE_EPS2 * std::abs(aB) + aTol2;
0290 const double aXm = 0.5 * (aC - aB);
0291 if (std::abs(aXm) < aTol1 || aFb == 0.0)
0292 {
0293 double aNewtonX = aB;
0294 for (int aNewtonIter = 0; aNewtonIter < 5; ++aNewtonIter)
0295 {
0296 double aY = 0.0;
0297 double aDfdx = 0.0;
0298 if (!EvaluateShiftedValues(theFunc, aNewtonX, theOffset, aY, aDfdx))
0299 {
0300 return false;
0301 }
0302
0303 if (std::abs(aDfdx) <= THE_DERIV_EPS)
0304 {
0305 break;
0306 }
0307
0308 aNewtonX -= aY / aDfdx;
0309 if (aNewtonX < theX1 || aNewtonX > theX2)
0310 {
0311 break;
0312 }
0313
0314 if (!EvaluateShiftedValue(theFunc, aNewtonX, theOffset, aY))
0315 {
0316 return false;
0317 }
0318
0319 if (std::abs(aY) < std::abs(aFb))
0320 {
0321 aB = aNewtonX;
0322 aFb = aY;
0323 }
0324 }
0325
0326 double aRootValue = 0.0;
0327 if (!EvaluateValue(theFunc, aB, aRootValue))
0328 {
0329 return false;
0330 }
0331
0332 theResult.NbIterations += static_cast<size_t>(anIter);
0333 AddRoot(theResult, theEpsX, aB, aRootValue);
0334 return true;
0335 }
0336
0337 if (std::abs(anE) >= aTol1 && std::abs(aFa) > std::abs(aFb))
0338 {
0339 double aP = 0.0;
0340 double aQ = 0.0;
0341 const double aS = aFb / aFa;
0342 if (aA == aC)
0343 {
0344 aP = 2.0 * aXm * aS;
0345 aQ = 1.0 - aS;
0346 }
0347 else
0348 {
0349 aQ = aFa / aFc;
0350 const double aR = aFb / aFc;
0351 aP = aS * (2.0 * aXm * aQ * (aQ - aR) - (aB - aA) * (aR - 1.0));
0352 aQ = (aQ - 1.0) * (aR - 1.0) * (aS - 1.0);
0353 }
0354
0355 if (aP > 0.0)
0356 {
0357 aQ = -aQ;
0358 }
0359
0360 aP = std::abs(aP);
0361 const double aMin1 = 3.0 * aXm * aQ - std::abs(aTol1 * aQ);
0362 const double aMin2 = std::abs(anE * aQ);
0363 if (2.0 * aP < std::min(aMin1, aMin2))
0364 {
0365 anE = aD;
0366 aD = aP / aQ;
0367 }
0368 else
0369 {
0370 aD = aXm;
0371 anE = aD;
0372 }
0373 }
0374 else
0375 {
0376 aD = aXm;
0377 anE = aD;
0378 }
0379
0380 aA = aB;
0381 aFa = aFb;
0382 if (std::abs(aD) > aTol1)
0383 {
0384 aB += aD;
0385 }
0386 else
0387 {
0388 aB += (aXm >= 0.0) ? std::abs(aTol1) : -std::abs(aTol1);
0389 }
0390
0391 if (!EvaluateShiftedValue(theFunc, aB, theOffset, aFb))
0392 {
0393 return false;
0394 }
0395 }
0396
0397 theResult.NbIterations += THE_MAX_ITERATIONS;
0398 return true;
0399 }
0400
0401
0402
0403
0404 template <typename Function>
0405 MultipleResult FindAllRootsWithDerivativeImpl(Function& theFunc,
0406 double theLower,
0407 double theUpper,
0408 const MultipleConfig& theConfig)
0409 {
0410 MultipleResult aResult;
0411 aResult.Status = MathUtils::Status::OK;
0412
0413 const double aLower = std::min(theLower, theUpper);
0414 const double aUpper = std::max(theLower, theUpper);
0415 const int aNbSamples = std::max(2 * theConfig.NbSamples, 20);
0416 const double aDx = (aUpper - aLower) / aNbSamples;
0417 const double aEpsX = EffectiveXTolerance(aLower, aUpper, theConfig.XTolerance);
0418 const double aRawXTolerance = theConfig.XTolerance;
0419 const double aMajorDx = 5.0 * aDx;
0420
0421 math_Vector aValues(0, aNbSamples);
0422 double aX = aLower;
0423 for (int i = 0; i <= aNbSamples; ++i, aX += aDx)
0424 {
0425 if (aX > aUpper)
0426 {
0427 aX = aUpper;
0428 }
0429
0430 if (!EvaluateShiftedValue(theFunc, aX, theConfig.Offset, aValues(i)))
0431 {
0432 aResult.Status = MathUtils::Status::NumericalError;
0433 return aResult;
0434 }
0435 }
0436
0437 aResult.IsAllNull = true;
0438 for (int i = 0; i <= aNbSamples; ++i)
0439 {
0440 if (aValues(i) > theConfig.NullTolerance || aValues(i) < -theConfig.NullTolerance)
0441 {
0442 aResult.IsAllNull = false;
0443 break;
0444 }
0445 }
0446 if (aResult.IsAllNull)
0447 {
0448 return aResult;
0449 }
0450
0451 const double aTolerance = aEpsX;
0452 double aX1 = aLower;
0453 for (int i = 0, anIp1 = 1; i < aNbSamples; ++i, ++anIp1, aX1 += aDx)
0454 {
0455 double aX2 = aX1 + aDx;
0456 if (aX2 > aUpper)
0457 {
0458 aX2 = aUpper;
0459 }
0460
0461 if ((aValues(i) < 0.0 && aValues(anIp1) > 0.0) || (aValues(i) > 0.0 && aValues(anIp1) < 0.0))
0462 {
0463 if (!RefineBracketedRoot(theFunc,
0464 theConfig.Offset,
0465 aX1,
0466 aValues(i),
0467 aX2,
0468 aValues(anIp1),
0469 aTolerance,
0470 aEpsX,
0471 aResult))
0472 {
0473 aResult.Status = MathUtils::Status::NumericalError;
0474 return aResult;
0475 }
0476 }
0477 }
0478
0479 for (int i = 0; i <= aNbSamples; ++i)
0480 {
0481 if (aValues(i) != 0.0)
0482 {
0483 continue;
0484 }
0485
0486 const double aZeroX = std::min(aLower + i * aDx, aUpper);
0487 double aLeftX = aZeroX - 0.5 * aDx;
0488 double aRightX = aZeroX + 0.5 * aDx;
0489 if (aLeftX < aLower)
0490 {
0491 aLeftX = aLower;
0492 }
0493 if (aLeftX > aUpper)
0494 {
0495 aLeftX = aUpper;
0496 }
0497 if (aRightX < aLower)
0498 {
0499 aRightX = aLower;
0500 }
0501 if (aRightX > aUpper)
0502 {
0503 aRightX = aUpper;
0504 }
0505
0506 double aLeftY = 0.0;
0507 double aRightY = 0.0;
0508 if (!EvaluateShiftedValue(theFunc, aLeftX, theConfig.Offset, aLeftY)
0509 || !EvaluateShiftedValue(theFunc, aRightX, theConfig.Offset, aRightY))
0510 {
0511 aResult.Status = MathUtils::Status::NumericalError;
0512 return aResult;
0513 }
0514
0515 if (aLeftY * aRightY < 0.0)
0516 {
0517 if (!RefineBracketedRoot(theFunc,
0518 theConfig.Offset,
0519 aLeftX,
0520 aLeftY,
0521 aRightX,
0522 aRightY,
0523 aTolerance,
0524 aEpsX,
0525 aResult))
0526 {
0527 aResult.Status = MathUtils::Status::NumericalError;
0528 return aResult;
0529 }
0530 }
0531 else if (aLeftY != 0.0 || aRightY != 0.0)
0532 {
0533 double aRootValue = 0.0;
0534 if (!EvaluateValue(theFunc, aZeroX, aRootValue))
0535 {
0536 aResult.Status = MathUtils::Status::NumericalError;
0537 return aResult;
0538 }
0539 AddRoot(aResult, aEpsX, aZeroX, aRootValue);
0540 }
0541 }
0542
0543 if (aValues(0) <= theConfig.FTolerance && aValues(0) >= -theConfig.FTolerance)
0544 {
0545 double aRootValue = 0.0;
0546 if (!EvaluateValue(theFunc, aLower, aRootValue))
0547 {
0548 aResult.Status = MathUtils::Status::NumericalError;
0549 return aResult;
0550 }
0551 AddRoot(aResult, aEpsX, aLower, aRootValue);
0552 }
0553
0554 if (aValues(aNbSamples) <= theConfig.FTolerance && aValues(aNbSamples) >= -theConfig.FTolerance)
0555 {
0556 double aRootValue = 0.0;
0557 if (!EvaluateValue(theFunc, aUpper, aRootValue))
0558 {
0559 aResult.Status = MathUtils::Status::NumericalError;
0560 return aResult;
0561 }
0562 AddRoot(aResult, aEpsX, aUpper, aRootValue);
0563 }
0564
0565 int anIm1 = 0;
0566 int anIp1 = 2;
0567 double aMidX = aLower + aDx;
0568 for (int i = 1; i < aNbSamples; ++i, ++anIm1, ++anIp1, aMidX += aDx)
0569 {
0570 if (aMidX > aUpper)
0571 {
0572 aMidX = aUpper;
0573 }
0574
0575 bool isRediscretize = false;
0576 if (aValues(i) > 0.0)
0577 {
0578 if (aValues(anIm1) > aValues(i) && aValues(anIp1) > aValues(i))
0579 {
0580 double aProbeX = std::max(aLower, aMidX - aDx);
0581 double aProbeY = 0.0;
0582 double aProbeDy = 0.0;
0583 if (!EvaluateShiftedValues(theFunc, aProbeX, theConfig.Offset, aProbeY, aProbeDy))
0584 {
0585 aResult.Status = MathUtils::Status::NumericalError;
0586 return aResult;
0587 }
0588
0589 if (std::abs(aProbeDy) > 1.0e-10)
0590 {
0591 const double aStep = aProbeY / aProbeDy;
0592 if (aStep < aMajorDx && aStep > -aMajorDx)
0593 {
0594 isRediscretize = true;
0595 }
0596 }
0597
0598 if (!isRediscretize)
0599 {
0600 aProbeX = std::min(aUpper, aMidX + aDx);
0601 if (!EvaluateShiftedValues(theFunc, aProbeX, theConfig.Offset, aProbeY, aProbeDy))
0602 {
0603 aResult.Status = MathUtils::Status::NumericalError;
0604 return aResult;
0605 }
0606
0607 if (std::abs(aProbeDy) > 1.0e-10)
0608 {
0609 const double aStep = aProbeY / aProbeDy;
0610 if (aStep < aMajorDx && aStep > -aMajorDx)
0611 {
0612 isRediscretize = true;
0613 }
0614 }
0615 }
0616 }
0617 }
0618 else if (aValues(i) < 0.0)
0619 {
0620 if (aValues(anIm1) < aValues(i) && aValues(anIp1) < aValues(i))
0621 {
0622 double aProbeX = std::max(aLower, aMidX - aDx);
0623 double aProbeY = 0.0;
0624 double aProbeDy = 0.0;
0625 if (!EvaluateShiftedValues(theFunc, aProbeX, theConfig.Offset, aProbeY, aProbeDy))
0626 {
0627 aResult.Status = MathUtils::Status::NumericalError;
0628 return aResult;
0629 }
0630
0631 if (std::abs(aProbeDy) > 1.0e-10)
0632 {
0633 const double aStep = aProbeY / aProbeDy;
0634 if (aStep < aMajorDx && aStep > -aMajorDx)
0635 {
0636 isRediscretize = true;
0637 }
0638 }
0639
0640 if (!isRediscretize)
0641 {
0642 aProbeX = std::min(aUpper, aMidX + aDx);
0643 if (!EvaluateShiftedValues(theFunc, aProbeX, theConfig.Offset, aProbeY, aProbeDy))
0644 {
0645 aResult.Status = MathUtils::Status::NumericalError;
0646 return aResult;
0647 }
0648
0649 if (std::abs(aProbeDy) > 1.0e-10)
0650 {
0651 const double aStep = aProbeY / aProbeDy;
0652 if (aStep < aMajorDx && aStep > -aMajorDx)
0653 {
0654 isRediscretize = true;
0655 }
0656 }
0657 }
0658 }
0659 }
0660
0661 if (!isRediscretize)
0662 {
0663 continue;
0664 }
0665
0666 double aX0 = std::max(aLower, aMidX - aDx);
0667 double aX3 = std::min(aUpper, aMidX + aDx);
0668 double aRoot1 = 0.0;
0669 double aRoot2 = 0.0;
0670 double aVal1 = 0.0;
0671 double aVal2 = 0.0;
0672 double aDer1 = 0.0;
0673 double aDer2 = 0.0;
0674 bool hasRoot1 = false;
0675 bool hasRoot2 = false;
0676
0677 MultipleDerivativeValueWrapper<Function> aDerivativeWrapper{theFunc};
0678 MathUtils::Config aDerivativeConfig;
0679 aDerivativeConfig.XTolerance = aRawXTolerance;
0680 aDerivativeConfig.FTolerance = 0.0;
0681 aDerivativeConfig.MaxIterations = theConfig.MaxIterations;
0682
0683 MathUtils::ScalarResult aDerivativeRoot =
0684 Brent(aDerivativeWrapper, aX0, aX3, aDerivativeConfig);
0685 aResult.NbIterations += aDerivativeRoot.NbIterations;
0686 if (aDerivativeRoot.IsDone() && aDerivativeRoot.Root.has_value())
0687 {
0688 aRoot1 = *aDerivativeRoot.Root;
0689 double aOriginalValue = 0.0;
0690 if (!EvaluateValue(theFunc, aRoot1, aOriginalValue))
0691 {
0692 aResult.Status = MathUtils::Status::NumericalError;
0693 return aResult;
0694 }
0695 aVal1 = std::abs(aOriginalValue - theConfig.Offset);
0696 if (aVal1 < theConfig.FTolerance)
0697 {
0698 hasRoot1 = true;
0699 if (!EvaluateShiftedValues(theFunc, aRoot1, theConfig.Offset, aOriginalValue, aDer1))
0700 {
0701 aResult.Status = MathUtils::Status::NumericalError;
0702 return aResult;
0703 }
0704 }
0705 }
0706
0707 double aXProbe1 = 0.0;
0708 double aXProbe2 = 0.0;
0709 constexpr double THE_GOLDEN_INV_RATIO = 1.0 / MathUtils::THE_GOLDEN_RATIO;
0710 constexpr double THE_GOLDEN_INV_COMP = 1.0 - THE_GOLDEN_INV_RATIO;
0711 const double aTolCR = aEpsX * 10.0;
0712 const double aLocalTolX = 0.001 * aEpsX;
0713 double aF0 = aValues(anIm1);
0714 double aF3 = aValues(anIp1);
0715 const bool isSearchMinimum = (aF0 > 0.0);
0716
0717 if (std::abs(aX3 - aMidX) > std::abs(aX0 - aMidX))
0718 {
0719 aXProbe1 = aMidX;
0720 aXProbe2 = aMidX + THE_GOLDEN_INV_COMP * (aX3 - aMidX);
0721 }
0722 else
0723 {
0724 aXProbe2 = aMidX;
0725 aXProbe1 = aMidX - THE_GOLDEN_INV_COMP * (aMidX - aX0);
0726 }
0727
0728 double aF1 = 0.0;
0729 double aF2 = 0.0;
0730 if (!EvaluateShiftedValue(theFunc, aXProbe1, theConfig.Offset, aF1)
0731 || !EvaluateShiftedValue(theFunc, aXProbe2, theConfig.Offset, aF2))
0732 {
0733 aResult.Status = MathUtils::Status::NumericalError;
0734 return aResult;
0735 }
0736
0737 while (std::abs(aX3 - aX0) > aTolCR * (std::abs(aXProbe1) + std::abs(aXProbe2))
0738 && std::abs(aXProbe1 - aXProbe2) > aLocalTolX)
0739 {
0740 if (isSearchMinimum)
0741 {
0742 if (aF2 < aF1)
0743 {
0744 aX0 = aXProbe1;
0745 aXProbe1 = aXProbe2;
0746 aXProbe2 = THE_GOLDEN_INV_RATIO * aXProbe1 + THE_GOLDEN_INV_COMP * aX3;
0747 aF0 = aF1;
0748 aF1 = aF2;
0749 if (!EvaluateShiftedValue(theFunc, aXProbe2, theConfig.Offset, aF2))
0750 {
0751 aResult.Status = MathUtils::Status::NumericalError;
0752 return aResult;
0753 }
0754 }
0755 else
0756 {
0757 aX3 = aXProbe2;
0758 aXProbe2 = aXProbe1;
0759 aXProbe1 = THE_GOLDEN_INV_RATIO * aXProbe2 + THE_GOLDEN_INV_COMP * aX0;
0760 aF3 = aF2;
0761 aF2 = aF1;
0762 if (!EvaluateShiftedValue(theFunc, aXProbe1, theConfig.Offset, aF1))
0763 {
0764 aResult.Status = MathUtils::Status::NumericalError;
0765 return aResult;
0766 }
0767 }
0768 }
0769 else
0770 {
0771 if (aF2 > aF1)
0772 {
0773 aX0 = aXProbe1;
0774 aXProbe1 = aXProbe2;
0775 aXProbe2 = THE_GOLDEN_INV_RATIO * aXProbe1 + THE_GOLDEN_INV_COMP * aX3;
0776 aF0 = aF1;
0777 aF1 = aF2;
0778 if (!EvaluateShiftedValue(theFunc, aXProbe2, theConfig.Offset, aF2))
0779 {
0780 aResult.Status = MathUtils::Status::NumericalError;
0781 return aResult;
0782 }
0783 }
0784 else
0785 {
0786 aX3 = aXProbe2;
0787 aXProbe2 = aXProbe1;
0788 aXProbe1 = THE_GOLDEN_INV_RATIO * aXProbe2 + THE_GOLDEN_INV_COMP * aX0;
0789 aF3 = aF2;
0790 aF2 = aF1;
0791 if (!EvaluateShiftedValue(theFunc, aXProbe1, theConfig.Offset, aF1))
0792 {
0793 aResult.Status = MathUtils::Status::NumericalError;
0794 return aResult;
0795 }
0796 }
0797 }
0798
0799 if (aF1 * aF0 < 0.0)
0800 {
0801 if (!RefineBracketedRoot(theFunc,
0802 theConfig.Offset,
0803 aX0,
0804 aF0,
0805 aXProbe1,
0806 aF1,
0807 aTolerance,
0808 aEpsX,
0809 aResult))
0810 {
0811 aResult.Status = MathUtils::Status::NumericalError;
0812 return aResult;
0813 }
0814 }
0815
0816 if (aF2 * aF3 < 0.0)
0817 {
0818 if (!RefineBracketedRoot(theFunc,
0819 theConfig.Offset,
0820 aXProbe2,
0821 aF2,
0822 aX3,
0823 aF3,
0824 aTolerance,
0825 aEpsX,
0826 aResult))
0827 {
0828 aResult.Status = MathUtils::Status::NumericalError;
0829 return aResult;
0830 }
0831 }
0832 }
0833
0834 if ((isSearchMinimum && aF1 < aF2) || (!isSearchMinimum && aF1 > aF2))
0835 {
0836 if (std::abs(aF1) < theConfig.FTolerance)
0837 {
0838 hasRoot2 = true;
0839 aRoot2 = aXProbe1;
0840 aVal2 = std::abs(aF1);
0841 }
0842 }
0843 else if (std::abs(aF2) < theConfig.FTolerance)
0844 {
0845 hasRoot2 = true;
0846 aRoot2 = aXProbe2;
0847 aVal2 = std::abs(aF2);
0848 }
0849
0850 if (hasRoot1 && hasRoot2)
0851 {
0852 if (aVal2 - aVal1 > theConfig.FTolerance)
0853 {
0854 double aRootValue = 0.0;
0855 if (!EvaluateValue(theFunc, aRoot1, aRootValue))
0856 {
0857 aResult.Status = MathUtils::Status::NumericalError;
0858 return aResult;
0859 }
0860 AddRoot(aResult, aEpsX, aRoot1, aRootValue);
0861 }
0862 else if (aVal1 - aVal2 > theConfig.FTolerance)
0863 {
0864 double aRootValue = 0.0;
0865 if (!EvaluateValue(theFunc, aRoot2, aRootValue))
0866 {
0867 aResult.Status = MathUtils::Status::NumericalError;
0868 return aResult;
0869 }
0870 AddRoot(aResult, aEpsX, aRoot2, aRootValue);
0871 }
0872 else
0873 {
0874 double aShiftedValue = 0.0;
0875 if (!EvaluateShiftedValues(theFunc, aRoot2, theConfig.Offset, aShiftedValue, aDer2))
0876 {
0877 aResult.Status = MathUtils::Status::NumericalError;
0878 return aResult;
0879 }
0880
0881 const double aChosenRoot = (std::abs(aDer1) < std::abs(aDer2)) ? aRoot1 : aRoot2;
0882 double aRootValue = 0.0;
0883 if (!EvaluateValue(theFunc, aChosenRoot, aRootValue))
0884 {
0885 aResult.Status = MathUtils::Status::NumericalError;
0886 return aResult;
0887 }
0888 AddRoot(aResult, aEpsX, aChosenRoot, aRootValue);
0889 }
0890 }
0891 else if (hasRoot1)
0892 {
0893 double aRootValue = 0.0;
0894 if (!EvaluateValue(theFunc, aRoot1, aRootValue))
0895 {
0896 aResult.Status = MathUtils::Status::NumericalError;
0897 return aResult;
0898 }
0899 AddRoot(aResult, aEpsX, aRoot1, aRootValue);
0900 }
0901 else if (hasRoot2)
0902 {
0903 double aRootValue = 0.0;
0904 if (!EvaluateValue(theFunc, aRoot2, aRootValue))
0905 {
0906 aResult.Status = MathUtils::Status::NumericalError;
0907 return aResult;
0908 }
0909 AddRoot(aResult, aEpsX, aRoot2, aRootValue);
0910 }
0911 }
0912
0913 SortRoots(aResult);
0914 return aResult;
0915 }
0916
0917
0918
0919
0920
0921
0922 struct MultipleNoExtraHandler
0923 {
0924 void operator()(int, double, double, double, double, MultipleResult&, double) const {}
0925 };
0926
0927
0928
0929
0930
0931
0932
0933
0934
0935
0936
0937
0938
0939 template <typename SampleFn,
0940 typename GetValueFn,
0941 typename BrentWrapperT,
0942 typename GetRootValueFn,
0943 typename IntervalExtraFn>
0944 MultipleResult FindAllRootsImpl(double theLower,
0945 double theUpper,
0946 const MultipleConfig& theConfig,
0947 SampleFn theSampleFn,
0948 GetValueFn theGetValue,
0949 BrentWrapperT& theBrentWrapper,
0950 GetRootValueFn theGetRootValue,
0951 IntervalExtraFn theIntervalExtra)
0952 {
0953 MultipleResult aResult;
0954 aResult.Status = MathUtils::Status::OK;
0955
0956
0957 const double aLower = std::min(theLower, theUpper);
0958 const double aUpper = std::max(theLower, theUpper);
0959
0960
0961 const int aNbSamples = std::max(2 * theConfig.NbSamples, 20);
0962 const double aDx = (aUpper - aLower) / aNbSamples;
0963
0964
0965 const double aEpsX = EffectiveXTolerance(aLower, aUpper, theConfig.XTolerance);
0966
0967
0968 math_Vector aXValues(0, aNbSamples);
0969 for (int i = 0; i <= aNbSamples; ++i)
0970 {
0971 double aX = aLower + i * aDx;
0972 if (aX > aUpper)
0973 aX = aUpper;
0974 aXValues(i) = aX;
0975
0976 if (!theSampleFn(i, aX))
0977 {
0978 aResult.Status = MathUtils::Status::NumericalError;
0979 return aResult;
0980 }
0981 }
0982
0983
0984 aResult.IsAllNull = true;
0985 for (int i = 0; i <= aNbSamples; ++i)
0986 {
0987 if (std::abs(theGetValue(i)) > theConfig.NullTolerance)
0988 {
0989 aResult.IsAllNull = false;
0990 break;
0991 }
0992 }
0993
0994 if (aResult.IsAllNull)
0995 {
0996 return aResult;
0997 }
0998
0999
1000 for (int i = 0; i < aNbSamples; ++i)
1001 {
1002 const double aF0 = theGetValue(i);
1003 const double aF1 = theGetValue(i + 1);
1004 const double aX0 = aXValues(i);
1005 const double aX1 = aXValues(i + 1);
1006
1007
1008 if (std::abs(aF0) < theConfig.FTolerance)
1009 {
1010 AddRoot(aResult, aEpsX, aX0, aF0 + theConfig.Offset);
1011 continue;
1012 }
1013
1014
1015 if (aF0 * aF1 < 0.0)
1016 {
1017 MathUtils::Config aBrentConfig;
1018 aBrentConfig.XTolerance = aEpsX;
1019 aBrentConfig.FTolerance = theConfig.FTolerance;
1020 aBrentConfig.MaxIterations = theConfig.MaxIterations;
1021
1022 MathUtils::ScalarResult aBrentResult = Brent(theBrentWrapper, aX0, aX1, aBrentConfig);
1023 aResult.NbIterations += aBrentResult.NbIterations;
1024
1025 if (aBrentResult.IsDone() && aBrentResult.Root.has_value())
1026 {
1027 AddRoot(aResult, aEpsX, *aBrentResult.Root, theGetRootValue(*aBrentResult.Root));
1028 }
1029 }
1030 else
1031 {
1032
1033 theIntervalExtra(i, aX0, aX1, aF0, aF1, aResult, aEpsX);
1034 }
1035 }
1036
1037
1038 if (std::abs(theGetValue(aNbSamples)) < theConfig.FTolerance)
1039 {
1040 AddRoot(aResult, aEpsX, aXValues(aNbSamples), theGetValue(aNbSamples) + theConfig.Offset);
1041 }
1042
1043 SortRoots(aResult);
1044 return aResult;
1045 }
1046
1047 }
1048
1049 #endif