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_Deriv_HeaderFile
0015 #define _MathUtils_Deriv_HeaderFile
0016
0017 #include <math_Vector.hxx>
0018 #include <math_Matrix.hxx>
0019 #include <MathUtils_Core.hxx>
0020
0021 #include <cmath>
0022
0023
0024 namespace MathUtils
0025 {
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037 template <typename Function>
0038 bool CentralDifference(Function& theFunc, double theX, double& theDeriv, double theStep = 1.0e-8)
0039 {
0040 double aFPlus = 0.0;
0041 double aFMinus = 0.0;
0042
0043 if (!theFunc.Value(theX + theStep, aFPlus))
0044 {
0045 return false;
0046 }
0047 if (!theFunc.Value(theX - theStep, aFMinus))
0048 {
0049 return false;
0050 }
0051
0052 theDeriv = (aFPlus - aFMinus) / (2.0 * theStep);
0053 return true;
0054 }
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068 template <typename Function>
0069 bool ForwardDifference(Function& theFunc,
0070 double theX,
0071 double theFx,
0072 double& theDeriv,
0073 double theStep = 1.0e-8)
0074 {
0075 double aFPlus = 0.0;
0076
0077 if (!theFunc.Value(theX + theStep, aFPlus))
0078 {
0079 return false;
0080 }
0081
0082 theDeriv = (aFPlus - theFx) / theStep;
0083 return true;
0084 }
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095 template <typename Function>
0096 bool NumericalGradient(Function& theFunc,
0097 math_Vector& theX,
0098 math_Vector& theGrad,
0099 double theStep = 1.0e-8)
0100 {
0101 const int aLower = theX.Lower();
0102 const int aUpper = theX.Upper();
0103
0104 for (int i = aLower; i <= aUpper; ++i)
0105 {
0106 const double aXi = theX(i);
0107 double aFPlus = 0.0;
0108 double aFMinus = 0.0;
0109
0110
0111 theX(i) = aXi + theStep;
0112 if (!theFunc.Value(theX, aFPlus))
0113 {
0114 theX(i) = aXi;
0115 return false;
0116 }
0117
0118
0119 theX(i) = aXi - theStep;
0120 if (!theFunc.Value(theX, aFMinus))
0121 {
0122 theX(i) = aXi;
0123 return false;
0124 }
0125
0126
0127 theX(i) = aXi;
0128
0129
0130 theGrad(i) = (aFPlus - aFMinus) / (2.0 * theStep);
0131 }
0132
0133 return true;
0134 }
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145 template <typename Function>
0146 bool NumericalGradientAdaptive(Function& theFunc,
0147 math_Vector& theX,
0148 math_Vector& theGrad,
0149 double theRelStep = 1.0e-8)
0150 {
0151 const int aLower = theX.Lower();
0152 const int aUpper = theX.Upper();
0153
0154 for (int i = aLower; i <= aUpper; ++i)
0155 {
0156 const double aXi = theX(i);
0157
0158 const double aStep = theRelStep * std::max(1.0, std::abs(aXi));
0159
0160 double aFPlus = 0.0;
0161 double aFMinus = 0.0;
0162
0163 theX(i) = aXi + aStep;
0164 if (!theFunc.Value(theX, aFPlus))
0165 {
0166 theX(i) = aXi;
0167 return false;
0168 }
0169
0170 theX(i) = aXi - aStep;
0171 if (!theFunc.Value(theX, aFMinus))
0172 {
0173 theX(i) = aXi;
0174 return false;
0175 }
0176
0177 theX(i) = aXi;
0178 theGrad(i) = (aFPlus - aFMinus) / (2.0 * aStep);
0179 }
0180
0181 return true;
0182 }
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193 template <typename Function>
0194 bool NumericalJacobian(Function& theFunc,
0195 math_Vector& theX,
0196 math_Matrix& theJac,
0197 double theStep = 1.0e-8)
0198 {
0199 const int aNbRows = theJac.RowNumber();
0200 const int aNbCols = theJac.ColNumber();
0201
0202 math_Vector aFPlus(1, aNbRows);
0203 math_Vector aFMinus(1, aNbRows);
0204
0205 for (int j = 1; j <= aNbCols; ++j)
0206 {
0207 const int aIdx = theX.Lower() + j - 1;
0208 const double aXj = theX(aIdx);
0209
0210
0211 theX(aIdx) = aXj + theStep;
0212 if (!theFunc.Value(theX, aFPlus))
0213 {
0214 theX(aIdx) = aXj;
0215 return false;
0216 }
0217
0218
0219 theX(aIdx) = aXj - theStep;
0220 if (!theFunc.Value(theX, aFMinus))
0221 {
0222 theX(aIdx) = aXj;
0223 return false;
0224 }
0225
0226
0227 theX(aIdx) = aXj;
0228
0229
0230 for (int i = 1; i <= aNbRows; ++i)
0231 {
0232 theJac(i, j) = (aFPlus(i) - aFMinus(i)) / (2.0 * theStep);
0233 }
0234 }
0235
0236 return true;
0237 }
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249 template <typename Function>
0250 bool NumericalHessian(Function& theFunc,
0251 math_Vector& theX,
0252 math_Matrix& theHess,
0253 double theStep = 1.0e-5)
0254 {
0255 const int aLower = theX.Lower();
0256 const int aUpper = theX.Upper();
0257
0258 double aFx = 0.0;
0259 if (!theFunc.Value(theX, aFx))
0260 {
0261 return false;
0262 }
0263
0264
0265 for (int i = aLower; i <= aUpper; ++i)
0266 {
0267 const double aXi = theX(i);
0268 double aFPlus = 0.0;
0269 double aFMinus = 0.0;
0270
0271 theX(i) = aXi + theStep;
0272 if (!theFunc.Value(theX, aFPlus))
0273 {
0274 theX(i) = aXi;
0275 return false;
0276 }
0277
0278 theX(i) = aXi - theStep;
0279 if (!theFunc.Value(theX, aFMinus))
0280 {
0281 theX(i) = aXi;
0282 return false;
0283 }
0284
0285 theX(i) = aXi;
0286
0287 const int aMatIdx = i - aLower + 1;
0288 theHess(aMatIdx, aMatIdx) = (aFPlus - 2.0 * aFx + aFMinus) / (theStep * theStep);
0289 }
0290
0291
0292
0293
0294 for (int i = aLower; i <= aUpper; ++i)
0295 {
0296 for (int j = i + 1; j <= aUpper; ++j)
0297 {
0298 const double aXi = theX(i);
0299 const double aXj = theX(j);
0300 double aFpp = 0.0, aFpm = 0.0, aFmp = 0.0, aFmm = 0.0;
0301
0302
0303 theX(i) = aXi + theStep;
0304 theX(j) = aXj + theStep;
0305 if (!theFunc.Value(theX, aFpp))
0306 {
0307 theX(i) = aXi;
0308 theX(j) = aXj;
0309 return false;
0310 }
0311
0312
0313 theX(j) = aXj - theStep;
0314 if (!theFunc.Value(theX, aFpm))
0315 {
0316 theX(i) = aXi;
0317 theX(j) = aXj;
0318 return false;
0319 }
0320
0321
0322 theX(i) = aXi - theStep;
0323 if (!theFunc.Value(theX, aFmm))
0324 {
0325 theX(i) = aXi;
0326 theX(j) = aXj;
0327 return false;
0328 }
0329
0330
0331 theX(j) = aXj + theStep;
0332 if (!theFunc.Value(theX, aFmp))
0333 {
0334 theX(i) = aXi;
0335 theX(j) = aXj;
0336 return false;
0337 }
0338
0339
0340 theX(i) = aXi;
0341 theX(j) = aXj;
0342
0343 const int aMatI = i - aLower + 1;
0344 const int aMatJ = j - aLower + 1;
0345 const double aHij = (aFpp - aFpm - aFmp + aFmm) / (4.0 * theStep * theStep);
0346
0347
0348 theHess(aMatI, aMatJ) = aHij;
0349 theHess(aMatJ, aMatI) = aHij;
0350 }
0351 }
0352
0353 return true;
0354 }
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366 template <typename Function>
0367 bool SecondDerivative(Function& theFunc,
0368 double theX,
0369 double theFx,
0370 double& theD2f,
0371 double theStep = 1.0e-5)
0372 {
0373 double aFPlus = 0.0;
0374 double aFMinus = 0.0;
0375
0376 if (!theFunc.Value(theX + theStep, aFPlus))
0377 {
0378 return false;
0379 }
0380 if (!theFunc.Value(theX - theStep, aFMinus))
0381 {
0382 return false;
0383 }
0384
0385 theD2f = (aFPlus - 2.0 * theFx + aFMinus) / (theStep * theStep);
0386 return true;
0387 }
0388
0389 }
0390
0391 #endif