File indexing completed on 2026-09-28 09:20:53
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef _MathUtils_Bracket_HeaderFile
0015 #define _MathUtils_Bracket_HeaderFile
0016
0017 #include <MathUtils_Core.hxx>
0018
0019 #include <algorithm>
0020 #include <cmath>
0021 #include <utility>
0022
0023
0024 namespace MathUtils
0025 {
0026
0027
0028 struct BracketResult
0029 {
0030 bool IsValid = false;
0031 double A = 0.0;
0032 double B = 0.0;
0033 double Fa = 0.0;
0034 double Fb = 0.0;
0035 };
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045 template <typename Function>
0046 BracketResult BracketRoot(Function& theFunc, double theA, double theB, int theMaxIter = 50)
0047 {
0048 BracketResult aResult;
0049 aResult.A = theA;
0050 aResult.B = theB;
0051
0052 if (!theFunc.Value(aResult.A, aResult.Fa))
0053 {
0054 return aResult;
0055 }
0056 if (!theFunc.Value(aResult.B, aResult.Fb))
0057 {
0058 return aResult;
0059 }
0060
0061 for (int i = 0; i < theMaxIter; ++i)
0062 {
0063 if (aResult.Fa * aResult.Fb < 0.0)
0064 {
0065 aResult.IsValid = true;
0066
0067 if (aResult.A > aResult.B)
0068 {
0069 std::swap(aResult.A, aResult.B);
0070 std::swap(aResult.Fa, aResult.Fb);
0071 }
0072 return aResult;
0073 }
0074
0075
0076 if (std::abs(aResult.Fa) < std::abs(aResult.Fb))
0077 {
0078 aResult.A += THE_GOLDEN_RATIO * (aResult.A - aResult.B);
0079 if (!theFunc.Value(aResult.A, aResult.Fa))
0080 {
0081 return aResult;
0082 }
0083 }
0084 else
0085 {
0086 aResult.B += THE_GOLDEN_RATIO * (aResult.B - aResult.A);
0087 if (!theFunc.Value(aResult.B, aResult.Fb))
0088 {
0089 return aResult;
0090 }
0091 }
0092 }
0093
0094 return aResult;
0095 }
0096
0097
0098 struct MinBracketResult
0099 {
0100 bool IsValid = false;
0101 double A = 0.0;
0102 double B = 0.0;
0103 double C = 0.0;
0104 double Fa = 0.0;
0105 double Fb = 0.0;
0106 double Fc = 0.0;
0107 };
0108
0109
0110 struct MinBracketOptions
0111 {
0112 int MaxIterations = 50;
0113 bool UseLimits = false;
0114 double LeftLimit = 0.0;
0115 double RightLimit = 0.0;
0116 bool HasFA = false;
0117 bool HasFB = false;
0118 double FA = 0.0;
0119 double FB = 0.0;
0120 };
0121
0122 namespace detail
0123 {
0124 inline double Limited(double theValue, const MinBracketOptions& theOptions)
0125 {
0126 if (!theOptions.UseLimits)
0127 {
0128 return theValue;
0129 }
0130 return std::max(theOptions.LeftLimit, std::min(theOptions.RightLimit, theValue));
0131 }
0132
0133 template <typename Function>
0134 bool LimitAndMayBeSwap(Function& theFunc,
0135 const MinBracketOptions& theOptions,
0136 const double theA,
0137 double& theB,
0138 double& theFB,
0139 double& theC,
0140 double& theFC)
0141 {
0142 theC = Limited(theC, theOptions);
0143 if (std::abs(theB - theC) < THE_ZERO_TOL)
0144 {
0145 return false;
0146 }
0147 if (!theFunc.Value(theC, theFC))
0148 {
0149 return false;
0150 }
0151
0152
0153 if ((theA - theB) * (theB - theC) < 0.0)
0154 {
0155 std::swap(theB, theC);
0156 std::swap(theFB, theFC);
0157 }
0158 return true;
0159 }
0160 }
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170 template <typename Function>
0171 MinBracketResult BracketMinimum(Function& theFunc,
0172 double theA,
0173 double theB,
0174 const MinBracketOptions& theOptions = MinBracketOptions())
0175 {
0176 MinBracketResult aResult;
0177 if (theOptions.MaxIterations < 1)
0178 {
0179 return aResult;
0180 }
0181 if (theOptions.UseLimits && theOptions.LeftLimit > theOptions.RightLimit)
0182 {
0183 return aResult;
0184 }
0185
0186 aResult.A = detail::Limited(theA, theOptions);
0187 aResult.B = detail::Limited(theB, theOptions);
0188 if (std::abs(aResult.A - aResult.B) < THE_ZERO_TOL)
0189 {
0190 return aResult;
0191 }
0192
0193 const bool isUseFA =
0194 theOptions.HasFA && (!theOptions.UseLimits || std::abs(aResult.A - theA) < THE_ZERO_TOL);
0195 const bool isUseFB =
0196 theOptions.HasFB && (!theOptions.UseLimits || std::abs(aResult.B - theB) < THE_ZERO_TOL);
0197
0198 if (isUseFA)
0199 {
0200 aResult.Fa = theOptions.FA;
0201 }
0202 else if (!theFunc.Value(aResult.A, aResult.Fa))
0203 {
0204 return aResult;
0205 }
0206
0207 if (isUseFB)
0208 {
0209 aResult.Fb = theOptions.FB;
0210 }
0211 else if (!theFunc.Value(aResult.B, aResult.Fb))
0212 {
0213 return aResult;
0214 }
0215
0216
0217 if (aResult.Fb > aResult.Fa)
0218 {
0219 std::swap(aResult.A, aResult.B);
0220 std::swap(aResult.Fa, aResult.Fb);
0221 }
0222
0223
0224 aResult.C = aResult.B + THE_GOLDEN_RATIO * (aResult.B - aResult.A);
0225 if (theOptions.UseLimits)
0226 {
0227 if (!detail::LimitAndMayBeSwap(theFunc,
0228 theOptions,
0229 aResult.A,
0230 aResult.B,
0231 aResult.Fb,
0232 aResult.C,
0233 aResult.Fc))
0234 {
0235 return aResult;
0236 }
0237 }
0238 else if (!theFunc.Value(aResult.C, aResult.Fc))
0239 {
0240 return aResult;
0241 }
0242
0243
0244 for (int anIter = 0; anIter < theOptions.MaxIterations && aResult.Fb >= aResult.Fc; ++anIter)
0245 {
0246
0247 const double aR = (aResult.B - aResult.A) * (aResult.Fb - aResult.Fc);
0248 const double aQ = (aResult.B - aResult.C) * (aResult.Fb - aResult.Fa);
0249 const double aDenom = 2.0 * SignTransfer(std::max(std::abs(aQ - aR), THE_ZERO_TOL), aQ - aR);
0250
0251 double aU = aResult.B - ((aResult.B - aResult.C) * aQ - (aResult.B - aResult.A) * aR) / aDenom;
0252
0253 double aULim = aResult.B + 100.0 * (aResult.C - aResult.B);
0254 if (theOptions.UseLimits)
0255 {
0256 aULim = detail::Limited(aULim, theOptions);
0257 }
0258 double aFu = 0.0;
0259
0260 if ((aResult.B - aU) * (aU - aResult.C) > 0.0)
0261 {
0262
0263 if (!theFunc.Value(aU, aFu))
0264 {
0265 return aResult;
0266 }
0267
0268 if (aFu < aResult.Fc)
0269 {
0270 aResult.A = aResult.B;
0271 aResult.B = aU;
0272 aResult.Fa = aResult.Fb;
0273 aResult.Fb = aFu;
0274 aResult.IsValid = true;
0275 return aResult;
0276 }
0277 else if (aFu > aResult.Fb)
0278 {
0279 aResult.C = aU;
0280 aResult.Fc = aFu;
0281 aResult.IsValid = true;
0282 return aResult;
0283 }
0284
0285
0286 aU = aResult.C + THE_GOLDEN_RATIO * (aResult.C - aResult.B);
0287 if (theOptions.UseLimits)
0288 {
0289 if (!detail::LimitAndMayBeSwap(theFunc,
0290 theOptions,
0291 aResult.B,
0292 aResult.C,
0293 aResult.Fc,
0294 aU,
0295 aFu))
0296 {
0297 return aResult;
0298 }
0299 }
0300 else if (!theFunc.Value(aU, aFu))
0301 {
0302 return aResult;
0303 }
0304 }
0305 else if ((aResult.C - aU) * (aU - aULim) > 0.0)
0306 {
0307
0308 if (theOptions.UseLimits)
0309 {
0310 if (!detail::LimitAndMayBeSwap(theFunc,
0311 theOptions,
0312 aResult.B,
0313 aResult.C,
0314 aResult.Fc,
0315 aU,
0316 aFu))
0317 {
0318 return aResult;
0319 }
0320 }
0321 else if (!theFunc.Value(aU, aFu))
0322 {
0323 return aResult;
0324 }
0325
0326 if (aFu < aResult.Fc)
0327 {
0328 aResult.B = aResult.C;
0329 aResult.C = aU;
0330 aU = aResult.C + THE_GOLDEN_RATIO * (aResult.C - aResult.B);
0331 aResult.Fb = aResult.Fc;
0332 aResult.Fc = aFu;
0333 if (theOptions.UseLimits)
0334 {
0335 if (!detail::LimitAndMayBeSwap(theFunc,
0336 theOptions,
0337 aResult.B,
0338 aResult.C,
0339 aResult.Fc,
0340 aU,
0341 aFu))
0342 {
0343 return aResult;
0344 }
0345 }
0346 else if (!theFunc.Value(aU, aFu))
0347 {
0348 return aResult;
0349 }
0350 }
0351 }
0352 else if ((aU - aULim) * (aULim - aResult.C) >= 0.0)
0353 {
0354
0355 aU = aULim;
0356 if (theOptions.UseLimits)
0357 {
0358 if (!detail::LimitAndMayBeSwap(theFunc,
0359 theOptions,
0360 aResult.B,
0361 aResult.C,
0362 aResult.Fc,
0363 aU,
0364 aFu))
0365 {
0366 return aResult;
0367 }
0368 }
0369 else if (!theFunc.Value(aU, aFu))
0370 {
0371 return aResult;
0372 }
0373 }
0374 else
0375 {
0376
0377 aU = aResult.C + THE_GOLDEN_RATIO * (aResult.C - aResult.B);
0378 if (theOptions.UseLimits)
0379 {
0380 if (!detail::LimitAndMayBeSwap(theFunc,
0381 theOptions,
0382 aResult.B,
0383 aResult.C,
0384 aResult.Fc,
0385 aU,
0386 aFu))
0387 {
0388 return aResult;
0389 }
0390 }
0391 else if (!theFunc.Value(aU, aFu))
0392 {
0393 return aResult;
0394 }
0395 }
0396
0397
0398 aResult.A = aResult.B;
0399 aResult.B = aResult.C;
0400 aResult.C = aU;
0401 aResult.Fa = aResult.Fb;
0402 aResult.Fb = aResult.Fc;
0403 aResult.Fc = aFu;
0404 }
0405
0406 aResult.IsValid = (aResult.Fb < aResult.Fa && aResult.Fb < aResult.Fc);
0407
0408
0409 if (aResult.IsValid && aResult.A > aResult.C)
0410 {
0411 std::swap(aResult.A, aResult.C);
0412 std::swap(aResult.Fa, aResult.Fc);
0413 }
0414
0415 if (aResult.IsValid && !(aResult.A < aResult.B && aResult.B < aResult.C))
0416 {
0417 aResult.IsValid = false;
0418 }
0419
0420 return aResult;
0421 }
0422
0423
0424 template <typename Function>
0425 MinBracketResult BracketMinimum(Function& theFunc, double theA, double theB, int theMaxIter)
0426 {
0427 MinBracketOptions anOptions;
0428 anOptions.MaxIterations = theMaxIter;
0429 return BracketMinimum(theFunc, theA, theB, anOptions);
0430 }
0431
0432 }
0433
0434 #endif