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_FunctorVector_HeaderFile
0015 #define _MathUtils_FunctorVector_HeaderFile
0016 
0017 #include <math_Vector.hxx>
0018 #include <math_Matrix.hxx>
0019 
0020 #include <cmath>
0021 #include <utility>
0022 
0023 //! @file MathUtils_FunctorVector.hxx
0024 //! @brief Non-virtual functor classes for N-dimensional (vector) functions.
0025 //!
0026 //! Provides ready-to-use functor classes that work with the template-based
0027 //! math API (MathOpt::Powell, MathOpt::BFGS, MathSys::Newton) without
0028 //! virtual dispatch overhead.
0029 
0030 //! Core utilities for modern math solvers.
0031 namespace MathUtils
0032 {
0033 
0034 //! Lambda wrapper for N-D objective functions (value only).
0035 //! Wraps a lambda/callable into a functor with Value() method.
0036 //!
0037 //! Usage:
0038 //! @code
0039 //! auto aFunc = VectorLambda([](const math_Vector& x, double& y) {
0040 //!   y = x(1)*x(1) + x(2)*x(2);  // Sphere function
0041 //!   return true;
0042 //! });
0043 //! auto aResult = MathOpt::Powell(aFunc, aStartPoint);
0044 //! @endcode
0045 //!
0046 //! @tparam Lambda callable type with signature bool(const math_Vector&, double&)
0047 template <typename Lambda>
0048 class VectorLambda
0049 {
0050 public:
0051   //! Constructor from lambda/callable.
0052   //! @param theLambda callable with signature bool(const math_Vector&, double&)
0053   explicit VectorLambda(Lambda theLambda)
0054       : myLambda(std::move(theLambda))
0055   {
0056   }
0057 
0058   //! Evaluates the function at theX.
0059   //! @param[in] theX input vector
0060   //! @param[out] theY function value f(theX)
0061   //! @return true if evaluation succeeded
0062   bool Value(const math_Vector& theX, double& theY) const { return myLambda(theX, theY); }
0063 
0064 private:
0065   Lambda myLambda;
0066 };
0067 
0068 //! Lambda wrapper for N-D objective functions with gradient.
0069 //! Wraps a lambda/callable into a functor with Value() and Gradient() methods.
0070 //!
0071 //! Usage:
0072 //! @code
0073 //! auto aFunc = VectorLambdaWithGradient(
0074 //!   [](const math_Vector& x, double& y) {
0075 //!     y = x(1)*x(1) + x(2)*x(2);
0076 //!     return true;
0077 //!   },
0078 //!   [](const math_Vector& x, math_Vector& g) {
0079 //!     g(1) = 2.0 * x(1);
0080 //!     g(2) = 2.0 * x(2);
0081 //!     return true;
0082 //!   });
0083 //! auto aResult = MathOpt::BFGS(aFunc, aStartPoint);
0084 //! @endcode
0085 //!
0086 //! @tparam ValueLambda callable for value: bool(const math_Vector&, double&)
0087 //! @tparam GradLambda callable for gradient: bool(const math_Vector&, math_Vector&)
0088 template <typename ValueLambda, typename GradLambda>
0089 class VectorLambdaWithGradient
0090 {
0091 public:
0092   //! Constructor from value and gradient lambdas.
0093   //! @param theValueLambda callable for value evaluation
0094   //! @param theGradLambda callable for gradient evaluation
0095   VectorLambdaWithGradient(ValueLambda theValueLambda, GradLambda theGradLambda)
0096       : myValueLambda(std::move(theValueLambda)),
0097         myGradLambda(std::move(theGradLambda))
0098   {
0099   }
0100 
0101   //! Evaluates the function value at theX.
0102   //! @param[in] theX input vector
0103   //! @param[out] theY function value f(theX)
0104   //! @return true if evaluation succeeded
0105   bool Value(const math_Vector& theX, double& theY) const { return myValueLambda(theX, theY); }
0106 
0107   //! Evaluates the gradient at theX.
0108   //! @param[in] theX input vector
0109   //! @param[out] theG gradient vector
0110   //! @return true if evaluation succeeded
0111   bool Gradient(const math_Vector& theX, math_Vector& theG) const
0112   {
0113     return myGradLambda(theX, theG);
0114   }
0115 
0116   //! Evaluates both value and gradient at theX.
0117   //! @param[in] theX input vector
0118   //! @param[out] theY function value
0119   //! @param[out] theG gradient vector
0120   //! @return true if evaluation succeeded
0121   bool Values(const math_Vector& theX, double& theY, math_Vector& theG) const
0122   {
0123     return myValueLambda(theX, theY) && myGradLambda(theX, theG);
0124   }
0125 
0126 private:
0127   ValueLambda myValueLambda;
0128   GradLambda  myGradLambda;
0129 };
0130 
0131 //! Helper function to create VectorLambda with type deduction.
0132 //! @tparam Lambda callable type (auto-deduced)
0133 //! @param theLambda callable with signature bool(const math_Vector&, double&)
0134 //! @return VectorLambda wrapper
0135 template <typename Lambda>
0136 VectorLambda<Lambda> MakeVector(Lambda theLambda)
0137 {
0138   return VectorLambda<Lambda>(std::move(theLambda));
0139 }
0140 
0141 //! Helper function to create VectorLambdaWithGradient with type deduction.
0142 //! @tparam ValueLambda callable for value
0143 //! @tparam GradLambda callable for gradient
0144 //! @param theValueLambda callable for value evaluation
0145 //! @param theGradLambda callable for gradient evaluation
0146 //! @return VectorLambdaWithGradient wrapper
0147 template <typename ValueLambda, typename GradLambda>
0148 VectorLambdaWithGradient<ValueLambda, GradLambda> MakeVectorWithGradient(ValueLambda theValueLambda,
0149                                                                          GradLambda  theGradLambda)
0150 {
0151   return VectorLambdaWithGradient<ValueLambda, GradLambda>(std::move(theValueLambda),
0152                                                            std::move(theGradLambda));
0153 }
0154 
0155 //! Quadratic form functor: f(x) = x^T A x + b^T x + c.
0156 //! Commonly used for testing optimization algorithms.
0157 //!
0158 //! Usage:
0159 //! @code
0160 //! math_Matrix A(1, 2, 1, 2);
0161 //! A(1,1) = 2.0; A(1,2) = 0.0;
0162 //! A(2,1) = 0.0; A(2,2) = 2.0;
0163 //! math_Vector b(1, 2);
0164 //! b(1) = -4.0; b(2) = -4.0;
0165 //! QuadraticForm aFunc(A, b, 8.0);  // f(x) = 2*x1^2 + 2*x2^2 - 4*x1 - 4*x2 + 8
0166 //! // Minimum at (1, 1) with value 4
0167 //! @endcode
0168 class QuadraticForm
0169 {
0170 public:
0171   //! Constructor from matrix, vector, and constant.
0172   //! @param theA quadratic coefficient matrix (must be square)
0173   //! @param theB linear coefficient vector
0174   //! @param theC constant term
0175   QuadraticForm(const math_Matrix& theA, const math_Vector& theB, double theC)
0176       : myA(theA),
0177         myB(theB),
0178         myC(theC)
0179   {
0180   }
0181 
0182   //! Evaluates the quadratic form f(x) = x^T A x + b^T x + c.
0183   //! @param[in] theX input vector
0184   //! @param[out] theY function value
0185   //! @return true if evaluation succeeded
0186   bool Value(const math_Vector& theX, double& theY) const
0187   {
0188     theY = myC;
0189     // x^T A x
0190     for (int i = theX.Lower(); i <= theX.Upper(); ++i)
0191     {
0192       for (int j = theX.Lower(); j <= theX.Upper(); ++j)
0193       {
0194         theY += theX(i) * myA(i, j) * theX(j);
0195       }
0196     }
0197     // b^T x
0198     for (int i = theX.Lower(); i <= theX.Upper(); ++i)
0199     {
0200       theY += myB(i) * theX(i);
0201     }
0202     return true;
0203   }
0204 
0205   //! Evaluates the gradient: g = 2*A*x + b.
0206   //! @param[in] theX input vector
0207   //! @param[out] theG gradient vector
0208   //! @return true if evaluation succeeded
0209   bool Gradient(const math_Vector& theX, math_Vector& theG) const
0210   {
0211     // g = (A + A^T) * x + b = 2*A*x + b (for symmetric A)
0212     for (int i = theX.Lower(); i <= theX.Upper(); ++i)
0213     {
0214       theG(i) = myB(i);
0215       for (int j = theX.Lower(); j <= theX.Upper(); ++j)
0216       {
0217         theG(i) += (myA(i, j) + myA(j, i)) * theX(j);
0218       }
0219     }
0220     return true;
0221   }
0222 
0223   //! Evaluates both value and gradient.
0224   //! @param[in] theX input vector
0225   //! @param[out] theY function value
0226   //! @param[out] theG gradient vector
0227   //! @return true if evaluation succeeded
0228   bool Values(const math_Vector& theX, double& theY, math_Vector& theG) const
0229   {
0230     return Value(theX, theY) && Gradient(theX, theG);
0231   }
0232 
0233 private:
0234   math_Matrix myA;
0235   math_Vector myB;
0236   double      myC;
0237 };
0238 
0239 //! Rosenbrock function functor (for testing optimization).
0240 //! f(x,y) = (a - x)^2 + b*(y - x^2)^2
0241 //! Default: a = 1, b = 100
0242 //! Global minimum at (a, a^2) = (1, 1) with f = 0.
0243 //!
0244 //! Usage:
0245 //! @code
0246 //! Rosenbrock aRosen;  // Default a=1, b=100
0247 //! math_Vector aStart(1, 2);
0248 //! aStart(1) = -1.0; aStart(2) = 1.0;
0249 //! auto aResult = MathOpt::BFGS(aRosen, aStart);
0250 //! // Should converge to (1, 1)
0251 //! @endcode
0252 class Rosenbrock
0253 {
0254 public:
0255   //! Constructor with parameters.
0256   //! @param theA parameter a (default 1.0)
0257   //! @param theB parameter b (default 100.0)
0258   Rosenbrock(double theA = 1.0, double theB = 100.0)
0259       : myA(theA),
0260         myB(theB)
0261   {
0262   }
0263 
0264   //! Evaluates the Rosenbrock function.
0265   //! @param[in] theX input vector (must have length 2)
0266   //! @param[out] theY function value
0267   //! @return true if evaluation succeeded
0268   bool Value(const math_Vector& theX, double& theY) const
0269   {
0270     const double x  = theX(theX.Lower());
0271     const double y  = theX(theX.Lower() + 1);
0272     const double t1 = myA - x;
0273     const double t2 = y - x * x;
0274     theY            = t1 * t1 + myB * t2 * t2;
0275     return true;
0276   }
0277 
0278   //! Evaluates the gradient of the Rosenbrock function.
0279   //! @param[in] theX input vector
0280   //! @param[out] theG gradient vector
0281   //! @return true if evaluation succeeded
0282   bool Gradient(const math_Vector& theX, math_Vector& theG) const
0283   {
0284     const double x         = theX(theX.Lower());
0285     const double y         = theX(theX.Lower() + 1);
0286     const double t2        = y - x * x;
0287     theG(theG.Lower())     = -2.0 * (myA - x) - 4.0 * myB * x * t2;
0288     theG(theG.Lower() + 1) = 2.0 * myB * t2;
0289     return true;
0290   }
0291 
0292   //! Evaluates both value and gradient.
0293   //! @param[in] theX input vector
0294   //! @param[out] theY function value
0295   //! @param[out] theG gradient vector
0296   //! @return true if evaluation succeeded
0297   bool Values(const math_Vector& theX, double& theY, math_Vector& theG) const
0298   {
0299     return Value(theX, theY) && Gradient(theX, theG);
0300   }
0301 
0302 private:
0303   double myA;
0304   double myB;
0305 };
0306 
0307 //! Sphere function functor (for testing optimization).
0308 //! f(x) = sum(x[i]^2) for all i.
0309 //! Global minimum at origin with f = 0.
0310 //!
0311 //! Usage:
0312 //! @code
0313 //! Sphere aSphere;
0314 //! math_Vector aStart(1, 3);
0315 //! aStart.Init(1.0);  // Start at (1, 1, 1)
0316 //! auto aResult = MathOpt::Powell(aSphere, aStart);
0317 //! // Should converge to (0, 0, 0)
0318 //! @endcode
0319 class Sphere
0320 {
0321 public:
0322   //! Evaluates the sphere function.
0323   //! @param[in] theX input vector
0324   //! @param[out] theY function value
0325   //! @return true (always succeeds)
0326   bool Value(const math_Vector& theX, double& theY) const
0327   {
0328     theY = 0.0;
0329     for (int i = theX.Lower(); i <= theX.Upper(); ++i)
0330     {
0331       theY += theX(i) * theX(i);
0332     }
0333     return true;
0334   }
0335 
0336   //! Evaluates the gradient of the sphere function.
0337   //! @param[in] theX input vector
0338   //! @param[out] theG gradient vector
0339   //! @return true (always succeeds)
0340   bool Gradient(const math_Vector& theX, math_Vector& theG) const
0341   {
0342     for (int i = theX.Lower(); i <= theX.Upper(); ++i)
0343     {
0344       theG(i) = 2.0 * theX(i);
0345     }
0346     return true;
0347   }
0348 
0349   //! Evaluates both value and gradient.
0350   //! @param[in] theX input vector
0351   //! @param[out] theY function value
0352   //! @param[out] theG gradient vector
0353   //! @return true (always succeeds)
0354   bool Values(const math_Vector& theX, double& theY, math_Vector& theG) const
0355   {
0356     return Value(theX, theY) && Gradient(theX, theG);
0357   }
0358 };
0359 
0360 //! Booth function functor (for testing optimization).
0361 //! f(x,y) = (x + 2y - 7)^2 + (2x + y - 5)^2
0362 //! Global minimum at (1, 3) with f = 0.
0363 //!
0364 //! Usage:
0365 //! @code
0366 //! Booth aBooth;
0367 //! math_Vector aStart(1, 2);
0368 //! aStart(1) = 0.0; aStart(2) = 0.0;
0369 //! auto aResult = MathOpt::BFGS(aBooth, aStart);
0370 //! // Should converge to (1, 3)
0371 //! @endcode
0372 class Booth
0373 {
0374 public:
0375   //! Evaluates the Booth function.
0376   //! @param[in] theX input vector (must have length 2)
0377   //! @param[out] theY function value
0378   //! @return true (always succeeds)
0379   bool Value(const math_Vector& theX, double& theY) const
0380   {
0381     const double x  = theX(theX.Lower());
0382     const double y  = theX(theX.Lower() + 1);
0383     const double t1 = x + 2.0 * y - 7.0;
0384     const double t2 = 2.0 * x + y - 5.0;
0385     theY            = t1 * t1 + t2 * t2;
0386     return true;
0387   }
0388 
0389   //! Evaluates the gradient of the Booth function.
0390   //! @param[in] theX input vector
0391   //! @param[out] theG gradient vector
0392   //! @return true (always succeeds)
0393   bool Gradient(const math_Vector& theX, math_Vector& theG) const
0394   {
0395     const double x         = theX(theX.Lower());
0396     const double y         = theX(theX.Lower() + 1);
0397     const double t1        = x + 2.0 * y - 7.0;
0398     const double t2        = 2.0 * x + y - 5.0;
0399     theG(theG.Lower())     = 2.0 * t1 + 4.0 * t2;
0400     theG(theG.Lower() + 1) = 4.0 * t1 + 2.0 * t2;
0401     return true;
0402   }
0403 
0404   //! Evaluates both value and gradient.
0405   //! @param[in] theX input vector
0406   //! @param[out] theY function value
0407   //! @param[out] theG gradient vector
0408   //! @return true (always succeeds)
0409   bool Values(const math_Vector& theX, double& theY, math_Vector& theG) const
0410   {
0411     return Value(theX, theY) && Gradient(theX, theG);
0412   }
0413 };
0414 
0415 //! Beale function functor (for testing optimization).
0416 //! f(x,y) = (1.5 - x + xy)^2 + (2.25 - x + xy^2)^2 + (2.625 - x + xy^3)^2
0417 //! Global minimum at (3, 0.5) with f = 0.
0418 class Beale
0419 {
0420 public:
0421   //! Evaluates the Beale function.
0422   //! @param[in] theX input vector (must have length 2)
0423   //! @param[out] theY function value
0424   //! @return true (always succeeds)
0425   bool Value(const math_Vector& theX, double& theY) const
0426   {
0427     const double x  = theX(theX.Lower());
0428     const double y  = theX(theX.Lower() + 1);
0429     const double t1 = 1.5 - x + x * y;
0430     const double t2 = 2.25 - x + x * y * y;
0431     const double t3 = 2.625 - x + x * y * y * y;
0432     theY            = t1 * t1 + t2 * t2 + t3 * t3;
0433     return true;
0434   }
0435 
0436   //! Evaluates the gradient of the Beale function.
0437   //! @param[in] theX input vector
0438   //! @param[out] theG gradient vector
0439   //! @return true (always succeeds)
0440   bool Gradient(const math_Vector& theX, math_Vector& theG) const
0441   {
0442     const double x         = theX(theX.Lower());
0443     const double y         = theX(theX.Lower() + 1);
0444     const double y2        = y * y;
0445     const double y3        = y2 * y;
0446     const double t1        = 1.5 - x + x * y;
0447     const double t2        = 2.25 - x + x * y2;
0448     const double t3        = 2.625 - x + x * y3;
0449     theG(theG.Lower())     = 2.0 * ((y - 1.0) * t1 + (y2 - 1.0) * t2 + (y3 - 1.0) * t3);
0450     theG(theG.Lower() + 1) = 2.0 * x * (t1 + 2.0 * y * t2 + 3.0 * y2 * t3);
0451     return true;
0452   }
0453 
0454   //! Evaluates both value and gradient.
0455   //! @param[in] theX input vector
0456   //! @param[out] theY function value
0457   //! @param[out] theG gradient vector
0458   //! @return true (always succeeds)
0459   bool Values(const math_Vector& theX, double& theY, math_Vector& theG) const
0460   {
0461     return Value(theX, theY) && Gradient(theX, theG);
0462   }
0463 };
0464 
0465 //! Himmelblau function functor (for testing optimization).
0466 //! f(x,y) = (x^2 + y - 11)^2 + (x + y^2 - 7)^2
0467 //! Has four local minima, all with f = 0:
0468 //! (3.0, 2.0), (-2.805118, 3.131312), (-3.779310, -3.283186), (3.584428, -1.848126)
0469 class Himmelblau
0470 {
0471 public:
0472   //! Evaluates the Himmelblau function.
0473   //! @param[in] theX input vector (must have length 2)
0474   //! @param[out] theY function value
0475   //! @return true (always succeeds)
0476   bool Value(const math_Vector& theX, double& theY) const
0477   {
0478     const double x  = theX(theX.Lower());
0479     const double y  = theX(theX.Lower() + 1);
0480     const double t1 = x * x + y - 11.0;
0481     const double t2 = x + y * y - 7.0;
0482     theY            = t1 * t1 + t2 * t2;
0483     return true;
0484   }
0485 
0486   //! Evaluates the gradient of the Himmelblau function.
0487   //! @param[in] theX input vector
0488   //! @param[out] theG gradient vector
0489   //! @return true (always succeeds)
0490   bool Gradient(const math_Vector& theX, math_Vector& theG) const
0491   {
0492     const double x         = theX(theX.Lower());
0493     const double y         = theX(theX.Lower() + 1);
0494     const double t1        = x * x + y - 11.0;
0495     const double t2        = x + y * y - 7.0;
0496     theG(theG.Lower())     = 4.0 * x * t1 + 2.0 * t2;
0497     theG(theG.Lower() + 1) = 2.0 * t1 + 4.0 * y * t2;
0498     return true;
0499   }
0500 
0501   //! Evaluates both value and gradient.
0502   //! @param[in] theX input vector
0503   //! @param[out] theY function value
0504   //! @param[out] theG gradient vector
0505   //! @return true (always succeeds)
0506   bool Values(const math_Vector& theX, double& theY, math_Vector& theG) const
0507   {
0508     return Value(theX, theY) && Gradient(theX, theG);
0509   }
0510 };
0511 
0512 //! Rastrigin function functor (for testing global optimization).
0513 //! f(x) = A*n + sum(x[i]^2 - A*cos(2*pi*x[i])) for all i
0514 //! Default: A = 10
0515 //! Global minimum at origin with f = 0.
0516 //! Highly multimodal - challenging for local optimizers.
0517 class Rastrigin
0518 {
0519 public:
0520   //! Constructor with parameter.
0521   //! @param theA parameter A (default 10.0)
0522   explicit Rastrigin(double theA = 10.0)
0523       : myA(theA)
0524   {
0525   }
0526 
0527   //! Evaluates the Rastrigin function.
0528   //! @param[in] theX input vector
0529   //! @param[out] theY function value
0530   //! @return true (always succeeds)
0531   bool Value(const math_Vector& theX, double& theY) const
0532   {
0533     constexpr double aTwoPi = 2.0 * 3.14159265358979323846;
0534     const int        n      = theX.Upper() - theX.Lower() + 1;
0535     theY                    = myA * static_cast<double>(n);
0536     for (int i = theX.Lower(); i <= theX.Upper(); ++i)
0537     {
0538       theY += theX(i) * theX(i) - myA * std::cos(aTwoPi * theX(i));
0539     }
0540     return true;
0541   }
0542 
0543   //! Evaluates the gradient of the Rastrigin function.
0544   //! @param[in] theX input vector
0545   //! @param[out] theG gradient vector
0546   //! @return true (always succeeds)
0547   bool Gradient(const math_Vector& theX, math_Vector& theG) const
0548   {
0549     constexpr double aTwoPi = 2.0 * 3.14159265358979323846;
0550     for (int i = theX.Lower(); i <= theX.Upper(); ++i)
0551     {
0552       theG(i) = 2.0 * theX(i) + myA * aTwoPi * std::sin(aTwoPi * theX(i));
0553     }
0554     return true;
0555   }
0556 
0557   //! Evaluates both value and gradient.
0558   //! @param[in] theX input vector
0559   //! @param[out] theY function value
0560   //! @param[out] theG gradient vector
0561   //! @return true (always succeeds)
0562   bool Values(const math_Vector& theX, double& theY, math_Vector& theG) const
0563   {
0564     return Value(theX, theY) && Gradient(theX, theG);
0565   }
0566 
0567 private:
0568   double myA;
0569 };
0570 
0571 //! Ackley function functor (for testing global optimization).
0572 //! f(x) = -a*exp(-b*sqrt(sum(x[i]^2)/n)) - exp(sum(cos(c*x[i]))/n) + a + e
0573 //! Default: a = 20, b = 0.2, c = 2*pi
0574 //! Global minimum at origin with f = 0.
0575 class Ackley
0576 {
0577 public:
0578   //! Constructor with parameters.
0579   //! @param theA parameter a (default 20.0)
0580   //! @param theB parameter b (default 0.2)
0581   //! @param theC parameter c (default 2*pi)
0582   Ackley(double theA = 20.0, double theB = 0.2, double theC = 2.0 * 3.14159265358979323846)
0583       : myA(theA),
0584         myB(theB),
0585         myC(theC)
0586   {
0587   }
0588 
0589   //! Evaluates the Ackley function.
0590   //! @param[in] theX input vector
0591   //! @param[out] theY function value
0592   //! @return true (always succeeds)
0593   bool Value(const math_Vector& theX, double& theY) const
0594   {
0595     constexpr double aE      = 2.718281828459045;
0596     const int        n       = theX.Upper() - theX.Lower() + 1;
0597     double           aSumSq  = 0.0;
0598     double           aSumCos = 0.0;
0599     for (int i = theX.Lower(); i <= theX.Upper(); ++i)
0600     {
0601       aSumSq += theX(i) * theX(i);
0602       aSumCos += std::cos(myC * theX(i));
0603     }
0604     theY = -myA * std::exp(-myB * std::sqrt(aSumSq / n)) - std::exp(aSumCos / n) + myA + aE;
0605     return true;
0606   }
0607 
0608 private:
0609   double myA;
0610   double myB;
0611   double myC;
0612 };
0613 
0614 //! Linear system residual functor: f(x) = ||Ax - b||^2.
0615 //! Useful for solving overdetermined linear systems via optimization.
0616 //!
0617 //! Usage:
0618 //! @code
0619 //! math_Matrix A(1, 3, 1, 2);  // 3x2 overdetermined system
0620 //! math_Vector b(1, 3);
0621 //! // ... fill A and b ...
0622 //! LinearResidual aRes(A, b);
0623 //! math_Vector aStart(1, 2);
0624 //! aStart.Init(0.0);
0625 //! auto aResult = MathOpt::BFGS(aRes, aStart);
0626 //! @endcode
0627 class LinearResidual
0628 {
0629 public:
0630   //! Constructor from matrix and right-hand side.
0631   //! @param theA coefficient matrix (m x n)
0632   //! @param theB right-hand side vector (m)
0633   LinearResidual(const math_Matrix& theA, const math_Vector& theB)
0634       : myA(theA),
0635         myB(theB)
0636   {
0637   }
0638 
0639   //! Evaluates the residual ||Ax - b||^2.
0640   //! @param[in] theX solution vector (n)
0641   //! @param[out] theY squared residual norm
0642   //! @return true (always succeeds)
0643   bool Value(const math_Vector& theX, double& theY) const
0644   {
0645     theY = 0.0;
0646     for (int i = myA.LowerRow(); i <= myA.UpperRow(); ++i)
0647     {
0648       double aResidual = -myB(i);
0649       for (int j = myA.LowerCol(); j <= myA.UpperCol(); ++j)
0650       {
0651         aResidual += myA(i, j) * theX(j);
0652       }
0653       theY += aResidual * aResidual;
0654     }
0655     return true;
0656   }
0657 
0658   //! Evaluates the gradient: g = 2 * A^T * (Ax - b).
0659   //! @param[in] theX solution vector
0660   //! @param[out] theG gradient vector
0661   //! @return true (always succeeds)
0662   bool Gradient(const math_Vector& theX, math_Vector& theG) const
0663   {
0664     // First compute residual r = Ax - b
0665     const int   m = myA.UpperRow() - myA.LowerRow() + 1;
0666     math_Vector aResidual(1, m);
0667     for (int i = myA.LowerRow(); i <= myA.UpperRow(); ++i)
0668     {
0669       aResidual(i - myA.LowerRow() + 1) = -myB(i);
0670       for (int j = myA.LowerCol(); j <= myA.UpperCol(); ++j)
0671       {
0672         aResidual(i - myA.LowerRow() + 1) += myA(i, j) * theX(j);
0673       }
0674     }
0675     // Then compute g = 2 * A^T * r
0676     for (int j = myA.LowerCol(); j <= myA.UpperCol(); ++j)
0677     {
0678       theG(j) = 0.0;
0679       for (int i = myA.LowerRow(); i <= myA.UpperRow(); ++i)
0680       {
0681         theG(j) += 2.0 * myA(i, j) * aResidual(i - myA.LowerRow() + 1);
0682       }
0683     }
0684     return true;
0685   }
0686 
0687   //! Evaluates both value and gradient.
0688   //! @param[in] theX solution vector
0689   //! @param[out] theY squared residual norm
0690   //! @param[out] theG gradient vector
0691   //! @return true (always succeeds)
0692   bool Values(const math_Vector& theX, double& theY, math_Vector& theG) const
0693   {
0694     return Value(theX, theY) && Gradient(theX, theG);
0695   }
0696 
0697 private:
0698   math_Matrix myA;
0699   math_Vector myB;
0700 };
0701 
0702 //! Nonlinear system functor: F(x) = [f1(x), f2(x), ..., fn(x)].
0703 //! Lambda wrapper for systems of nonlinear equations.
0704 //!
0705 //! Usage:
0706 //! @code
0707 //! auto aSys = SystemLambda([](const math_Vector& x, math_Vector& f) {
0708 //!   f(1) = x(1)*x(1) + x(2)*x(2) - 1.0;  // Circle
0709 //!   f(2) = x(1) - x(2);                   // Line y=x
0710 //!   return true;
0711 //! });
0712 //! auto aResult = MathSys::Newton(aSys, aStartPoint);
0713 //! @endcode
0714 //!
0715 //! @tparam Lambda callable with signature bool(const math_Vector&, math_Vector&)
0716 template <typename Lambda>
0717 class SystemLambda
0718 {
0719 public:
0720   //! Constructor from lambda.
0721   //! @param theLambda callable for system evaluation
0722   //! @param theNbEquations number of equations in the system
0723   SystemLambda(Lambda theLambda, int theNbEquations)
0724       : myLambda(std::move(theLambda)),
0725         myNbEquations(theNbEquations)
0726   {
0727   }
0728 
0729   //! Returns the number of equations.
0730   //! @return number of equations
0731   int NbEquations() const { return myNbEquations; }
0732 
0733   //! Evaluates the system F(x).
0734   //! @param[in] theX input vector
0735   //! @param[out] theF system values
0736   //! @return true if evaluation succeeded
0737   bool Value(const math_Vector& theX, math_Vector& theF) const { return myLambda(theX, theF); }
0738 
0739 private:
0740   Lambda myLambda;
0741   int    myNbEquations;
0742 };
0743 
0744 //! Helper function to create SystemLambda with type deduction.
0745 //! @tparam Lambda callable type
0746 //! @param theLambda callable for system evaluation
0747 //! @param theNbEquations number of equations
0748 //! @return SystemLambda wrapper
0749 template <typename Lambda>
0750 SystemLambda<Lambda> MakeSystem(Lambda theLambda, int theNbEquations)
0751 {
0752   return SystemLambda<Lambda>(std::move(theLambda), theNbEquations);
0753 }
0754 
0755 } // namespace MathUtils
0756 
0757 #endif // _MathUtils_FunctorVector_HeaderFile