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_FunctorScalar_HeaderFile
0015 #define _MathUtils_FunctorScalar_HeaderFile
0016 
0017 #include <math_Vector.hxx>
0018 
0019 #include <cmath>
0020 #include <initializer_list>
0021 #include <utility>
0022 
0023 //! @file MathUtils_FunctorScalar.hxx
0024 //! @brief Non-virtual functor classes for scalar (1D) functions.
0025 //!
0026 //! Provides ready-to-use functor classes that work with the template-based
0027 //! math API (MathRoot, MathOpt, MathInteg) without virtual dispatch overhead.
0028 
0029 //! Core utilities for modern math solvers.
0030 namespace MathUtils
0031 {
0032 
0033 //! Lambda wrapper for scalar functions with value only.
0034 //! Wraps a lambda/callable into a functor with Value() method.
0035 //!
0036 //! Usage:
0037 //! @code
0038 //! auto aFunc = ScalarLambda([](double x, double& y) {
0039 //!   y = x * x - 2.0;
0040 //!   return true;
0041 //! });
0042 //! auto aResult = MathRoot::Brent(aFunc, 0.0, 2.0);
0043 //! @endcode
0044 //!
0045 //! @tparam Lambda callable type with signature bool(double, double&)
0046 template <typename Lambda>
0047 class ScalarLambda
0048 {
0049 public:
0050   //! Constructor from lambda/callable.
0051   //! @param theLambda callable with signature bool(double theX, double& theY)
0052   explicit ScalarLambda(Lambda theLambda)
0053       : myLambda(std::move(theLambda))
0054   {
0055   }
0056 
0057   //! Evaluates the function at theX.
0058   //! @param[in] theX input value
0059   //! @param[out] theY function value f(theX)
0060   //! @return true if evaluation succeeded
0061   bool Value(double theX, double& theY) const { return myLambda(theX, theY); }
0062 
0063 private:
0064   Lambda myLambda;
0065 };
0066 
0067 //! Lambda wrapper for scalar functions with value and derivative.
0068 //! Wraps a lambda/callable into a functor with Values() method.
0069 //!
0070 //! Usage:
0071 //! @code
0072 //! auto aFunc = ScalarLambdaWithDerivative([](double x, double& y, double& dy) {
0073 //!   y = x * x - 2.0;
0074 //!   dy = 2.0 * x;
0075 //!   return true;
0076 //! });
0077 //! auto aResult = MathRoot::Newton(aFunc, 1.0);
0078 //! @endcode
0079 //!
0080 //! @tparam Lambda callable type with signature bool(double, double&, double&)
0081 template <typename Lambda>
0082 class ScalarLambdaWithDerivative
0083 {
0084 public:
0085   //! Constructor from lambda/callable.
0086   //! @param theLambda callable with signature bool(double theX, double& theY, double& theDY)
0087   explicit ScalarLambdaWithDerivative(Lambda theLambda)
0088       : myLambda(std::move(theLambda))
0089   {
0090   }
0091 
0092   //! Evaluates function and derivative at theX.
0093   //! @param[in] theX input value
0094   //! @param[out] theY function value f(theX)
0095   //! @param[out] theDY derivative value f'(theX)
0096   //! @return true if evaluation succeeded
0097   bool Values(double theX, double& theY, double& theDY) const
0098   {
0099     return myLambda(theX, theY, theDY);
0100   }
0101 
0102   //! Evaluates only the function value (for algorithms that don't need derivative).
0103   //! @param[in] theX input value
0104   //! @param[out] theY function value f(theX)
0105   //! @return true if evaluation succeeded
0106   bool Value(double theX, double& theY) const
0107   {
0108     double aDummy = 0.0;
0109     return myLambda(theX, theY, aDummy);
0110   }
0111 
0112 private:
0113   Lambda myLambda;
0114 };
0115 
0116 //! Helper function to create ScalarLambda with type deduction.
0117 //! @tparam Lambda callable type (auto-deduced)
0118 //! @param theLambda callable with signature bool(double, double&)
0119 //! @return ScalarLambda wrapper
0120 template <typename Lambda>
0121 ScalarLambda<Lambda> MakeScalar(Lambda theLambda)
0122 {
0123   return ScalarLambda<Lambda>(std::move(theLambda));
0124 }
0125 
0126 //! Helper function to create ScalarLambdaWithDerivative with type deduction.
0127 //! @tparam Lambda callable type (auto-deduced)
0128 //! @param theLambda callable with signature bool(double, double&, double&)
0129 //! @return ScalarLambdaWithDerivative wrapper
0130 template <typename Lambda>
0131 ScalarLambdaWithDerivative<Lambda> MakeScalarWithDerivative(Lambda theLambda)
0132 {
0133   return ScalarLambdaWithDerivative<Lambda>(std::move(theLambda));
0134 }
0135 
0136 //! Polynomial functor: f(x) = sum(a[i] * x^i).
0137 //! Coefficients are stored in order: a[0] + a[1]*x + a[2]*x^2 + ...
0138 //!
0139 //! Usage:
0140 //! @code
0141 //! // x^2 - 2 (find sqrt(2))
0142 //! Polynomial aPoly({-2.0, 0.0, 1.0});
0143 //!
0144 //! // x^3 - 6x^2 + 11x - 6 = (x-1)(x-2)(x-3)
0145 //! Polynomial aCubic({-6.0, 11.0, -6.0, 1.0});
0146 //! @endcode
0147 class Polynomial
0148 {
0149 public:
0150   //! Constructor from initializer list.
0151   //! @param theCoeffs coefficients in ascending power order
0152   Polynomial(std::initializer_list<double> theCoeffs)
0153       : myCoeffs(0, static_cast<int>(theCoeffs.size()) - 1)
0154   {
0155     int anIdx = 0;
0156     for (double aCoeff : theCoeffs)
0157     {
0158       myCoeffs(anIdx++) = aCoeff;
0159     }
0160   }
0161 
0162   //! Constructor from math_Vector.
0163   //! @param theCoeffs coefficients in ascending power order
0164   explicit Polynomial(const math_Vector& theCoeffs)
0165       : myCoeffs(theCoeffs)
0166   {
0167   }
0168 
0169   //! Evaluates polynomial at theX using Horner's method.
0170   //! @param[in] theX input value
0171   //! @param[out] theY polynomial value p(theX)
0172   //! @return true (always succeeds for polynomials)
0173   bool Value(double theX, double& theY) const
0174   {
0175     if (myCoeffs.Length() <= 0)
0176     {
0177       theY = 0.0;
0178       return true;
0179     }
0180 
0181     // Horner's method: p(x) = a[0] + x*(a[1] + x*(a[2] + ...))
0182     const int aLast = myCoeffs.Upper();
0183     theY            = myCoeffs(aLast);
0184     for (int i = aLast - 1; i >= myCoeffs.Lower(); --i)
0185     {
0186       theY = theY * theX + myCoeffs(i);
0187     }
0188     return true;
0189   }
0190 
0191   //! Evaluates polynomial and its derivative at theX.
0192   //! @param[in] theX input value
0193   //! @param[out] theY polynomial value p(theX)
0194   //! @param[out] theDY derivative value p'(theX)
0195   //! @return true (always succeeds for polynomials)
0196   bool Values(double theX, double& theY, double& theDY) const
0197   {
0198     if (myCoeffs.Length() <= 0)
0199     {
0200       theY  = 0.0;
0201       theDY = 0.0;
0202       return true;
0203     }
0204 
0205     const int n = myCoeffs.Length();
0206     if (n == 1)
0207     {
0208       theY  = myCoeffs(myCoeffs.Lower());
0209       theDY = 0.0;
0210       return true;
0211     }
0212 
0213     // Horner's method for value and derivative simultaneously
0214     const int aLower = myCoeffs.Lower();
0215     const int aLast  = myCoeffs.Upper();
0216     theY             = myCoeffs(aLast);
0217     theDY            = 0.0;
0218     for (int i = aLast - 1; i >= aLower; --i)
0219     {
0220       theDY = theDY * theX + theY;
0221       theY  = theY * theX + myCoeffs(i);
0222     }
0223     return true;
0224   }
0225 
0226   //! Returns the degree of the polynomial.
0227   //! @return polynomial degree (number of coefficients - 1)
0228   int Degree() const { return myCoeffs.Length() <= 0 ? 0 : myCoeffs.Length() - 1; }
0229 
0230   //! Returns coefficient by index.
0231   //! @param theIndex coefficient index (0 = constant term)
0232   //! @return coefficient value
0233   double Coefficient(int theIndex) const
0234   {
0235     const int aIdx = myCoeffs.Lower() + theIndex;
0236     return (aIdx >= myCoeffs.Lower() && aIdx <= myCoeffs.Upper()) ? myCoeffs(aIdx) : 0.0;
0237   }
0238 
0239 private:
0240   math_Vector myCoeffs;
0241 };
0242 
0243 //! Rational function functor: f(x) = P(x) / Q(x).
0244 //! Both numerator P and denominator Q are polynomials.
0245 //!
0246 //! Usage:
0247 //! @code
0248 //! // (x + 1) / (x^2 + 1)
0249 //! Rational aRat({1.0, 1.0}, {1.0, 0.0, 1.0});
0250 //! @endcode
0251 class Rational
0252 {
0253 public:
0254   //! Constructor from math_Vector.
0255   //! @param theNum numerator coefficients (ascending power order)
0256   //! @param theDenom denominator coefficients (ascending power order)
0257   Rational(const math_Vector& theNum, const math_Vector& theDenom)
0258       : myNum(theNum),
0259         myDenom(theDenom)
0260   {
0261   }
0262 
0263   //! Constructor from initializer lists.
0264   //! @param theNum numerator coefficients
0265   //! @param theDenom denominator coefficients
0266   Rational(std::initializer_list<double> theNum, std::initializer_list<double> theDenom)
0267       : myNum(0, static_cast<int>(theNum.size()) - 1),
0268         myDenom(0, static_cast<int>(theDenom.size()) - 1)
0269   {
0270     int anIdx = 0;
0271     for (double aCoeff : theNum)
0272     {
0273       myNum(anIdx++) = aCoeff;
0274     }
0275     anIdx = 0;
0276     for (double aCoeff : theDenom)
0277     {
0278       myDenom(anIdx++) = aCoeff;
0279     }
0280   }
0281 
0282   //! Evaluates rational function at theX.
0283   //! @param[in] theX input value
0284   //! @param[out] theY function value P(theX)/Q(theX)
0285   //! @return false if denominator is zero
0286   bool Value(double theX, double& theY) const
0287   {
0288     double aNum   = 0.0;
0289     double aDenom = 0.0;
0290 
0291     // Evaluate numerator using Horner's method
0292     if (myNum.Length() > 0)
0293     {
0294       const int aLast = myNum.Upper();
0295       aNum            = myNum(aLast);
0296       for (int i = aLast - 1; i >= myNum.Lower(); --i)
0297       {
0298         aNum = aNum * theX + myNum(i);
0299       }
0300     }
0301 
0302     // Evaluate denominator using Horner's method
0303     if (myDenom.Length() > 0)
0304     {
0305       const int aLast = myDenom.Upper();
0306       aDenom          = myDenom(aLast);
0307       for (int i = aLast - 1; i >= myDenom.Lower(); --i)
0308       {
0309         aDenom = aDenom * theX + myDenom(i);
0310       }
0311     }
0312 
0313     // Check for division by zero
0314     if (std::abs(aDenom) < 1e-15)
0315     {
0316       return false;
0317     }
0318 
0319     theY = aNum / aDenom;
0320     return true;
0321   }
0322 
0323 private:
0324   math_Vector myNum;
0325   math_Vector myDenom;
0326 };
0327 
0328 //! Composite functor: f(g(x)).
0329 //! Evaluates the outer function at the result of the inner function.
0330 //!
0331 //! Usage:
0332 //! @code
0333 //! Polynomial aInner({0.0, 1.0});         // g(x) = x
0334 //! Polynomial aOuter({-1.0, 0.0, 1.0});   // f(x) = x^2 - 1
0335 //! Composite aComp(aOuter, aInner);       // f(g(x)) = x^2 - 1
0336 //! @endcode
0337 //!
0338 //! @tparam Outer outer function type (must have Value method)
0339 //! @tparam Inner inner function type (must have Value method)
0340 template <typename Outer, typename Inner>
0341 class Composite
0342 {
0343 public:
0344   //! Constructor from outer and inner functions.
0345   //! @param theOuter outer function f
0346   //! @param theInner inner function g
0347   Composite(Outer theOuter, Inner theInner)
0348       : myOuter(std::move(theOuter)),
0349         myInner(std::move(theInner))
0350   {
0351   }
0352 
0353   //! Evaluates composite function f(g(theX)).
0354   //! @param[in] theX input value
0355   //! @param[out] theY function value f(g(theX))
0356   //! @return false if either evaluation fails
0357   bool Value(double theX, double& theY) const
0358   {
0359     double aInner = 0.0;
0360     if (!myInner.Value(theX, aInner))
0361     {
0362       return false;
0363     }
0364     return myOuter.Value(aInner, theY);
0365   }
0366 
0367 private:
0368   Outer myOuter;
0369   Inner myInner;
0370 };
0371 
0372 //! Helper function to create Composite with type deduction.
0373 //! @tparam Outer outer function type
0374 //! @tparam Inner inner function type
0375 //! @param theOuter outer function f
0376 //! @param theInner inner function g
0377 //! @return Composite functor representing f(g(x))
0378 template <typename Outer, typename Inner>
0379 Composite<Outer, Inner> MakeComposite(Outer theOuter, Inner theInner)
0380 {
0381   return Composite<Outer, Inner>(std::move(theOuter), std::move(theInner));
0382 }
0383 
0384 //! Sum of functions functor: f(x) + g(x).
0385 //!
0386 //! Usage:
0387 //! @code
0388 //! Polynomial aF({1.0, 2.0});   // f(x) = 1 + 2x
0389 //! Polynomial aG({3.0, 0.0, 1.0}); // g(x) = 3 + x^2
0390 //! Sum aSum(aF, aG);            // h(x) = 4 + 2x + x^2
0391 //! @endcode
0392 //!
0393 //! @tparam F first function type
0394 //! @tparam G second function type
0395 template <typename F, typename G>
0396 class Sum
0397 {
0398 public:
0399   //! Constructor from two functions.
0400   //! @param theF first function
0401   //! @param theG second function
0402   Sum(F theF, G theG)
0403       : myF(std::move(theF)),
0404         myG(std::move(theG))
0405   {
0406   }
0407 
0408   //! Evaluates sum f(theX) + g(theX).
0409   //! @param[in] theX input value
0410   //! @param[out] theY sum value
0411   //! @return false if either evaluation fails
0412   bool Value(double theX, double& theY) const
0413   {
0414     double aF = 0.0;
0415     double aG = 0.0;
0416     if (!myF.Value(theX, aF))
0417     {
0418       return false;
0419     }
0420     if (!myG.Value(theX, aG))
0421     {
0422       return false;
0423     }
0424     theY = aF + aG;
0425     return true;
0426   }
0427 
0428 private:
0429   F myF;
0430   G myG;
0431 };
0432 
0433 //! Helper function to create Sum with type deduction.
0434 template <typename F, typename G>
0435 Sum<F, G> MakeSum(F theF, G theG)
0436 {
0437   return Sum<F, G>(std::move(theF), std::move(theG));
0438 }
0439 
0440 //! Difference of functions functor: f(x) - g(x).
0441 //!
0442 //! @tparam F first function type
0443 //! @tparam G second function type
0444 template <typename F, typename G>
0445 class Difference
0446 {
0447 public:
0448   //! Constructor from two functions.
0449   //! @param theF first function (minuend)
0450   //! @param theG second function (subtrahend)
0451   Difference(F theF, G theG)
0452       : myF(std::move(theF)),
0453         myG(std::move(theG))
0454   {
0455   }
0456 
0457   //! Evaluates difference f(theX) - g(theX).
0458   //! @param[in] theX input value
0459   //! @param[out] theY difference value
0460   //! @return false if either evaluation fails
0461   bool Value(double theX, double& theY) const
0462   {
0463     double aF = 0.0;
0464     double aG = 0.0;
0465     if (!myF.Value(theX, aF))
0466     {
0467       return false;
0468     }
0469     if (!myG.Value(theX, aG))
0470     {
0471       return false;
0472     }
0473     theY = aF - aG;
0474     return true;
0475   }
0476 
0477 private:
0478   F myF;
0479   G myG;
0480 };
0481 
0482 //! Helper function to create Difference with type deduction.
0483 template <typename F, typename G>
0484 Difference<F, G> MakeDifference(F theF, G theG)
0485 {
0486   return Difference<F, G>(std::move(theF), std::move(theG));
0487 }
0488 
0489 //! Product of functions functor: f(x) * g(x).
0490 //!
0491 //! @tparam F first function type
0492 //! @tparam G second function type
0493 template <typename F, typename G>
0494 class Product
0495 {
0496 public:
0497   //! Constructor from two functions.
0498   //! @param theF first function (multiplicand)
0499   //! @param theG second function (multiplier)
0500   Product(F theF, G theG)
0501       : myF(std::move(theF)),
0502         myG(std::move(theG))
0503   {
0504   }
0505 
0506   //! Evaluates product f(theX) * g(theX).
0507   //! @param[in] theX input value
0508   //! @param[out] theY product value
0509   //! @return false if either evaluation fails
0510   bool Value(double theX, double& theY) const
0511   {
0512     double aF = 0.0;
0513     double aG = 0.0;
0514     if (!myF.Value(theX, aF))
0515     {
0516       return false;
0517     }
0518     if (!myG.Value(theX, aG))
0519     {
0520       return false;
0521     }
0522     theY = aF * aG;
0523     return true;
0524   }
0525 
0526 private:
0527   F myF;
0528   G myG;
0529 };
0530 
0531 //! Helper function to create Product with type deduction.
0532 template <typename F, typename G>
0533 Product<F, G> MakeProduct(F theF, G theG)
0534 {
0535   return Product<F, G>(std::move(theF), std::move(theG));
0536 }
0537 
0538 //! Quotient of functions functor: f(x) / g(x).
0539 //!
0540 //! @tparam F numerator function type
0541 //! @tparam G denominator function type
0542 template <typename F, typename G>
0543 class Quotient
0544 {
0545 public:
0546   //! Constructor from two functions.
0547   //! @param theF numerator function
0548   //! @param theG denominator function
0549   Quotient(F theF, G theG)
0550       : myF(std::move(theF)),
0551         myG(std::move(theG))
0552   {
0553   }
0554 
0555   //! Evaluates quotient f(theX) / g(theX).
0556   //! @param[in] theX input value
0557   //! @param[out] theY quotient value
0558   //! @return false if evaluation fails or denominator is zero
0559   bool Value(double theX, double& theY) const
0560   {
0561     double aF = 0.0;
0562     double aG = 0.0;
0563     if (!myF.Value(theX, aF))
0564     {
0565       return false;
0566     }
0567     if (!myG.Value(theX, aG))
0568     {
0569       return false;
0570     }
0571     if (std::abs(aG) < 1e-15)
0572     {
0573       return false;
0574     }
0575     theY = aF / aG;
0576     return true;
0577   }
0578 
0579 private:
0580   F myF;
0581   G myG;
0582 };
0583 
0584 //! Helper function to create Quotient with type deduction.
0585 template <typename F, typename G>
0586 Quotient<F, G> MakeQuotient(F theF, G theG)
0587 {
0588   return Quotient<F, G>(std::move(theF), std::move(theG));
0589 }
0590 
0591 //! Scaled function functor: c * f(x).
0592 //!
0593 //! @tparam F function type
0594 template <typename F>
0595 class Scaled
0596 {
0597 public:
0598   //! Constructor from function and scale factor.
0599   //! @param theF function to scale
0600   //! @param theScale scale factor
0601   Scaled(F theF, double theScale)
0602       : myF(std::move(theF)),
0603         myScale(theScale)
0604   {
0605   }
0606 
0607   //! Evaluates scaled function c * f(theX).
0608   //! @param[in] theX input value
0609   //! @param[out] theY scaled value
0610   //! @return false if evaluation fails
0611   bool Value(double theX, double& theY) const
0612   {
0613     double aF = 0.0;
0614     if (!myF.Value(theX, aF))
0615     {
0616       return false;
0617     }
0618     theY = myScale * aF;
0619     return true;
0620   }
0621 
0622 private:
0623   F      myF;
0624   double myScale;
0625 };
0626 
0627 //! Helper function to create Scaled with type deduction.
0628 template <typename F>
0629 Scaled<F> MakeScaled(F theF, double theScale)
0630 {
0631   return Scaled<F>(std::move(theF), theScale);
0632 }
0633 
0634 //! Shifted function functor: f(x) + c.
0635 //!
0636 //! @tparam F function type
0637 template <typename F>
0638 class Shifted
0639 {
0640 public:
0641   //! Constructor from function and shift value.
0642   //! @param theF function to shift
0643   //! @param theShift shift value (added to output)
0644   Shifted(F theF, double theShift)
0645       : myF(std::move(theF)),
0646         myShift(theShift)
0647   {
0648   }
0649 
0650   //! Evaluates shifted function f(theX) + c.
0651   //! @param[in] theX input value
0652   //! @param[out] theY shifted value
0653   //! @return false if evaluation fails
0654   bool Value(double theX, double& theY) const
0655   {
0656     double aF = 0.0;
0657     if (!myF.Value(theX, aF))
0658     {
0659       return false;
0660     }
0661     theY = aF + myShift;
0662     return true;
0663   }
0664 
0665 private:
0666   F      myF;
0667   double myShift;
0668 };
0669 
0670 //! Helper function to create Shifted with type deduction.
0671 template <typename F>
0672 Shifted<F> MakeShifted(F theF, double theShift)
0673 {
0674   return Shifted<F>(std::move(theF), theShift);
0675 }
0676 
0677 //! Negated function functor: -f(x).
0678 //!
0679 //! @tparam F function type
0680 template <typename F>
0681 class Negated
0682 {
0683 public:
0684   //! Constructor from function.
0685   //! @param theF function to negate
0686   explicit Negated(F theF)
0687       : myF(std::move(theF))
0688   {
0689   }
0690 
0691   //! Evaluates negated function -f(theX).
0692   //! @param[in] theX input value
0693   //! @param[out] theY negated value
0694   //! @return false if evaluation fails
0695   bool Value(double theX, double& theY) const
0696   {
0697     double aF = 0.0;
0698     if (!myF.Value(theX, aF))
0699     {
0700       return false;
0701     }
0702     theY = -aF;
0703     return true;
0704   }
0705 
0706 private:
0707   F myF;
0708 };
0709 
0710 //! Helper function to create Negated with type deduction.
0711 template <typename F>
0712 Negated<F> MakeNegated(F theF)
0713 {
0714   return Negated<F>(std::move(theF));
0715 }
0716 
0717 //! Constant function functor: f(x) = c.
0718 class Constant
0719 {
0720 public:
0721   //! Constructor from constant value.
0722   //! @param theValue constant value
0723   explicit Constant(double theValue)
0724       : myValue(theValue)
0725   {
0726   }
0727 
0728   //! Evaluates constant function.
0729   //! @param[in] theX input value (ignored)
0730   //! @param[out] theY constant value
0731   //! @return true (always succeeds)
0732   bool Value(double /*theX*/, double& theY) const
0733   {
0734     theY = myValue;
0735     return true;
0736   }
0737 
0738   //! Evaluates constant and derivative (derivative is always 0).
0739   //! @param[in] theX input value (ignored)
0740   //! @param[out] theY constant value
0741   //! @param[out] theDY derivative (always 0)
0742   //! @return true (always succeeds)
0743   bool Values(double /*theX*/, double& theY, double& theDY) const
0744   {
0745     theY  = myValue;
0746     theDY = 0.0;
0747     return true;
0748   }
0749 
0750 private:
0751   double myValue;
0752 };
0753 
0754 //! Linear function functor: f(x) = a*x + b.
0755 class Linear
0756 {
0757 public:
0758   //! Constructor from slope and intercept.
0759   //! @param theSlope coefficient a (slope)
0760   //! @param theIntercept coefficient b (y-intercept)
0761   Linear(double theSlope, double theIntercept)
0762       : mySlope(theSlope),
0763         myIntercept(theIntercept)
0764   {
0765   }
0766 
0767   //! Evaluates linear function a*x + b.
0768   //! @param[in] theX input value
0769   //! @param[out] theY function value
0770   //! @return true (always succeeds)
0771   bool Value(double theX, double& theY) const
0772   {
0773     theY = mySlope * theX + myIntercept;
0774     return true;
0775   }
0776 
0777   //! Evaluates linear function and derivative.
0778   //! @param[in] theX input value
0779   //! @param[out] theY function value
0780   //! @param[out] theDY derivative (= slope)
0781   //! @return true (always succeeds)
0782   bool Values(double theX, double& theY, double& theDY) const
0783   {
0784     theY  = mySlope * theX + myIntercept;
0785     theDY = mySlope;
0786     return true;
0787   }
0788 
0789 private:
0790   double mySlope;
0791   double myIntercept;
0792 };
0793 
0794 //! Sine function functor: f(x) = a * sin(b*x + c) + d.
0795 class Sine
0796 {
0797 public:
0798   //! Constructor with full parameters.
0799   //! @param theAmplitude amplitude a
0800   //! @param theFrequency angular frequency b
0801   //! @param thePhase phase shift c
0802   //! @param theOffset vertical offset d
0803   Sine(double theAmplitude = 1.0,
0804        double theFrequency = 1.0,
0805        double thePhase     = 0.0,
0806        double theOffset    = 0.0)
0807       : myAmplitude(theAmplitude),
0808         myFrequency(theFrequency),
0809         myPhase(thePhase),
0810         myOffset(theOffset)
0811   {
0812   }
0813 
0814   //! Evaluates sine function.
0815   //! @param[in] theX input value
0816   //! @param[out] theY function value
0817   //! @return true (always succeeds)
0818   bool Value(double theX, double& theY) const
0819   {
0820     theY = myAmplitude * std::sin(myFrequency * theX + myPhase) + myOffset;
0821     return true;
0822   }
0823 
0824   //! Evaluates sine function and derivative.
0825   //! @param[in] theX input value
0826   //! @param[out] theY function value
0827   //! @param[out] theDY derivative value
0828   //! @return true (always succeeds)
0829   bool Values(double theX, double& theY, double& theDY) const
0830   {
0831     const double anArg = myFrequency * theX + myPhase;
0832     theY               = myAmplitude * std::sin(anArg) + myOffset;
0833     theDY              = myAmplitude * myFrequency * std::cos(anArg);
0834     return true;
0835   }
0836 
0837 private:
0838   double myAmplitude;
0839   double myFrequency;
0840   double myPhase;
0841   double myOffset;
0842 };
0843 
0844 //! Cosine function functor: f(x) = a * cos(b*x + c) + d.
0845 class Cosine
0846 {
0847 public:
0848   //! Constructor with full parameters.
0849   //! @param theAmplitude amplitude a
0850   //! @param theFrequency angular frequency b
0851   //! @param thePhase phase shift c
0852   //! @param theOffset vertical offset d
0853   Cosine(double theAmplitude = 1.0,
0854          double theFrequency = 1.0,
0855          double thePhase     = 0.0,
0856          double theOffset    = 0.0)
0857       : myAmplitude(theAmplitude),
0858         myFrequency(theFrequency),
0859         myPhase(thePhase),
0860         myOffset(theOffset)
0861   {
0862   }
0863 
0864   //! Evaluates cosine function.
0865   //! @param[in] theX input value
0866   //! @param[out] theY function value
0867   //! @return true (always succeeds)
0868   bool Value(double theX, double& theY) const
0869   {
0870     theY = myAmplitude * std::cos(myFrequency * theX + myPhase) + myOffset;
0871     return true;
0872   }
0873 
0874   //! Evaluates cosine function and derivative.
0875   //! @param[in] theX input value
0876   //! @param[out] theY function value
0877   //! @param[out] theDY derivative value
0878   //! @return true (always succeeds)
0879   bool Values(double theX, double& theY, double& theDY) const
0880   {
0881     const double anArg = myFrequency * theX + myPhase;
0882     theY               = myAmplitude * std::cos(anArg) + myOffset;
0883     theDY              = -myAmplitude * myFrequency * std::sin(anArg);
0884     return true;
0885   }
0886 
0887 private:
0888   double myAmplitude;
0889   double myFrequency;
0890   double myPhase;
0891   double myOffset;
0892 };
0893 
0894 //! Exponential function functor: f(x) = a * exp(b*x) + c.
0895 class Exponential
0896 {
0897 public:
0898   //! Constructor with full parameters.
0899   //! @param theScale scale factor a
0900   //! @param theRate rate b
0901   //! @param theOffset vertical offset c
0902   Exponential(double theScale = 1.0, double theRate = 1.0, double theOffset = 0.0)
0903       : myScale(theScale),
0904         myRate(theRate),
0905         myOffset(theOffset)
0906   {
0907   }
0908 
0909   //! Evaluates exponential function.
0910   //! @param[in] theX input value
0911   //! @param[out] theY function value
0912   //! @return true (always succeeds)
0913   bool Value(double theX, double& theY) const
0914   {
0915     theY = myScale * std::exp(myRate * theX) + myOffset;
0916     return true;
0917   }
0918 
0919   //! Evaluates exponential function and derivative.
0920   //! @param[in] theX input value
0921   //! @param[out] theY function value
0922   //! @param[out] theDY derivative value
0923   //! @return true (always succeeds)
0924   bool Values(double theX, double& theY, double& theDY) const
0925   {
0926     const double anExp = std::exp(myRate * theX);
0927     theY               = myScale * anExp + myOffset;
0928     theDY              = myScale * myRate * anExp;
0929     return true;
0930   }
0931 
0932 private:
0933   double myScale;
0934   double myRate;
0935   double myOffset;
0936 };
0937 
0938 //! Power function functor: f(x) = a * x^n + b.
0939 class Power
0940 {
0941 public:
0942   //! Constructor with full parameters.
0943   //! @param theExponent power n
0944   //! @param theScale scale factor a
0945   //! @param theOffset vertical offset b
0946   Power(double theExponent, double theScale = 1.0, double theOffset = 0.0)
0947       : myExponent(theExponent),
0948         myScale(theScale),
0949         myOffset(theOffset)
0950   {
0951   }
0952 
0953   //! Evaluates power function.
0954   //! @param[in] theX input value
0955   //! @param[out] theY function value
0956   //! @return false if x < 0 and exponent is non-integer
0957   bool Value(double theX, double& theY) const
0958   {
0959     if (theX < 0.0 && myExponent != std::floor(myExponent))
0960     {
0961       return false;
0962     }
0963     theY = myScale * std::pow(theX, myExponent) + myOffset;
0964     return true;
0965   }
0966 
0967   //! Evaluates power function and derivative.
0968   //! @param[in] theX input value
0969   //! @param[out] theY function value
0970   //! @param[out] theDY derivative value
0971   //! @return false if x < 0 and exponent is non-integer
0972   bool Values(double theX, double& theY, double& theDY) const
0973   {
0974     if (theX < 0.0 && myExponent != std::floor(myExponent))
0975     {
0976       return false;
0977     }
0978     const double aPow = std::pow(theX, myExponent);
0979     theY              = myScale * aPow + myOffset;
0980     if (std::abs(theX) < 1e-15)
0981     {
0982       theDY = (myExponent == 1.0) ? myScale : 0.0;
0983     }
0984     else
0985     {
0986       theDY = myScale * myExponent * aPow / theX;
0987     }
0988     return true;
0989   }
0990 
0991 private:
0992   double myExponent;
0993   double myScale;
0994   double myOffset;
0995 };
0996 
0997 //! Gaussian function functor: f(x) = a * exp(-((x-mu)^2)/(2*sigma^2)).
0998 class Gaussian
0999 {
1000 public:
1001   //! Constructor with full parameters.
1002   //! @param theAmplitude amplitude a (peak height)
1003   //! @param theMean mean mu (center)
1004   //! @param theSigma standard deviation sigma (width)
1005   Gaussian(double theAmplitude = 1.0, double theMean = 0.0, double theSigma = 1.0)
1006       : myAmplitude(theAmplitude),
1007         myMean(theMean),
1008         mySigma(theSigma)
1009   {
1010   }
1011 
1012   //! Evaluates Gaussian function.
1013   //! @param[in] theX input value
1014   //! @param[out] theY function value
1015   //! @return false if sigma is zero
1016   bool Value(double theX, double& theY) const
1017   {
1018     if (std::abs(mySigma) < 1e-15)
1019     {
1020       return false;
1021     }
1022     const double aZ = (theX - myMean) / mySigma;
1023     theY            = myAmplitude * std::exp(-0.5 * aZ * aZ);
1024     return true;
1025   }
1026 
1027   //! Evaluates Gaussian function and derivative.
1028   //! @param[in] theX input value
1029   //! @param[out] theY function value
1030   //! @param[out] theDY derivative value
1031   //! @return false if sigma is zero
1032   bool Values(double theX, double& theY, double& theDY) const
1033   {
1034     if (std::abs(mySigma) < 1e-15)
1035     {
1036       return false;
1037     }
1038     const double aZ   = (theX - myMean) / mySigma;
1039     const double aExp = std::exp(-0.5 * aZ * aZ);
1040     theY              = myAmplitude * aExp;
1041     theDY             = -myAmplitude * aZ * aExp / mySigma;
1042     return true;
1043   }
1044 
1045 private:
1046   double myAmplitude;
1047   double myMean;
1048   double mySigma;
1049 };
1050 
1051 } // namespace MathUtils
1052 
1053 #endif // _MathUtils_FunctorScalar_HeaderFile