File indexing completed on 2026-09-28 09:20:51
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef _MathOpt_Powell_HeaderFile
0015 #define _MathOpt_Powell_HeaderFile
0016
0017 #include <MathUtils_Types.hxx>
0018 #include <MathUtils_Config.hxx>
0019 #include <MathUtils_Core.hxx>
0020 #include <MathUtils_LineSearch.hxx>
0021
0022 #include <cmath>
0023
0024 namespace MathOpt
0025 {
0026 using namespace MathUtils;
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051 template <typename Function>
0052 VectorResult Powell(Function& theFunc,
0053 const math_Vector& theStartingPoint,
0054 const Config& theConfig = Config())
0055 {
0056 VectorResult aResult;
0057
0058 const int aLower = theStartingPoint.Lower();
0059 const int aUpper = theStartingPoint.Upper();
0060 const int aN = aUpper - aLower + 1;
0061
0062
0063 math_Vector aX(aLower, aUpper);
0064 aX = theStartingPoint;
0065
0066
0067 double aFx = 0.0;
0068 if (!theFunc.Value(aX, aFx))
0069 {
0070 aResult.Status = Status::NumericalError;
0071 return aResult;
0072 }
0073
0074
0075
0076 math_Matrix aDirections(1, aN, 1, aN, 0.0);
0077 for (int i = 1; i <= aN; ++i)
0078 {
0079 aDirections(i, i) = 1.0;
0080 }
0081
0082
0083 math_Vector aDir(aLower, aUpper);
0084 math_Vector aXOld(aLower, aUpper);
0085 math_Vector aPt(aLower, aUpper);
0086 math_Vector aPtt(aLower, aUpper);
0087 math_Vector aXit(aLower, aUpper);
0088
0089 for (int anIter = 0; anIter < theConfig.MaxIterations; ++anIter)
0090 {
0091 aResult.NbIterations = anIter + 1;
0092
0093 const double aFp = aFx;
0094 aXOld = aX;
0095
0096
0097 double aDel = 0.0;
0098 int aIBig = 0;
0099
0100
0101 for (int i = 1; i <= aN; ++i)
0102 {
0103
0104 for (int j = aLower; j <= aUpper; ++j)
0105 {
0106 aDir(j) = aDirections(i, j - aLower + 1);
0107 }
0108
0109 const double aFpPrev = aFx;
0110
0111
0112 MathUtils::LineSearchResult aLineResult =
0113 MathUtils::ExactLineSearch(theFunc, aX, aDir, 10.0, theConfig.XTolerance);
0114
0115 if (aLineResult.IsValid)
0116 {
0117
0118 for (int j = aLower; j <= aUpper; ++j)
0119 {
0120 aX(j) += aLineResult.Alpha * aDir(j);
0121 }
0122 aFx = aLineResult.FNew;
0123
0124
0125 const double aDecrease = aFpPrev - aFx;
0126 if (aDecrease > aDel)
0127 {
0128 aDel = aDecrease;
0129 aIBig = i;
0130 }
0131 }
0132 }
0133
0134
0135 if (2.0 * std::abs(aFp - aFx)
0136 <= theConfig.FTolerance * (std::abs(aFp) + std::abs(aFx) + MathUtils::THE_ZERO_TOL))
0137 {
0138 aResult.Status = Status::OK;
0139 aResult.Solution = aX;
0140 aResult.Value = aFx;
0141 return aResult;
0142 }
0143
0144
0145 for (int j = aLower; j <= aUpper; ++j)
0146 {
0147 aPtt(j) = 2.0 * aX(j) - aXOld(j);
0148 aXit(j) = aX(j) - aXOld(j);
0149 }
0150
0151
0152 double aFptt = 0.0;
0153 if (!theFunc.Value(aPtt, aFptt))
0154 {
0155
0156 continue;
0157 }
0158
0159
0160 if (aFptt < aFp)
0161 {
0162 const double aT = 2.0 * (aFp - 2.0 * aFx + aFptt) * MathUtils::Sqr(aFp - aFx - aDel)
0163 - aDel * MathUtils::Sqr(aFp - aFptt);
0164
0165 if (aT < 0.0)
0166 {
0167
0168 MathUtils::LineSearchResult aLineResult =
0169 MathUtils::ExactLineSearch(theFunc, aX, aXit, 10.0, theConfig.XTolerance);
0170
0171 if (aLineResult.IsValid)
0172 {
0173
0174 for (int j = aLower; j <= aUpper; ++j)
0175 {
0176 aX(j) += aLineResult.Alpha * aXit(j);
0177 }
0178 aFx = aLineResult.FNew;
0179
0180
0181 if (aIBig > 0)
0182 {
0183 for (int j = 1; j <= aN; ++j)
0184 {
0185 aDirections(aIBig, j) = aDirections(aN, j);
0186 aDirections(aN, j) = aXit(aLower + j - 1);
0187 }
0188 }
0189 }
0190 }
0191 }
0192
0193
0194 double aMaxDiff = 0.0;
0195 for (int j = aLower; j <= aUpper; ++j)
0196 {
0197 aMaxDiff = std::max(aMaxDiff, std::abs(aX(j) - aXOld(j)));
0198 }
0199 if (aMaxDiff < theConfig.XTolerance)
0200 {
0201 aResult.Status = Status::OK;
0202 aResult.Solution = aX;
0203 aResult.Value = aFx;
0204 return aResult;
0205 }
0206 }
0207
0208
0209 aResult.Status = Status::MaxIterations;
0210 aResult.Solution = aX;
0211 aResult.Value = aFx;
0212 return aResult;
0213 }
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224 template <typename Function>
0225 VectorResult PowellWithDirections(Function& theFunc,
0226 const math_Vector& theStartingPoint,
0227 const math_Matrix& theInitialDirections,
0228 const Config& theConfig = Config())
0229 {
0230 VectorResult aResult;
0231
0232 const int aLower = theStartingPoint.Lower();
0233 const int aUpper = theStartingPoint.Upper();
0234 const int aN = aUpper - aLower + 1;
0235
0236
0237 if (theInitialDirections.RowNumber() != aN || theInitialDirections.ColNumber() != aN)
0238 {
0239 aResult.Status = Status::InvalidInput;
0240 return aResult;
0241 }
0242
0243 math_Vector aX(aLower, aUpper);
0244 aX = theStartingPoint;
0245
0246 double aFx = 0.0;
0247 if (!theFunc.Value(aX, aFx))
0248 {
0249 aResult.Status = Status::NumericalError;
0250 return aResult;
0251 }
0252
0253
0254 math_Matrix aDirections(1, aN, 1, aN);
0255 aDirections = theInitialDirections;
0256
0257 math_Vector aDir(aLower, aUpper);
0258 math_Vector aXOld(aLower, aUpper);
0259 math_Vector aPtt(aLower, aUpper);
0260 math_Vector aXit(aLower, aUpper);
0261
0262 for (int anIter = 0; anIter < theConfig.MaxIterations; ++anIter)
0263 {
0264 aResult.NbIterations = anIter + 1;
0265
0266 const double aFp = aFx;
0267 aXOld = aX;
0268
0269 double aDel = 0.0;
0270 int aIBig = 0;
0271
0272 for (int i = 1; i <= aN; ++i)
0273 {
0274 for (int j = aLower; j <= aUpper; ++j)
0275 {
0276 aDir(j) = aDirections(i, j - aLower + 1);
0277 }
0278
0279 const double aFpPrev = aFx;
0280
0281 MathUtils::LineSearchResult aLineResult =
0282 MathUtils::ExactLineSearch(theFunc, aX, aDir, 10.0, theConfig.XTolerance);
0283
0284 if (aLineResult.IsValid)
0285 {
0286 for (int j = aLower; j <= aUpper; ++j)
0287 {
0288 aX(j) += aLineResult.Alpha * aDir(j);
0289 }
0290 aFx = aLineResult.FNew;
0291
0292 const double aDecrease = aFpPrev - aFx;
0293 if (aDecrease > aDel)
0294 {
0295 aDel = aDecrease;
0296 aIBig = i;
0297 }
0298 }
0299 }
0300
0301
0302 if (2.0 * std::abs(aFp - aFx)
0303 <= theConfig.FTolerance * (std::abs(aFp) + std::abs(aFx) + MathUtils::THE_ZERO_TOL))
0304 {
0305 aResult.Status = Status::OK;
0306 aResult.Solution = aX;
0307 aResult.Value = aFx;
0308 return aResult;
0309 }
0310
0311
0312 for (int j = aLower; j <= aUpper; ++j)
0313 {
0314 aPtt(j) = 2.0 * aX(j) - aXOld(j);
0315 aXit(j) = aX(j) - aXOld(j);
0316 }
0317
0318 double aFptt = 0.0;
0319 if (!theFunc.Value(aPtt, aFptt))
0320 {
0321 continue;
0322 }
0323
0324 if (aFptt < aFp)
0325 {
0326 const double aT = 2.0 * (aFp - 2.0 * aFx + aFptt) * MathUtils::Sqr(aFp - aFx - aDel)
0327 - aDel * MathUtils::Sqr(aFp - aFptt);
0328
0329 if (aT < 0.0)
0330 {
0331 MathUtils::LineSearchResult aLineResult =
0332 MathUtils::ExactLineSearch(theFunc, aX, aXit, 10.0, theConfig.XTolerance);
0333
0334 if (aLineResult.IsValid)
0335 {
0336 for (int j = aLower; j <= aUpper; ++j)
0337 {
0338 aX(j) += aLineResult.Alpha * aXit(j);
0339 }
0340 aFx = aLineResult.FNew;
0341
0342 if (aIBig > 0)
0343 {
0344 for (int j = 1; j <= aN; ++j)
0345 {
0346 aDirections(aIBig, j) = aDirections(aN, j);
0347 aDirections(aN, j) = aXit(aLower + j - 1);
0348 }
0349 }
0350 }
0351 }
0352 }
0353
0354 double aMaxDiff = 0.0;
0355 for (int j = aLower; j <= aUpper; ++j)
0356 {
0357 aMaxDiff = std::max(aMaxDiff, std::abs(aX(j) - aXOld(j)));
0358 }
0359 if (aMaxDiff < theConfig.XTolerance)
0360 {
0361 aResult.Status = Status::OK;
0362 aResult.Solution = aX;
0363 aResult.Value = aFx;
0364 return aResult;
0365 }
0366 }
0367
0368 aResult.Status = Status::MaxIterations;
0369 aResult.Solution = aX;
0370 aResult.Value = aFx;
0371 return aResult;
0372 }
0373
0374 }
0375
0376 #endif