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_All_HeaderFile
0015 #define _MathRoot_All_HeaderFile
0016
0017 #include <MathUtils_Types.hxx>
0018 #include <MathUtils_Config.hxx>
0019 #include <MathRoot_Multiple.hxx>
0020 #include <math_Vector.hxx>
0021
0022 #include <NCollection_DynamicArray.hxx>
0023
0024 #include <cmath>
0025
0026 namespace MathRoot
0027 {
0028 using namespace MathUtils;
0029
0030
0031 struct NullInterval
0032 {
0033 double A = 0.0;
0034 double B = 0.0;
0035 int State = 0;
0036 };
0037
0038
0039 struct AllRootsResult
0040 {
0041 MathUtils::Status Status = MathUtils::Status::NotConverged;
0042 NCollection_DynamicArray<double> Roots;
0043 NCollection_DynamicArray<int> RootStates;
0044 NCollection_DynamicArray<NullInterval> NullIntervals;
0045
0046 bool IsDone() const { return Status == MathUtils::Status::OK; }
0047
0048 explicit operator bool() const { return IsDone(); }
0049
0050 int NbRoots() const { return Roots.Length(); }
0051
0052 int NbIntervals() const { return NullIntervals.Length(); }
0053 };
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065 template <typename Func>
0066 MultipleResult FindMultipleRoots(Func& theFunc,
0067 double theA,
0068 double theB,
0069 int theNbSamples,
0070 double theEpsX,
0071 double theEpsF,
0072 double theOffset = 0.0)
0073 {
0074 MultipleConfig aConfig;
0075 aConfig.NbSamples = theNbSamples;
0076 aConfig.XTolerance = theEpsX;
0077 aConfig.FTolerance = theEpsF;
0078 aConfig.Offset = theOffset;
0079 return FindAllRoots(theFunc, theA, theB, aConfig);
0080 }
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103 template <typename Func>
0104 AllRootsResult FindAllRootsWithIntervals(Func& theFunc,
0105 const math_Vector& theSamples,
0106 double theEpsX = 1.0e-10,
0107 double theEpsF = 1.0e-10,
0108 double theEpsNul = 1.0e-10)
0109 {
0110 AllRootsResult aResult;
0111
0112 const int aNbp = theSamples.Length();
0113 if (aNbp < 2)
0114 {
0115 aResult.Status = MathUtils::Status::InvalidInput;
0116 return aResult;
0117 }
0118
0119 const int aLower = theSamples.Lower();
0120
0121
0122 double aVal, aPrevVal;
0123 if (!theFunc.Value(theSamples(aLower), aPrevVal))
0124 {
0125 aResult.Status = MathUtils::Status::NotConverged;
0126 return aResult;
0127 }
0128
0129 bool aPrevNul = std::abs(aPrevVal) <= theEpsNul;
0130 if (!aPrevNul)
0131 {
0132
0133 }
0134
0135 bool aInInterval = false;
0136 bool aNulStart = false;
0137 bool aNulEnd = false;
0138 double aDebNul = 0.0, aFinNul = 0.0;
0139 double aValSav = aPrevVal;
0140
0141 NCollection_DynamicArray<double> aIntervalStarts, aIntervalEnds;
0142
0143
0144 for (int i = 1; i < aNbp; ++i)
0145 {
0146 if (!theFunc.Value(theSamples(aLower + i), aVal))
0147 {
0148 aResult.Status = MathUtils::Status::NotConverged;
0149 return aResult;
0150 }
0151
0152 bool aCurNul = std::abs(aVal) <= theEpsNul;
0153 if (!aCurNul)
0154 {
0155 aValSav = aVal;
0156 }
0157
0158 if (aInInterval && !aCurNul)
0159 {
0160
0161 aInInterval = false;
0162 aIntervalStarts.Append(aDebNul);
0163
0164
0165 double aCst = (aVal > 0.0) ? theEpsNul : -theEpsNul;
0166
0167
0168 MultipleResult aRes = FindMultipleRoots(theFunc,
0169 theSamples(aLower + i - 1),
0170 theSamples(aLower + i),
0171 10,
0172 theEpsX,
0173 theEpsF,
0174 aCst);
0175 if (aRes.IsDone() && aRes.NbRoots() > 0)
0176 {
0177 aFinNul = aRes.Roots[0];
0178 }
0179 else
0180 {
0181 aFinNul = theSamples(aLower + i - 1);
0182 }
0183
0184
0185 aCst = -aCst;
0186 auto aRes2 = FindMultipleRoots(theFunc,
0187 theSamples(aLower + i - 1),
0188 theSamples(aLower + i),
0189 10,
0190 theEpsX,
0191 theEpsF,
0192 aCst);
0193 if (aRes2.IsDone() && aRes2.NbRoots() > 0)
0194 {
0195 if (aRes2.Roots[0] < aFinNul)
0196 {
0197 aFinNul = aRes2.Roots[0];
0198 }
0199 }
0200
0201 aIntervalEnds.Append(aFinNul);
0202 }
0203 else if (!aInInterval && aPrevNul && aCurNul)
0204 {
0205
0206 aInInterval = true;
0207 if (i == 1)
0208 {
0209 aDebNul = theSamples(aLower);
0210 aNulStart = true;
0211 }
0212 else
0213 {
0214
0215 double aCst = (aValSav > 0.0) ? theEpsNul : -theEpsNul;
0216
0217 MultipleResult aRes = FindMultipleRoots(theFunc,
0218 theSamples(aLower + i - 2),
0219 theSamples(aLower + i - 1),
0220 10,
0221 theEpsX,
0222 theEpsF,
0223 aCst);
0224 if (aRes.IsDone() && aRes.NbRoots() > 0)
0225 {
0226 aDebNul = aRes.Roots[aRes.NbRoots() - 1];
0227 }
0228 else
0229 {
0230 aDebNul = theSamples(aLower + i - 1);
0231 }
0232
0233
0234 aCst = -aCst;
0235 auto aRes2 = FindMultipleRoots(theFunc,
0236 theSamples(aLower + i - 2),
0237 theSamples(aLower + i - 1),
0238 10,
0239 theEpsX,
0240 theEpsF,
0241 aCst);
0242 if (aRes2.IsDone() && aRes2.NbRoots() > 0)
0243 {
0244 if (aRes2.Roots[aRes2.NbRoots() - 1] > aDebNul)
0245 {
0246 aDebNul = aRes2.Roots[aRes2.NbRoots() - 1];
0247 }
0248 }
0249 }
0250 }
0251
0252 aPrevNul = aCurNul;
0253 }
0254
0255
0256 if (aInInterval)
0257 {
0258 aIntervalStarts.Append(aDebNul);
0259 aFinNul = theSamples(aLower + aNbp - 1);
0260 aIntervalEnds.Append(aFinNul);
0261 aNulEnd = true;
0262 }
0263
0264
0265 for (int k = 0; k < aIntervalStarts.Length(); ++k)
0266 {
0267 NullInterval anInt;
0268 anInt.A = aIntervalStarts.Value(k);
0269 anInt.B = aIntervalEnds.Value(k);
0270 aResult.NullIntervals.Append(anInt);
0271 }
0272
0273 const double aSampleFirst = theSamples(aLower);
0274 const double aSampleLast = theSamples(aLower + aNbp - 1);
0275
0276
0277 if (aIntervalStarts.IsEmpty())
0278 {
0279
0280 MultipleResult aRes =
0281 FindMultipleRoots(theFunc, aSampleFirst, aSampleLast, aNbp, theEpsX, theEpsF);
0282 if (aRes.IsDone())
0283 {
0284 for (int j = 0; j < aRes.NbRoots(); ++j)
0285 {
0286 aResult.Roots.Append(aRes.Roots[j]);
0287 aResult.RootStates.Append(0);
0288 }
0289 }
0290 }
0291 else
0292 {
0293
0294 if (!aNulStart)
0295 {
0296 double aStart = aSampleFirst;
0297 double aEnd = aIntervalStarts.Value(0);
0298 int aNbrpt =
0299 std::max(3,
0300 static_cast<int>(std::abs((aEnd - aStart) / (aSampleLast - aSampleFirst)) * aNbp));
0301
0302 MultipleResult aRes = FindMultipleRoots(theFunc, aStart, aEnd, aNbrpt, theEpsX, theEpsF);
0303 if (aRes.IsDone())
0304 {
0305 for (int j = 0; j < aRes.NbRoots(); ++j)
0306 {
0307 aResult.Roots.Append(aRes.Roots[j]);
0308 aResult.RootStates.Append(0);
0309 }
0310 }
0311 }
0312
0313
0314 for (int k = 1; k < aIntervalStarts.Length(); ++k)
0315 {
0316 double aStart = aIntervalEnds.Value(k - 1);
0317 double aEnd = aIntervalStarts.Value(k);
0318 int aNbrpt =
0319 std::max(3,
0320 static_cast<int>(std::abs((aEnd - aStart) / (aSampleLast - aSampleFirst)) * aNbp));
0321
0322 MultipleResult aRes = FindMultipleRoots(theFunc, aStart, aEnd, aNbrpt, theEpsX, theEpsF);
0323 if (aRes.IsDone())
0324 {
0325 for (int j = 0; j < aRes.NbRoots(); ++j)
0326 {
0327 aResult.Roots.Append(aRes.Roots[j]);
0328 aResult.RootStates.Append(0);
0329 }
0330 }
0331 }
0332
0333
0334 if (!aNulEnd)
0335 {
0336 double aStart = aIntervalEnds.Value(aIntervalEnds.Length() - 1);
0337 double aEnd = aSampleLast;
0338 int aNbrpt =
0339 std::max(3,
0340 static_cast<int>(std::abs((aEnd - aStart) / (aSampleLast - aSampleFirst)) * aNbp));
0341
0342 MultipleResult aRes = FindMultipleRoots(theFunc, aStart, aEnd, aNbrpt, theEpsX, theEpsF);
0343 if (aRes.IsDone())
0344 {
0345 for (int j = 0; j < aRes.NbRoots(); ++j)
0346 {
0347 aResult.Roots.Append(aRes.Roots[j]);
0348 aResult.RootStates.Append(0);
0349 }
0350 }
0351 }
0352 }
0353
0354 aResult.Status = MathUtils::Status::OK;
0355 return aResult;
0356 }
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369 template <typename Func>
0370 AllRootsResult FindAllRootsWithIntervals(Func& theFunc,
0371 double theA,
0372 double theB,
0373 int theNbSamples,
0374 double theEpsX = 1.0e-10,
0375 double theEpsF = 1.0e-10,
0376 double theEpsNul = 1.0e-10)
0377 {
0378 math_Vector aSamples(0, theNbSamples - 1);
0379 const double aStep = (theB - theA) / (theNbSamples - 1);
0380 for (int i = 0; i < theNbSamples; ++i)
0381 {
0382 aSamples(i) = theA + i * aStep;
0383 }
0384
0385 aSamples(theNbSamples - 1) = theB;
0386
0387 return FindAllRootsWithIntervals(theFunc, aSamples, theEpsX, theEpsF, theEpsNul);
0388 }
0389
0390 }
0391
0392 #endif