Back to home page

EIC code displayed by LXR

 
 

    


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

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 _MathSys_Newton_HeaderFile
0015 #define _MathSys_Newton_HeaderFile
0016 
0017 #include <MathUtils_Types.hxx>
0018 #include <MathUtils_Config.hxx>
0019 #include <MathLin_Gauss.hxx>
0020 #include <math_FunctionSetWithDerivatives.hxx>
0021 
0022 #include <cmath>
0023 
0024 namespace MathSys
0025 {
0026 using namespace MathUtils;
0027 
0028 //! Newton-Raphson method for solving systems of nonlinear equations.
0029 //!
0030 //! Solves F(X) = 0 where F is a vector function of vector X.
0031 //! The method iteratively improves an initial guess by solving
0032 //! the linear system J(X)*dX = -F(X) where J is the Jacobian matrix.
0033 //!
0034 //! @param theFunc function set with derivatives (Jacobian)
0035 //! @param theStart initial guess vector
0036 //! @param theTolX tolerance for solution change ||X(n+1) - X(n)|| < tolX
0037 //! @param theTolF tolerance for function values ||F(X)|| < tolF
0038 //! @param theMaxIter maximum number of iterations
0039 //! @return result containing solution vector if converged
0040 template <typename FuncSetType>
0041 VectorResult Newton(FuncSetType&       theFunc,
0042                     const math_Vector& theStart,
0043                     const math_Vector& theTolX,
0044                     double             theTolF,
0045                     size_t             theMaxIter = 100)
0046 {
0047   VectorResult aResult;
0048 
0049   const int aN = theFunc.NbVariables();
0050   const int aM = theFunc.NbEquations();
0051 
0052   // Check dimensions
0053   if (aN != aM || theStart.Length() != aN || theTolX.Length() != aN)
0054   {
0055     aResult.Status = Status::InvalidInput;
0056     return aResult;
0057   }
0058 
0059   const int aLower = theStart.Lower();
0060   const int aUpper = theStart.Upper();
0061 
0062   // Working vectors
0063   math_Vector aSol = theStart;
0064   math_Vector aF(aLower, aUpper);
0065   math_Vector aDeltaX(aLower, aUpper);
0066   math_Matrix aJacobian(aLower, aUpper, aLower, aUpper);
0067 
0068   // Newton iteration
0069   for (size_t anIter = 0; anIter < theMaxIter; ++anIter)
0070   {
0071     // Evaluate function and Jacobian
0072     if (!theFunc.Values(aSol, aF, aJacobian))
0073     {
0074       aResult.Status       = Status::NumericalError;
0075       aResult.NbIterations = anIter;
0076       return aResult;
0077     }
0078 
0079     // Solve J * dX = -F
0080     // Negate F for the right-hand side
0081     math_Vector aNegF(aLower, aUpper);
0082     for (int i = aLower; i <= aUpper; ++i)
0083     {
0084       aNegF(i) = -aF(i);
0085     }
0086 
0087     auto aLinResult = MathLin::Solve(aJacobian, aNegF);
0088     if (!aLinResult.IsDone())
0089     {
0090       aResult.Status       = Status::Singular;
0091       aResult.NbIterations = anIter;
0092       return aResult;
0093     }
0094 
0095     aDeltaX = *aLinResult.Solution;
0096 
0097     // Check X convergence before update
0098     bool aXConverged = true;
0099     for (int i = aLower; i <= aUpper; ++i)
0100     {
0101       if (std::abs(aDeltaX(i)) > theTolX(i))
0102       {
0103         aXConverged = false;
0104         break;
0105       }
0106     }
0107 
0108     // Update solution
0109     for (int i = aLower; i <= aUpper; ++i)
0110     {
0111       aSol(i) += aDeltaX(i);
0112     }
0113 
0114     // Re-evaluate function at new solution to check F convergence
0115     if (!theFunc.Value(aSol, aF))
0116     {
0117       aResult.Status       = Status::NumericalError;
0118       aResult.NbIterations = anIter + 1;
0119       return aResult;
0120     }
0121 
0122     // Check F convergence with updated function values
0123     bool aFConverged = true;
0124     for (int i = aLower; i <= aUpper; ++i)
0125     {
0126       if (std::abs(aF(i)) > theTolF)
0127       {
0128         aFConverged = false;
0129         break;
0130       }
0131     }
0132 
0133     if (aXConverged && aFConverged)
0134     {
0135       aResult.Status       = Status::OK;
0136       aResult.NbIterations = anIter + 1;
0137       aResult.Solution     = aSol;
0138       aResult.Jacobian     = aJacobian;
0139       return aResult;
0140     }
0141 
0142     aResult.NbIterations = anIter + 1;
0143   }
0144 
0145   // Max iterations reached - return last solution
0146   aResult.Status   = Status::MaxIterations;
0147   aResult.Solution = aSol;
0148   aResult.Jacobian = aJacobian;
0149   return aResult;
0150 }
0151 
0152 //! Newton-Raphson method with bounds constraints.
0153 //!
0154 //! Solves F(X) = 0 subject to InfBound <= X <= SupBound.
0155 //! If the Newton step would take X outside bounds, the solution
0156 //! is clamped to the boundary.
0157 //!
0158 //! @param theFunc function set with derivatives (Jacobian)
0159 //! @param theStart initial guess vector
0160 //! @param theInfBound lower bounds for solution
0161 //! @param theSupBound upper bounds for solution
0162 //! @param theTolX tolerance for solution change
0163 //! @param theTolF tolerance for function values
0164 //! @param theMaxIter maximum number of iterations
0165 //! @return result containing solution vector if converged
0166 template <typename FuncSetType>
0167 VectorResult NewtonBounded(FuncSetType&       theFunc,
0168                            const math_Vector& theStart,
0169                            const math_Vector& theInfBound,
0170                            const math_Vector& theSupBound,
0171                            const math_Vector& theTolX,
0172                            double             theTolF,
0173                            size_t             theMaxIter = 100)
0174 {
0175   VectorResult aResult;
0176 
0177   const int aN = theFunc.NbVariables();
0178   const int aM = theFunc.NbEquations();
0179 
0180   // Check dimensions
0181   if (aN != aM || theStart.Length() != aN || theTolX.Length() != aN || theInfBound.Length() != aN
0182       || theSupBound.Length() != aN)
0183   {
0184     aResult.Status = Status::InvalidInput;
0185     return aResult;
0186   }
0187 
0188   const int aLower = theStart.Lower();
0189   const int aUpper = theStart.Upper();
0190 
0191   // Working vectors
0192   math_Vector aSol = theStart;
0193   math_Vector aF(aLower, aUpper);
0194   math_Vector aDeltaX(aLower, aUpper);
0195   math_Matrix aJacobian(aLower, aUpper, aLower, aUpper);
0196 
0197   // Clamp initial solution to bounds
0198   for (int i = aLower; i <= aUpper; ++i)
0199   {
0200     if (aSol(i) < theInfBound(i))
0201     {
0202       aSol(i) = theInfBound(i);
0203     }
0204     if (aSol(i) > theSupBound(i))
0205     {
0206       aSol(i) = theSupBound(i);
0207     }
0208   }
0209 
0210   // Newton iteration
0211   for (size_t anIter = 0; anIter < theMaxIter; ++anIter)
0212   {
0213     // Evaluate function and Jacobian
0214     if (!theFunc.Values(aSol, aF, aJacobian))
0215     {
0216       aResult.Status       = Status::NumericalError;
0217       aResult.NbIterations = anIter;
0218       return aResult;
0219     }
0220 
0221     // Solve J * dX = -F
0222     math_Vector aNegF(aLower, aUpper);
0223     for (int i = aLower; i <= aUpper; ++i)
0224     {
0225       aNegF(i) = -aF(i);
0226     }
0227 
0228     auto aLinResult = MathLin::Solve(aJacobian, aNegF);
0229     if (!aLinResult.IsDone())
0230     {
0231       aResult.Status       = Status::Singular;
0232       aResult.NbIterations = anIter;
0233       return aResult;
0234     }
0235 
0236     aDeltaX = *aLinResult.Solution;
0237 
0238     // Check X convergence before update
0239     bool aXConverged = true;
0240     for (int i = aLower; i <= aUpper; ++i)
0241     {
0242       if (std::abs(aDeltaX(i)) > theTolX(i))
0243       {
0244         aXConverged = false;
0245         break;
0246       }
0247     }
0248 
0249     // Update solution with bounds clamping
0250     for (int i = aLower; i <= aUpper; ++i)
0251     {
0252       aSol(i) += aDeltaX(i);
0253       if (aSol(i) < theInfBound(i))
0254       {
0255         aSol(i) = theInfBound(i);
0256       }
0257       if (aSol(i) > theSupBound(i))
0258       {
0259         aSol(i) = theSupBound(i);
0260       }
0261     }
0262 
0263     // Re-evaluate function at new solution to check F convergence
0264     if (!theFunc.Value(aSol, aF))
0265     {
0266       aResult.Status       = Status::NumericalError;
0267       aResult.NbIterations = anIter + 1;
0268       return aResult;
0269     }
0270 
0271     // Check F convergence with updated function values
0272     bool aFConverged = true;
0273     for (int i = aLower; i <= aUpper; ++i)
0274     {
0275       if (std::abs(aF(i)) > theTolF)
0276       {
0277         aFConverged = false;
0278         break;
0279       }
0280     }
0281 
0282     if (aXConverged && aFConverged)
0283     {
0284       aResult.Status       = Status::OK;
0285       aResult.NbIterations = anIter + 1;
0286       aResult.Solution     = aSol;
0287       aResult.Jacobian     = aJacobian;
0288       return aResult;
0289     }
0290 
0291     aResult.NbIterations = anIter + 1;
0292   }
0293 
0294   // Max iterations reached
0295   aResult.Status   = Status::MaxIterations;
0296   aResult.Solution = aSol;
0297   aResult.Jacobian = aJacobian;
0298   return aResult;
0299 }
0300 
0301 //! Simplified Newton method with uniform tolerances.
0302 //!
0303 //! @param theFunc function set with derivatives
0304 //! @param theStart initial guess vector
0305 //! @param theTolX uniform tolerance for all variables
0306 //! @param theTolF tolerance for function values
0307 //! @param theMaxIter maximum number of iterations
0308 //! @return result containing solution vector if converged
0309 template <typename FuncSetType>
0310 VectorResult Newton(FuncSetType&       theFunc,
0311                     const math_Vector& theStart,
0312                     double             theTolX,
0313                     double             theTolF,
0314                     size_t             theMaxIter = 100)
0315 {
0316   math_Vector aTolXVec(theStart.Lower(), theStart.Upper(), theTolX);
0317   return Newton(theFunc, theStart, aTolXVec, theTolF, theMaxIter);
0318 }
0319 
0320 } // namespace MathSys
0321 
0322 #endif // _MathSys_Newton_HeaderFile