00001 #include "Math/Polynomial.h"
00002 #include "Math/Derivator.h"
00003 #include "Math/IFunction.h"
00004 #include "Math/Functor.h"
00005 #include "Math/WrappedFunction.h"
00006 #include "Math/WrappedParamFunction.h"
00007 #include <iostream>
00008 #include <vector>
00009 #include <cassert>
00010 #include <cmath>
00011
00012 #ifdef HAVE_ROOTLIBS
00013
00014 #include "TStopwatch.h"
00015 #include "TF1.h"
00016 #include "Math/WrappedTF1.h"
00017 #include "Math/WrappedMultiTF1.h"
00018 #include "Math/DistFunc.h"
00019
00020 #endif
00021
00022 const double ERRORLIMIT = 1E-5;
00023
00024 typedef double ( * FP ) ( double, void * );
00025 typedef double ( * FP2 ) ( double );
00026
00027
00028 double myfunc ( double x, void * ) {
00029
00030 return std::pow( x, 1.5);
00031 }
00032
00033 double myfunc2 ( double x) {
00034 return std::pow( x, 1.5);
00035 }
00036
00037 int testDerivation() {
00038
00039 int status = 0;
00040
00041
00042
00043
00044 ROOT::Math::Polynomial *f1 = new ROOT::Math::Polynomial(2);
00045
00046 std::vector<double> p(3);
00047 p[0] = 2;
00048 p[1] = 3;
00049 p[2] = 4;
00050 f1->SetParameters(&p[0]);
00051
00052 ROOT::Math::Derivator *der = new ROOT::Math::Derivator(*f1);
00053
00054 double step = 1E-8;
00055 double x0 = 2;
00056
00057 der->SetFunction(*f1);
00058 double result = der->Eval(x0);
00059 std::cout << "Derivative of function inheriting from IGenFunction f(x) = 2 + 3x + 4x^2 at x = 2" << std::endl;
00060 std::cout << "Return code: " << der->Status() << std::endl;
00061 std::cout << "Result: " << result << " +/- " << der->Error() << std::endl;
00062 std::cout << "Exact result: " << f1->Derivative(x0) << std::endl;
00063 std::cout << "EvalForward: " << der->EvalForward(*f1, x0) << std::endl;
00064 std::cout << "EvalBackward: " << der->EvalBackward(x0, step) << std::endl << std::endl;;
00065 status += fabs(result-f1->Derivative(x0)) > ERRORLIMIT;
00066
00067
00068
00069
00070 FP f2 = &myfunc;
00071 der->SetFunction(f2);
00072
00073 std::cout << "Derivative of a free function f(x) = x^(3/2) at x = 2" << std::endl;
00074 std::cout << "EvalCentral: " << der->EvalCentral(x0) << std::endl;
00075 std::cout << "EvalForward: " << der->EvalForward(x0) << std::endl;
00076 std::cout << "EvalBackward: " << der->EvalBackward(x0) << std::endl;
00077
00078 std::cout << "Exact result: " << 1.5*sqrt(x0) << std::endl << std::endl;
00079
00080 status += fabs(der->EvalCentral(x0)-1.5*sqrt(x0)) > ERRORLIMIT;
00081 status += fabs(der->EvalForward(x0)-1.5*sqrt(x0)) > ERRORLIMIT;
00082 status += fabs(der->EvalBackward(x0)-1.5*sqrt(x0)) > ERRORLIMIT;
00083
00084
00085
00086
00087
00088 ROOT::Math::Functor1D *f3 = new ROOT::Math::Functor1D (&myfunc2);
00089
00090 std::cout << "Derivative of a free function wrapped in a Functor f(x) = x^(3/2) at x = 2" << std::endl;
00091 std::cout << "EvalCentral: " << der->Eval( *f3, x0) << std::endl;
00092 der->SetFunction(*f3);
00093 std::cout << "EvalForward: " << der->EvalForward(x0) << std::endl;
00094 std::cout << "EvalBackward: " << der->EvalBackward(x0) << std::endl;
00095 std::cout << "Exact result: " << 1.5*sqrt(x0) << std::endl << std::endl;
00096
00097 status += fabs(der->Eval( *f3, x0)-1.5*sqrt(x0)) > ERRORLIMIT;
00098 status += fabs(der->EvalForward(x0)-1.5*sqrt(x0)) > ERRORLIMIT;
00099 status += fabs(der->EvalBackward(x0)-1.5*sqrt(x0)) > ERRORLIMIT;
00100
00101
00102
00103
00104 ROOT::Math::Derivator der2;
00105 std::cout << "Tes a derivator without a function" << std::endl;
00106 std::cout << der2.Eval(1.0) << std::endl;
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122 return status;
00123 }
00124
00125
00126 #ifdef HAVE_ROOTLIBS
00127
00128 void testDerivPerf() {
00129
00130
00131 std::cout << "\n\n***************************************************************\n";
00132 std::cout << "Test derivation performances....\n\n";
00133
00134 ROOT::Math::Polynomial f1(2);
00135 double p[3] = {2,3,4};
00136 f1.SetParameters(p);
00137
00138 TStopwatch timer;
00139 int n = 1000000;
00140 double x1 = 0; double x2 = 10;
00141 double dx = (x2-x1)/double(n);
00142
00143 timer.Start();
00144 double s1 = 0;
00145 ROOT::Math::Derivator der(f1);
00146 for (int i = 0; i < n; ++i) {
00147 double x = x1 + dx*i;
00148 s1+= der.EvalCentral(x);
00149 }
00150 timer.Stop();
00151 std::cout << "Time using ROOT::Math::Derivator :\t" << timer.RealTime() << std::endl;
00152 int pr = std::cout.precision(18); std::cout << s1 << std::endl; std::cout.precision(pr);
00153
00154 timer.Start();
00155 s1 = 0;
00156 for (int i = 0; i < n; ++i) {
00157 ROOT::Math::Derivator der2(f1);
00158 double x = x1 + dx*i;
00159 s1+= der2.EvalForward(x);
00160 }
00161 timer.Stop();
00162 std::cout << "Time using ROOT::Math::Derivator(2):\t" << timer.RealTime() << std::endl;
00163 pr = std::cout.precision(18); std::cout << s1 << std::endl; std::cout.precision(pr);
00164
00165 timer.Start();
00166 s1 = 0;
00167 for (int i = 0; i < n; ++i) {
00168 double x = x1 + dx*i;
00169 s1+= ROOT::Math::Derivator::Eval(f1,x);
00170 }
00171 timer.Stop();
00172 std::cout << "Time using ROOT::Math::Derivator(3):\t" << timer.RealTime() << std::endl;
00173 pr = std::cout.precision(18); std::cout << s1 << std::endl; std::cout.precision(pr);
00174
00175
00176 TF1 f2("pol","pol2",0,10);
00177 f2.SetParameters(p);
00178
00179 timer.Start();
00180 double s2 = 0;
00181 for (int i = 0; i < n; ++i) {
00182 double x = x1 + dx*i;
00183 s2+= f2.Derivative(x);
00184 }
00185 timer.Stop();
00186 std::cout << "Time using TF1::Derivative :\t\t" << timer.RealTime() << std::endl;
00187 pr = std::cout.precision(18);
00188 std::cout << s2 << std::endl;
00189 std::cout.precision(pr);
00190
00191
00192
00193 }
00194
00195 double userFunc(const double *x, const double * = 0) {
00196 return std::exp(-x[0]);
00197 }
00198 double userFunc1(double x) { return userFunc(&x); }
00199
00200 double userFunc2(const double * x) { return userFunc(x); }
00201
00202 void testDerivPerfUser() {
00203
00204
00205 std::cout << "\n\n***************************************************************\n";
00206 std::cout << "Test derivation performances - using a User function\n\n";
00207
00208 ROOT::Math::WrappedFunction<> f1(userFunc1);
00209
00210 TStopwatch timer;
00211 int n = 1000000;
00212 double x1 = 0; double x2 = 10;
00213 double dx = (x2-x1)/double(n);
00214
00215 timer.Start();
00216 double s1 = 0;
00217 ROOT::Math::Derivator der(f1);
00218 for (int i = 0; i < n; ++i) {
00219 double x = x1 + dx*i;
00220 s1+= der.EvalCentral(x);
00221 }
00222 timer.Stop();
00223 std::cout << "Time using ROOT::Math::Derivator :\t" << timer.RealTime() << std::endl;
00224 int pr = std::cout.precision(18); std::cout << s1 << std::endl; std::cout.precision(pr);
00225
00226 timer.Start();
00227 s1 = 0;
00228 for (int i = 0; i < n; ++i) {
00229 ROOT::Math::Derivator der2(f1);
00230 double x = x1 + dx*i;
00231 s1+= der2.EvalForward(x);
00232 }
00233 timer.Stop();
00234 std::cout << "Time using ROOT::Math::Derivator(2):\t" << timer.RealTime() << std::endl;
00235 pr = std::cout.precision(18); std::cout << s1 << std::endl; std::cout.precision(pr);
00236
00237 timer.Start();
00238 s1 = 0;
00239 for (int i = 0; i < n; ++i) {
00240 double x = x1 + dx*i;
00241 s1+= ROOT::Math::Derivator::Eval(f1,x);
00242 }
00243 timer.Stop();
00244 std::cout << "Time using ROOT::Math::Derivator(3):\t" << timer.RealTime() << std::endl;
00245 pr = std::cout.precision(18); std::cout << s1 << std::endl; std::cout.precision(pr);
00246
00247
00248 TF1 f2("uf",userFunc,0,10,0);
00249
00250 timer.Start();
00251 double s2 = 0;
00252 for (int i = 0; i < n; ++i) {
00253 double x = x1 + dx*i;
00254 s2+= f2.Derivative(x);
00255 }
00256 timer.Stop();
00257 std::cout << "Time using TF1::Derivative :\t\t" << timer.RealTime() << std::endl;
00258 pr = std::cout.precision(18);
00259 std::cout << s2 << std::endl;
00260 std::cout.precision(pr);
00261
00262
00263 ROOT::Math::WrappedMultiFunction<> f3(userFunc2,1);
00264 timer.Start();
00265 s1 = 0;
00266 double xx[1];
00267 for (int i = 0; i < n; ++i) {
00268 xx[0] = x1 + dx*i;
00269 s1+= ROOT::Math::Derivator::Eval(f3,xx,0);
00270 }
00271 timer.Stop();
00272 std::cout << "Time using ROOT::Math::Derivator Multi:\t" << timer.RealTime() << std::endl;
00273 pr = std::cout.precision(18); std::cout << s1 << std::endl; std::cout.precision(pr);
00274
00275
00276
00277 }
00278
00279
00280 double gausFunc( const double * x, const double * p) {
00281 return p[0] * ROOT::Math::normal_pdf(x[0], p[2], p[1] );
00282 }
00283
00284
00285 void testDerivPerfParam() {
00286
00287
00288 std::cout << "\n\n***************************************************************\n";
00289 std::cout << "Test derivation performances - using a Gaussian Param function\n\n";
00290
00291
00292 TF1 gaus("gaus",gausFunc,-10,10,3);
00293 double params[3] = {10,1.,1.};
00294 gaus.SetParameters(params);
00295
00296 ROOT::Math::WrappedTF1 f1(gaus);
00297
00298 TStopwatch timer;
00299 int n = 300000;
00300 double x1 = 0; double x2 = 10;
00301 double dx = (x2-x1)/double(n);
00302
00303 timer.Start();
00304 double s1 = 0;
00305 for (int i = 0; i < n; ++i) {
00306 double x = x1 + dx*i;
00307
00308 s1 += ROOT::Math::Derivator::Eval(f1,x,params,0);
00309 s1 += ROOT::Math::Derivator::Eval(f1,x,params,1);
00310 s1 += ROOT::Math::Derivator::Eval(f1,x,params,2);
00311 }
00312 timer.Stop();
00313 std::cout << "Time using ROOT::Math::Derivator (1D) :\t" << timer.RealTime() << std::endl;
00314 int pr = std::cout.precision(18); std::cout << s1 << std::endl; std::cout.precision(pr);
00315
00316 ROOT::Math::WrappedParamFunction<> f2(&gausFunc,1,params,params+3);
00317 double xx[1];
00318
00319 timer.Start();
00320 s1 = 0;
00321 for (int i = 0; i < n; ++i) {
00322 xx[0] = x1 + dx*i;
00323 s1 += ROOT::Math::Derivator::Eval(f2,xx,params,0);
00324 s1 += ROOT::Math::Derivator::Eval(f2,xx,params,1);
00325 s1 += ROOT::Math::Derivator::Eval(f2,xx,params,2);
00326 }
00327 timer.Stop();
00328 std::cout << "Time using ROOT::Math::Derivator(ND):\t" << timer.RealTime() << std::endl;
00329 pr = std::cout.precision(18); std::cout << s1 << std::endl; std::cout.precision(pr);
00330
00331
00332 assert( std::fabs(params[0] - gaus.GetParameter(0)) < 1.E-15);
00333 assert( std::fabs(params[1] - gaus.GetParameter(1)) < 1.E-15);
00334 assert( std::fabs(params[2] - gaus.GetParameter(2)) < 1.E-15);
00335
00336 timer.Start();
00337 s1 = 0;
00338 double g[3];
00339 for (int i = 0; i < n; ++i) {
00340 xx[0] = x1 + dx*i;
00341 gaus.GradientPar(xx,g,1E-8);
00342 s1 += g[0];
00343 s1 += g[1];
00344 s1 += g[2];
00345 }
00346 timer.Stop();
00347 std::cout << "Time using TF1::ParamGradient:\t\t" << timer.RealTime() << std::endl;
00348 pr = std::cout.precision(18); std::cout << s1 << std::endl; std::cout.precision(pr);
00349
00350 }
00351
00352 #endif
00353
00354 int main() {
00355
00356 int status = 0;
00357
00358 status += testDerivation();
00359
00360 #ifdef HAVE_ROOTLIBS
00361 testDerivPerf();
00362 testDerivPerfUser();
00363 testDerivPerfParam();
00364 #endif
00365
00366 return status;
00367
00368 }