File indexing completed on 2026-09-28 09:20:54
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
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
0024
0025
0026
0027
0028
0029
0030 namespace MathUtils
0031 {
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046 template <typename Lambda>
0047 class ScalarLambda
0048 {
0049 public:
0050
0051
0052 explicit ScalarLambda(Lambda theLambda)
0053 : myLambda(std::move(theLambda))
0054 {
0055 }
0056
0057
0058
0059
0060
0061 bool Value(double theX, double& theY) const { return myLambda(theX, theY); }
0062
0063 private:
0064 Lambda myLambda;
0065 };
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081 template <typename Lambda>
0082 class ScalarLambdaWithDerivative
0083 {
0084 public:
0085
0086
0087 explicit ScalarLambdaWithDerivative(Lambda theLambda)
0088 : myLambda(std::move(theLambda))
0089 {
0090 }
0091
0092
0093
0094
0095
0096
0097 bool Values(double theX, double& theY, double& theDY) const
0098 {
0099 return myLambda(theX, theY, theDY);
0100 }
0101
0102
0103
0104
0105
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
0117
0118
0119
0120 template <typename Lambda>
0121 ScalarLambda<Lambda> MakeScalar(Lambda theLambda)
0122 {
0123 return ScalarLambda<Lambda>(std::move(theLambda));
0124 }
0125
0126
0127
0128
0129
0130 template <typename Lambda>
0131 ScalarLambdaWithDerivative<Lambda> MakeScalarWithDerivative(Lambda theLambda)
0132 {
0133 return ScalarLambdaWithDerivative<Lambda>(std::move(theLambda));
0134 }
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147 class Polynomial
0148 {
0149 public:
0150
0151
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
0163
0164 explicit Polynomial(const math_Vector& theCoeffs)
0165 : myCoeffs(theCoeffs)
0166 {
0167 }
0168
0169
0170
0171
0172
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
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
0192
0193
0194
0195
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
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
0227
0228 int Degree() const { return myCoeffs.Length() <= 0 ? 0 : myCoeffs.Length() - 1; }
0229
0230
0231
0232
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
0244
0245
0246
0247
0248
0249
0250
0251 class Rational
0252 {
0253 public:
0254
0255
0256
0257 Rational(const math_Vector& theNum, const math_Vector& theDenom)
0258 : myNum(theNum),
0259 myDenom(theDenom)
0260 {
0261 }
0262
0263
0264
0265
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
0283
0284
0285
0286 bool Value(double theX, double& theY) const
0287 {
0288 double aNum = 0.0;
0289 double aDenom = 0.0;
0290
0291
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
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
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
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340 template <typename Outer, typename Inner>
0341 class Composite
0342 {
0343 public:
0344
0345
0346
0347 Composite(Outer theOuter, Inner theInner)
0348 : myOuter(std::move(theOuter)),
0349 myInner(std::move(theInner))
0350 {
0351 }
0352
0353
0354
0355
0356
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
0373
0374
0375
0376
0377
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
0385
0386
0387
0388
0389
0390
0391
0392
0393
0394
0395 template <typename F, typename G>
0396 class Sum
0397 {
0398 public:
0399
0400
0401
0402 Sum(F theF, G theG)
0403 : myF(std::move(theF)),
0404 myG(std::move(theG))
0405 {
0406 }
0407
0408
0409
0410
0411
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
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
0441
0442
0443
0444 template <typename F, typename G>
0445 class Difference
0446 {
0447 public:
0448
0449
0450
0451 Difference(F theF, G theG)
0452 : myF(std::move(theF)),
0453 myG(std::move(theG))
0454 {
0455 }
0456
0457
0458
0459
0460
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
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
0490
0491
0492
0493 template <typename F, typename G>
0494 class Product
0495 {
0496 public:
0497
0498
0499
0500 Product(F theF, G theG)
0501 : myF(std::move(theF)),
0502 myG(std::move(theG))
0503 {
0504 }
0505
0506
0507
0508
0509
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
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
0539
0540
0541
0542 template <typename F, typename G>
0543 class Quotient
0544 {
0545 public:
0546
0547
0548
0549 Quotient(F theF, G theG)
0550 : myF(std::move(theF)),
0551 myG(std::move(theG))
0552 {
0553 }
0554
0555
0556
0557
0558
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
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
0592
0593
0594 template <typename F>
0595 class Scaled
0596 {
0597 public:
0598
0599
0600
0601 Scaled(F theF, double theScale)
0602 : myF(std::move(theF)),
0603 myScale(theScale)
0604 {
0605 }
0606
0607
0608
0609
0610
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
0628 template <typename F>
0629 Scaled<F> MakeScaled(F theF, double theScale)
0630 {
0631 return Scaled<F>(std::move(theF), theScale);
0632 }
0633
0634
0635
0636
0637 template <typename F>
0638 class Shifted
0639 {
0640 public:
0641
0642
0643
0644 Shifted(F theF, double theShift)
0645 : myF(std::move(theF)),
0646 myShift(theShift)
0647 {
0648 }
0649
0650
0651
0652
0653
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
0671 template <typename F>
0672 Shifted<F> MakeShifted(F theF, double theShift)
0673 {
0674 return Shifted<F>(std::move(theF), theShift);
0675 }
0676
0677
0678
0679
0680 template <typename F>
0681 class Negated
0682 {
0683 public:
0684
0685
0686 explicit Negated(F theF)
0687 : myF(std::move(theF))
0688 {
0689 }
0690
0691
0692
0693
0694
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
0711 template <typename F>
0712 Negated<F> MakeNegated(F theF)
0713 {
0714 return Negated<F>(std::move(theF));
0715 }
0716
0717
0718 class Constant
0719 {
0720 public:
0721
0722
0723 explicit Constant(double theValue)
0724 : myValue(theValue)
0725 {
0726 }
0727
0728
0729
0730
0731
0732 bool Value(double , double& theY) const
0733 {
0734 theY = myValue;
0735 return true;
0736 }
0737
0738
0739
0740
0741
0742
0743 bool Values(double , 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
0755 class Linear
0756 {
0757 public:
0758
0759
0760
0761 Linear(double theSlope, double theIntercept)
0762 : mySlope(theSlope),
0763 myIntercept(theIntercept)
0764 {
0765 }
0766
0767
0768
0769
0770
0771 bool Value(double theX, double& theY) const
0772 {
0773 theY = mySlope * theX + myIntercept;
0774 return true;
0775 }
0776
0777
0778
0779
0780
0781
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
0795 class Sine
0796 {
0797 public:
0798
0799
0800
0801
0802
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
0815
0816
0817
0818 bool Value(double theX, double& theY) const
0819 {
0820 theY = myAmplitude * std::sin(myFrequency * theX + myPhase) + myOffset;
0821 return true;
0822 }
0823
0824
0825
0826
0827
0828
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
0845 class Cosine
0846 {
0847 public:
0848
0849
0850
0851
0852
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
0865
0866
0867
0868 bool Value(double theX, double& theY) const
0869 {
0870 theY = myAmplitude * std::cos(myFrequency * theX + myPhase) + myOffset;
0871 return true;
0872 }
0873
0874
0875
0876
0877
0878
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
0895 class Exponential
0896 {
0897 public:
0898
0899
0900
0901
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
0910
0911
0912
0913 bool Value(double theX, double& theY) const
0914 {
0915 theY = myScale * std::exp(myRate * theX) + myOffset;
0916 return true;
0917 }
0918
0919
0920
0921
0922
0923
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
0939 class Power
0940 {
0941 public:
0942
0943
0944
0945
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
0954
0955
0956
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
0968
0969
0970
0971
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
0998 class Gaussian
0999 {
1000 public:
1001
1002
1003
1004
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
1013
1014
1015
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
1028
1029
1030
1031
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 }
1052
1053 #endif