File indexing completed on 2026-09-28 09:20:50
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef _MathOpt_Brent_HeaderFile
0015 #define _MathOpt_Brent_HeaderFile
0016
0017 #include <MathUtils_Types.hxx>
0018 #include <MathUtils_Config.hxx>
0019 #include <MathUtils_Core.hxx>
0020 #include <MathUtils_Bracket.hxx>
0021
0022 #include <cmath>
0023
0024
0025 namespace MathOpt
0026 {
0027 using namespace MathUtils;
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045 template <typename Function>
0046 ScalarResult Brent(Function& theFunc,
0047 double theLower,
0048 double theUpper,
0049 const Config& theConfig = Config())
0050 {
0051 ScalarResult aResult;
0052
0053 double aA = theLower;
0054 double aB = theUpper;
0055
0056
0057 double aX = aA + MathUtils::THE_GOLDEN_SECTION * (aB - aA);
0058 double aW = aX;
0059 double aV = aX;
0060
0061 double aFx = 0.0;
0062 if (!theFunc.Value(aX, aFx))
0063 {
0064 aResult.Status = Status::NumericalError;
0065 return aResult;
0066 }
0067 double aFw = aFx;
0068 double aFv = aFx;
0069
0070 double aD = 0.0;
0071 double aE = 0.0;
0072
0073 for (int anIter = 0; anIter < theConfig.MaxIterations; ++anIter)
0074 {
0075 const double aXm = 0.5 * (aA + aB);
0076 const double aTol1 = theConfig.XTolerance * std::abs(aX) + MathUtils::THE_ZERO_TOL / 10.0;
0077 const double aTol2 = 2.0 * aTol1;
0078
0079 aResult.NbIterations = anIter + 1;
0080
0081
0082 if (std::abs(aX - aXm) <= (aTol2 - 0.5 * (aB - aA)))
0083 {
0084 aResult.Status = Status::OK;
0085 aResult.Root = aX;
0086 aResult.Value = aFx;
0087 return aResult;
0088 }
0089
0090 double aU = 0.0;
0091 bool aUseParabolic = false;
0092
0093
0094 if (std::abs(aE) > aTol1)
0095 {
0096
0097 const double aR = (aX - aW) * (aFx - aFv);
0098 double aQ = (aX - aV) * (aFx - aFw);
0099 double aP = (aX - aV) * aQ - (aX - aW) * aR;
0100 aQ = 2.0 * (aQ - aR);
0101
0102 if (aQ > 0.0)
0103 {
0104 aP = -aP;
0105 }
0106 else
0107 {
0108 aQ = -aQ;
0109 }
0110
0111 const double aETmp = aE;
0112 aE = aD;
0113
0114
0115 if (std::abs(aP) < std::abs(0.5 * aQ * aETmp) && aP > aQ * (aA - aX) && aP < aQ * (aB - aX))
0116 {
0117 aD = aP / aQ;
0118 aU = aX + aD;
0119
0120
0121 if ((aU - aA) < aTol2 || (aB - aU) < aTol2)
0122 {
0123 aD = MathUtils::SignTransfer(aTol1, aXm - aX);
0124 }
0125 aUseParabolic = true;
0126 }
0127 }
0128
0129 if (!aUseParabolic)
0130 {
0131
0132 aE = (aX < aXm) ? (aB - aX) : (aA - aX);
0133 aD = MathUtils::THE_GOLDEN_SECTION * aE;
0134 }
0135
0136
0137 if (std::abs(aD) >= aTol1)
0138 {
0139 aU = aX + aD;
0140 }
0141 else
0142 {
0143 aU = aX + MathUtils::SignTransfer(aTol1, aD);
0144 }
0145
0146 double aFu = 0.0;
0147 if (!theFunc.Value(aU, aFu))
0148 {
0149 aResult.Status = Status::NumericalError;
0150 aResult.Root = aX;
0151 aResult.Value = aFx;
0152 return aResult;
0153 }
0154
0155
0156 if (aFu <= aFx)
0157 {
0158 if (aU < aX)
0159 {
0160 aB = aX;
0161 }
0162 else
0163 {
0164 aA = aX;
0165 }
0166
0167 aV = aW;
0168 aW = aX;
0169 aX = aU;
0170 aFv = aFw;
0171 aFw = aFx;
0172 aFx = aFu;
0173 }
0174 else
0175 {
0176 if (aU < aX)
0177 {
0178 aA = aU;
0179 }
0180 else
0181 {
0182 aB = aU;
0183 }
0184
0185 if (aFu <= aFw || aW == aX)
0186 {
0187 aV = aW;
0188 aW = aU;
0189 aFv = aFw;
0190 aFw = aFu;
0191 }
0192 else if (aFu <= aFv || aV == aX || aV == aW)
0193 {
0194 aV = aU;
0195 aFv = aFu;
0196 }
0197 }
0198 }
0199
0200
0201 aResult.Status = Status::MaxIterations;
0202 aResult.Root = aX;
0203 aResult.Value = aFx;
0204 return aResult;
0205 }
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217 template <typename Function>
0218 ScalarResult Golden(Function& theFunc,
0219 double theLower,
0220 double theUpper,
0221 const Config& theConfig = Config())
0222 {
0223 ScalarResult aResult;
0224
0225 constexpr double aR = 0.618033988749895;
0226 constexpr double aC = 1.0 - aR;
0227
0228 double aA = theLower;
0229 double aB = theUpper;
0230
0231
0232 double aX1 = aA + aC * (aB - aA);
0233 double aX2 = aA + aR * (aB - aA);
0234
0235 double aF1 = 0.0;
0236 double aF2 = 0.0;
0237
0238 if (!theFunc.Value(aX1, aF1))
0239 {
0240 aResult.Status = Status::NumericalError;
0241 return aResult;
0242 }
0243 if (!theFunc.Value(aX2, aF2))
0244 {
0245 aResult.Status = Status::NumericalError;
0246 return aResult;
0247 }
0248
0249 for (int anIter = 0; anIter < theConfig.MaxIterations; ++anIter)
0250 {
0251 aResult.NbIterations = anIter + 1;
0252
0253
0254 if ((aB - aA) < theConfig.XTolerance * (std::abs(aX1) + std::abs(aX2)))
0255 {
0256 aResult.Status = Status::OK;
0257 if (aF1 < aF2)
0258 {
0259 aResult.Root = aX1;
0260 aResult.Value = aF1;
0261 }
0262 else
0263 {
0264 aResult.Root = aX2;
0265 aResult.Value = aF2;
0266 }
0267 return aResult;
0268 }
0269
0270 if (aF1 < aF2)
0271 {
0272
0273 aB = aX2;
0274 aX2 = aX1;
0275 aF2 = aF1;
0276 aX1 = aA + aC * (aB - aA);
0277 if (!theFunc.Value(aX1, aF1))
0278 {
0279 aResult.Status = Status::NumericalError;
0280 aResult.Root = aX2;
0281 aResult.Value = aF2;
0282 return aResult;
0283 }
0284 }
0285 else
0286 {
0287
0288 aA = aX1;
0289 aX1 = aX2;
0290 aF1 = aF2;
0291 aX2 = aA + aR * (aB - aA);
0292 if (!theFunc.Value(aX2, aF2))
0293 {
0294 aResult.Status = Status::NumericalError;
0295 aResult.Root = aX1;
0296 aResult.Value = aF1;
0297 return aResult;
0298 }
0299 }
0300 }
0301
0302
0303 aResult.Status = Status::MaxIterations;
0304 if (aF1 < aF2)
0305 {
0306 aResult.Root = aX1;
0307 aResult.Value = aF1;
0308 }
0309 else
0310 {
0311 aResult.Root = aX2;
0312 aResult.Value = aF2;
0313 }
0314 return aResult;
0315 }
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326 template <typename Function>
0327 ScalarResult BrentWithBracket(Function& theFunc,
0328 double theGuess,
0329 double theStep = 1.0,
0330 const Config& theConfig = Config())
0331 {
0332 ScalarResult aResult;
0333
0334
0335 MathUtils::MinBracketResult aBracket =
0336 MathUtils::BracketMinimum(theFunc, theGuess, theGuess + theStep);
0337
0338 if (!aBracket.IsValid)
0339 {
0340 aResult.Status = Status::InvalidInput;
0341 return aResult;
0342 }
0343
0344
0345 return Brent(theFunc, aBracket.A, aBracket.C, theConfig);
0346 }
0347
0348 }
0349
0350 #endif