Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-28 09:20:54

0001 // Copyright (c) 2025 OPEN CASCADE SAS
0002 //
0003 // This file is part of Open CASCADE Technology software library.
0004 //
0005 // This library is free software; you can redistribute it and/or modify it under
0006 // the terms of the GNU Lesser General Public License version 2.1 as published
0007 // by the Free Software Foundation, with special exception defined in the file
0008 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0009 // distribution for complete text of the license and disclaimer of any warranty.
0010 //
0011 // Alternatively, this file may be used under the terms of Open CASCADE
0012 // commercial license or contractual agreement.
0013 
0014 #ifndef _MathUtils_Poly_HeaderFile
0015 #define _MathUtils_Poly_HeaderFile
0016 
0017 #include <MathUtils_Core.hxx>
0018 
0019 #include <cmath>
0020 #include <array>
0021 
0022 //! Modern math solver utilities.
0023 namespace MathUtils
0024 {
0025 
0026 //! Evaluate polynomial using Horner's method.
0027 //! Coefficients are ordered as [a0, a1, a2, ...] for P(x) = a0 + a1*x + a2*x^2 + ...
0028 //! @param theCoeffs coefficient array (constant term first)
0029 //! @param theDegree polynomial degree
0030 //! @param theX evaluation point
0031 //! @return P(theX)
0032 inline double EvalPoly(const double* theCoeffs, int theDegree, double theX)
0033 {
0034   double aResult = theCoeffs[theDegree];
0035   for (int i = theDegree - 1; i >= 0; --i)
0036   {
0037     aResult = aResult * theX + theCoeffs[i];
0038   }
0039   return aResult;
0040 }
0041 
0042 //! Evaluate polynomial and its derivative using Horner's method.
0043 //! Computes both P(x) and P'(x) efficiently in a single pass.
0044 //! @param theCoeffs coefficient array (constant term first)
0045 //! @param theDegree polynomial degree
0046 //! @param theX evaluation point
0047 //! @param[out] theValue P(theX)
0048 //! @param[out] theDeriv P'(theX)
0049 inline void EvalPolyDeriv(const double* theCoeffs,
0050                           int           theDegree,
0051                           double        theX,
0052                           double&       theValue,
0053                           double&       theDeriv)
0054 {
0055   theValue = theCoeffs[theDegree];
0056   theDeriv = 0.0;
0057   for (int i = theDegree - 1; i >= 0; --i)
0058   {
0059     theDeriv = theDeriv * theX + theValue;
0060     theValue = theValue * theX + theCoeffs[i];
0061   }
0062 }
0063 
0064 //! Evaluate polynomial with coefficients in descending order.
0065 //! Coefficients are ordered as [an, a(n-1), ..., a1, a0] for P(x) = an*x^n + ... + a0.
0066 //! @param theCoeffs coefficient array (leading term first)
0067 //! @param theDegree polynomial degree
0068 //! @param theX evaluation point
0069 //! @return P(theX)
0070 inline double EvalPolyDesc(const double* theCoeffs, int theDegree, double theX)
0071 {
0072   double aResult = theCoeffs[0];
0073   for (int i = 1; i <= theDegree; ++i)
0074   {
0075     aResult = aResult * theX + theCoeffs[i];
0076   }
0077   return aResult;
0078 }
0079 
0080 //! Newton-Raphson refinement for polynomial root.
0081 //! Polishes an approximate root to higher precision.
0082 //! @param theCoeffs coefficient array (constant term first)
0083 //! @param theDegree polynomial degree
0084 //! @param theRoot initial root estimate
0085 //! @param theMaxIter maximum refinement iterations
0086 //! @return refined root value
0087 inline double RefinePolyRoot(const double* theCoeffs,
0088                              int           theDegree,
0089                              double        theRoot,
0090                              int           theMaxIter = 5)
0091 {
0092   double aX = theRoot;
0093   for (int i = 0; i < theMaxIter; ++i)
0094   {
0095     double aF  = 0.0;
0096     double aDf = 0.0;
0097     EvalPolyDeriv(theCoeffs, theDegree, aX, aF, aDf);
0098 
0099     if (IsZero(aDf))
0100     {
0101       break;
0102     }
0103 
0104     const double aDx = aF / aDf;
0105     aX -= aDx;
0106 
0107     if (std::abs(aDx) < THE_EPSILON * std::max(1.0, std::abs(aX)))
0108     {
0109       break;
0110     }
0111   }
0112   return aX;
0113 }
0114 
0115 //! Newton-Raphson refinement with coefficients in descending order.
0116 //! @param theCoeffs coefficient array (leading term first)
0117 //! @param theDegree polynomial degree
0118 //! @param theRoot initial root estimate
0119 //! @param theMaxIter maximum refinement iterations
0120 //! @return refined root value
0121 inline double RefinePolyRootDesc(const double* theCoeffs,
0122                                  int           theDegree,
0123                                  double        theRoot,
0124                                  int           theMaxIter = 5)
0125 {
0126   // Convert to ascending order for refinement
0127   std::array<double, 5> aAsc;
0128   for (int i = 0; i <= theDegree; ++i)
0129   {
0130     aAsc[i] = theCoeffs[theDegree - i];
0131   }
0132   return RefinePolyRoot(aAsc.data(), theDegree, theRoot, theMaxIter);
0133 }
0134 
0135 //! Sort roots in ascending order (simple insertion sort for small arrays).
0136 //! @param theRoots array of roots
0137 //! @param theCount number of roots
0138 inline void SortRoots(double* theRoots, size_t theCount)
0139 {
0140   for (size_t i = 1; i < theCount; ++i)
0141   {
0142     const double aKey = theRoots[i];
0143     size_t       j    = i;
0144     while (j > 0 && theRoots[j - 1] > aKey)
0145     {
0146       theRoots[j] = theRoots[j - 1];
0147       --j;
0148     }
0149     theRoots[j] = aKey;
0150   }
0151 }
0152 
0153 //! Remove duplicate roots within tolerance.
0154 //! @param theRoots array of sorted roots
0155 //! @param theCount current number of roots
0156 //! @param theTolerance tolerance for duplicate detection
0157 //! @return new count after removing duplicates
0158 inline size_t RemoveDuplicateRoots(double* theRoots, size_t theCount, double theTolerance = 1.0e-10)
0159 {
0160   if (theCount <= 1)
0161   {
0162     return theCount;
0163   }
0164 
0165   size_t aNewCount = 1;
0166   for (size_t i = 1; i < theCount; ++i)
0167   {
0168     if (std::abs(theRoots[i] - theRoots[aNewCount - 1]) > theTolerance)
0169     {
0170       theRoots[aNewCount] = theRoots[i];
0171       ++aNewCount;
0172     }
0173   }
0174   return aNewCount;
0175 }
0176 
0177 //! Compute depressed cubic coefficients.
0178 //! Transforms x^3 + bx^2 + cx + d to t^3 + pt + q via x = t - b/3.
0179 //! @param theB coefficient of x^2 (after dividing by leading coeff)
0180 //! @param theC coefficient of x
0181 //! @param theD constant term
0182 //! @param[out] theP coefficient of t in depressed form
0183 //! @param[out] theQ constant term in depressed form
0184 //! @param[out] theShift substitution shift (b/3)
0185 inline void DepressCubic(double  theB,
0186                          double  theC,
0187                          double  theD,
0188                          double& theP,
0189                          double& theQ,
0190                          double& theShift)
0191 {
0192   theShift         = theB / 3.0;
0193   const double aB2 = theB * theB;
0194   theP             = theC - aB2 / 3.0;
0195   theQ             = theD - theB * theC / 3.0 + 2.0 * aB2 * theB / 27.0;
0196 }
0197 
0198 //! Compute depressed quartic coefficients.
0199 //! Transforms x^4 + bx^3 + cx^2 + dx + e to t^4 + pt^2 + qt + r via x = t - b/4.
0200 //! @param theB coefficient of x^3 (after dividing by leading coeff)
0201 //! @param theC coefficient of x^2
0202 //! @param theD coefficient of x
0203 //! @param theE constant term
0204 //! @param[out] theP coefficient of t^2 in depressed form
0205 //! @param[out] theQ coefficient of t in depressed form
0206 //! @param[out] theR constant term in depressed form
0207 //! @param[out] theShift substitution shift (b/4)
0208 inline void DepressQuartic(double  theB,
0209                            double  theC,
0210                            double  theD,
0211                            double  theE,
0212                            double& theP,
0213                            double& theQ,
0214                            double& theR,
0215                            double& theShift)
0216 {
0217   theShift         = theB / 4.0;
0218   const double aB2 = theB * theB;
0219   const double aB3 = aB2 * theB;
0220   const double aB4 = aB2 * aB2;
0221 
0222   theP = theC - 3.0 * aB2 / 8.0;
0223   theQ = theD - theB * theC / 2.0 + aB3 / 8.0;
0224   theR = theE - theB * theD / 4.0 + aB2 * theC / 16.0 - 3.0 * aB4 / 256.0;
0225 }
0226 
0227 } // namespace MathUtils
0228 
0229 #endif // _MathUtils_Poly_HeaderFile