![]() |
Object-oriented Scientific Computing Library: Version 0.908
|
This example shows how to provide functions to O2scl classes by solving the equation
Where and
. The parameter
is stored as member data for the class, and the parameter
is an argument to the member function.
The image below shows how the solver progresses to the solution of the example function.
/* Example: ex_fptr.cpp ------------------------------------------------------------------- This gives an example of the how member functions and external parameters are supplied to numerical routines. In this case, a member function with two parameters is passed to the gsl_root_brent class, which solves the equation. One of the parameters is member data, and the other is specified using the extra parameter argument to the function. */ #include <o2scl/funct.h> #include <o2scl/gsl_root_brent.h> #include <o2scl/test_mgr.h> using namespace std; using namespace o2scl; class my_class { private: double parameter; public: void set_parameter() { parameter=0.01; } // A function demonstrating the different ways of implementing // function parameters double function_to_solve(double x, double &p) { return atan((x-parameter)*4)*(1.0+sin((x-parameter)*50.0)/p); } }; // Simple code to write the function to a file int write_file(double sol); int main(void) { cout.setf(ios::scientific); test_mgr t; // Only print something out if one of the tests fails t.set_output_level(1); // The solver, specifying the type of the parameter (double) // and the function type (funct<double>) gsl_root_brent<> solver; my_class c; c.set_parameter(); double p=1.1; // This is the code that allows specification of class member // functions as functions to solve. This approach avoids the use of // static variables and functions and multiple inheritance at the // expense of a little overhead. We need to provide the address of // an instantiated object and the address of the member function. funct_mfptr_param<my_class,double> function(&c,&my_class::function_to_solve,p); double x1=-1; double x2=2; // The value verbose=1 prints out iteration information // and verbose=2 requires a keypress between iterations. // The parameter p=0.1 is used. solver.verbose=1; solver.solve_bkt(x1,x2,function); // This is actually a somewhat difficult function to solve because // of the sinusoidal behavior. cout << "Solution: " << x1 << " Function value: " << c.function_to_solve(x1,p) << endl; // Write the function being solved to a file (see source code // in examples directory for details) write_file(x1); t.report(); return 0; } // End of example
This demonstrates several ways of using the multi-dimensional solvers to solve the equations
/* Example: ex_mroot.cpp ------------------------------------------------------------------- Several ways to use an O2scl solver to solve a simple function */ #include <cmath> #include <o2scl/test_mgr.h> #include <o2scl/mm_funct.h> #include <o2scl/gsl_mroot_hybrids.h> #include <o2scl/cern_mroot.h> using namespace std; using namespace o2scl; int gfn(size_t nv, const ovector_base &x, ovector_base &y) { y[0]=sin(x[1]-0.2); y[1]=sin(x[0]-0.25); return 0; } typedef double arr_t[2]; typedef double mat_t[2][2]; class cl { public: // Store the number of function and derivative evaluations int nf, nd; int mfn(size_t nv, const ovector_base &x, ovector_base &y) { y[0]=sin(x[1]-0.2); y[1]=sin(x[0]-0.25); nf++; return 0; } int operator()(size_t nv, const ovector_base &x, ovector_base &y) { y[0]=sin(x[1]-0.2); y[1]=sin(x[0]-0.25); nf++; return 0; } int mfnd(size_t nv, ovector_base &x, ovector_base &y, omatrix_base &j) { j[0][0]=0.0; j[0][1]=cos(x[1]-0.2); j[1][0]=cos(x[0]-0.25); j[1][1]=0.0; nd++; return 0; } int mfna(size_t nv, const arr_t &x, arr_t &y) { y[0]=sin(x[1]-0.2); y[1]=sin(x[0]-0.25); return 0; } int mfnad(size_t nv, arr_t &x, arr_t &y, mat_t &j) { j[0][0]=0.0; j[0][1]=cos(x[1]-0.2); j[1][0]=cos(x[0]-0.25); j[1][1]=0.0; return 0; } }; int main(void) { cl acl; ovector x(2); double xa[2]; int i; size_t tmp; int r1, r2, r3; bool done; test_mgr t; t.set_output_level(1); /* Using a member function with \ref ovector objects */ mm_funct_mfptr<cl> f1(&acl,&cl::mfn); gsl_mroot_hybrids<> cr1; x[0]=0.5; x[1]=0.5; acl.nf=0; int ret1=cr1.msolve(2,x,f1); cout << "GSL solver (numerical Jacobian): " << endl; cout << "Return value: " << ret1 << endl; cout << "Number of iterations: " << cr1.last_ntrial << endl; cout << "Number of function evaluations: " << acl.nf << endl; cout << endl; t.test_rel(x[0],0.25,1.0e-6,"1a"); t.test_rel(x[1],0.2,1.0e-6,"1b"); /* Using the CERNLIB solver */ cern_mroot<> cr2; x[0]=0.5; x[1]=0.5; acl.nf=0; int ret2=cr2.msolve(2,x,f1); cout << "CERNLIB solver (numerical Jacobian): " << endl; cout << "Return value: " << ret2 << endl; cout << "INFO parameter: " << cr2.get_info() << endl; cout << "Number of function evaluations: " << acl.nf << endl; cout << endl; t.test_rel(x[0],0.25,1.0e-6,"2a"); t.test_rel(x[1],0.2,1.0e-6,"2b"); /* Using a member function with \ref ovector objects, but using the GSL-like interface with set() and iterate(). */ gsl_mroot_hybrids<> cr3; x[0]=0.5; x[1]=0.5; cr3.allocate(2); cr3.set(2,x,f1); done=false; do { r3=cr3.iterate(); double resid=fabs(cr3.f[0])+fabs(cr3.f[1]); if (resid<cr3.tolf || r3>0) done=true; } while (done==false); t.test_rel(cr3.x[0],0.25,1.0e-6,"3a"); t.test_rel(cr3.x[1],0.2,1.0e-6,"3b"); cr3.free(); /* Now instead of using the automatic Jacobian, using a user-specified Jacobian. */ jac_funct_mfptr<cl,ovector_base,omatrix_base> j4(&acl,&cl::mfnd); x[0]=0.5; x[1]=0.5; acl.nf=0; acl.nd=0; int ret4=cr1.msolve_de(2,x,f1,j4); cout << "GSL solver (analytic Jacobian): " << endl; cout << "Return value: " << ret4 << endl; cout << "Number of iterations: " << cr1.last_ntrial << endl; cout << "Number of function evaluations: " << acl.nf << endl; cout << "Number of Jacobian evaluations: " << acl.nd << endl; cout << endl; t.test_rel(x[0],0.25,1.0e-6,"4a"); t.test_rel(x[1],0.2,1.0e-6,"4b"); /* Using a user-specified Jacobian and the GSL-like interface */ gsl_mroot_hybrids<> cr5; x[0]=0.5; x[1]=0.5; cr5.allocate(2); cr5.set_de(2,x,f1,j4); done=false; do { r3=cr5.iterate(); double resid=fabs(cr5.f[0])+fabs(cr5.f[1]); if (resid<cr5.tolf || r3>0) done=true; } while (done==false); t.test_rel(cr5.x[0],0.25,1.0e-6,"5a"); t.test_rel(cr5.x[1],0.2,1.0e-6,"5b"); cr5.free(); /* Using C-style arrays instead of ovector objects */ mm_funct_mfptr<cl,arr_t> f6(&acl,&cl::mfna); gsl_mroot_hybrids<mm_funct_mfptr<cl,arr_t>,arr_t, arr_t,array_alloc<arr_t> > cr6; xa[0]=0.5; xa[1]=0.5; cr6.msolve(2,xa,f6); t.test_rel(xa[0],0.25,1.0e-6,"6a"); t.test_rel(xa[1],0.2,1.0e-6,"6b"); /* Using the CERNLIB solver with C-style arrays instead of ovector objects */ cern_mroot<mm_funct_mfptr<cl,arr_t>,arr_t, arr_t,array_alloc<arr_t> > cr7; xa[0]=0.5; xa[1]=0.5; cr7.msolve(2,xa,f6); t.test_rel(xa[0],0.25,1.0e-6,"7a"); t.test_rel(xa[1],0.2,1.0e-6,"7b"); /* Using C-style arrays with a user-specified Jacobian */ jac_funct_mfptr<cl,arr_t,mat_t> j8(&acl,&cl::mfnad); gsl_mroot_hybrids<mm_funct_mfptr<cl,arr_t>,arr_t, arr_t,array_alloc<arr_t>,mat_t,mat_t, array_2d_alloc<mat_t>,jac_funct<arr_t,mat_t> > cr8; xa[0]=0.5; xa[1]=0.5; cr8.msolve_de(2,xa,f6,j8); t.test_rel(xa[0],0.25,1.0e-6,"8a"); t.test_rel(xa[1],0.2,1.0e-6,"8b"); /* Using a class with an operator(). Note that there can be only one operator() function in each class. */ gsl_mroot_hybrids<cl> cr9; x[0]=0.5; x[1]=0.5; cr9.msolve(2,x,acl); t.test_rel(x[0],0.25,1.0e-6,"9a"); t.test_rel(x[1],0.2,1.0e-6,"9b"); /* Using a function pointer to a global function. */ typedef int (*gfnt)(size_t, const ovector_base &, ovector_base &); gsl_mroot_hybrids<gfnt> cr10; gfnt f10=&gfn; x[0]=0.5; x[1]=0.5; cr10.msolve(2,x,f10); t.test_rel(x[0],0.25,1.0e-6,"10a"); t.test_rel(x[1],0.2,1.0e-6,"10b"); t.report(); return 0; } // End of example
This example uses the O2scl minimizers based on GSL to minimize a rather complicated three-dimensional function which has constant level surfaces which look like springs oriented along the z-axis.
/* Example: ex_mmin.cpp ------------------------------------------------------------------- Example usage of the multidimensional minimizers with and without gradients. */ #include <fstream> #include <string> #include <cmath> #include <o2scl/test_mgr.h> #include <o2scl/multi_funct.h> #include <o2scl/constants.h> #include <o2scl/gsl_mmin_simp2.h> #include <o2scl/gsl_mmin_conf.h> #include <o2scl/gsl_mmin_conp.h> #include <o2scl/gsl_mmin_bfgs2.h> using namespace std; using namespace o2scl; class cl { public: cl() { param=30.0; } // To output function evaluations to a file ofstream fout; // Parameter of the quadratic double param; // Updated spring function double spring_two(size_t nv, const ovector_base &x) { double theta=atan2(x[1],x[0]); double r=sqrt(x[0]*x[0]+x[1]*x[1]); double z=x[2]; double tmz=theta-z; double fact=8.0-pow(sin(tmz+o2scl_const::pi/2.0)+1.0,3.0); double rm1=r-1.0; double ret=fact+exp(rm1*rm1)+z*z/param; fout << x << " " << ret << endl; return ret; } // Gradient of the spring function int sgrad(size_t nv, ovector_base &x, ovector_base &g) { double theta=atan2(x[1],x[0]); double r=sqrt(x[0]*x[0]+x[1]*x[1]); double z=x[2]; double tmz=theta-z; double rm1=r-1.0; double fact=8.0-pow(sin(tmz+o2scl_const::pi/2.0)+1.0,3.0); double dtdx=-x[1]/r/r; double dtdy=x[0]/r/r; double drdx=x[0]/r; double drdy=x[1]/r; double dfdt=-3.0*pow(sin(tmz+o2scl_const::pi/2.0)+1.0,2.0)* cos(tmz+o2scl_const::pi/2.0); double dfdz=2.0*z/param+3.0*pow(sin(tmz+o2scl_const::pi/2.0)+1.0,2.0)* cos(tmz+o2scl_const::pi/2.0); double dfdr=2.0*rm1*exp(rm1*rm1); g[0]=dfdr*drdx+dfdt*dtdx; g[1]=dfdr*drdy+dfdt*dtdy; g[2]=dfdz; return 0; } }; int main(void) { cl acl; ovector x(3); double fmin; test_mgr t; t.set_output_level(1); cout.setf(ios::scientific); // Using a member function with \ref ovector objects multi_funct_mfptr<cl> f1(&acl,&cl::spring_two); grad_funct_mfptr<cl> f1g(&acl,&cl::sgrad); gsl_mmin_simp2<> gm1; gsl_mmin_conf<> gm2; gsl_mmin_conp<> gm3; gsl_mmin_bfgs2<> gm4; // This function is difficult to minimize, so more trials // are required. gm1.ntrial*=10; gm2.ntrial*=10; gm3.ntrial*=10; gm4.ntrial*=10; // Simplex minimization acl.fout.open("ex_mmin1.dat"); x[0]=1.0; x[1]=0.0; x[2]=7.0*o2scl_const::pi; gm1.mmin(3,x,fmin,f1); acl.fout.close(); cout << gm1.last_ntrial << endl; cout << "Found minimum at: " << x << endl; t.test_rel(x[0],1.0,1.0e-4,"1a"); t.test_rel(x[1],0.0,1.0e-4,"1b"); t.test_rel(x[2],0.0,1.0e-4,"1c"); // Fletcher-Reeves conjugate acl.fout.open("ex_mmin2.dat"); x[0]=1.0; x[1]=0.0; x[2]=7.0*o2scl_const::pi; gm2.mmin(3,x,fmin,f1); acl.fout.close(); cout << gm2.last_ntrial << endl; cout << "Found minimum at: " << x << endl; t.test_rel(x[0],1.0,4.0e-3,"2a"); t.test_rel(x[1],0.0,4.0e-3,"2b"); t.test_rel(x[2],0.0,4.0e-3,"2c"); // Fletcher-Reeves conjugate with gradients acl.fout.open("ex_mmin2g.dat"); x[0]=1.0; x[1]=0.0; x[2]=7.0*o2scl_const::pi; gm2.mmin_de(3,x,fmin,f1,f1g); acl.fout.close(); cout << gm2.last_ntrial << endl; cout << "Found minimum at: " << x << endl; t.test_rel(x[0],1.0,4.0e-3,"2a"); t.test_rel(x[1],0.0,4.0e-3,"2b"); t.test_rel(x[2],0.0,4.0e-3,"2c"); // Polak-Ribere conjugate acl.fout.open("ex_mmin3.dat"); x[0]=1.0; x[1]=0.0; x[2]=7.0*o2scl_const::pi; gm3.mmin(3,x,fmin,f1); acl.fout.close(); cout << gm3.last_ntrial << endl; cout << "Found minimum at: " << x << endl; t.test_rel(x[0],1.0,4.0e-3,"3a"); t.test_rel(x[1],0.0,4.0e-3,"3b"); t.test_rel(x[2],0.0,4.0e-3,"3c"); // Polak-Ribere conjugate with gradients acl.fout.open("ex_mmin3g.dat"); x[0]=1.0; x[1]=0.0; x[2]=7.0*o2scl_const::pi; gm3.mmin_de(3,x,fmin,f1,f1g); acl.fout.close(); cout << gm3.last_ntrial << endl; cout << "Found minimum at: " << x << endl; t.test_rel(x[0],1.0,4.0e-3,"3a"); t.test_rel(x[1],0.0,4.0e-3,"3b"); t.test_rel(x[2],0.0,4.0e-3,"3c"); // BFGS method // BFGS has trouble converging (especially to zero, since the // minimimum of x[0] is exactly at zero) if the derivative is not // very accurate. gm4.def_grad.epsrel=1.0e-8; acl.fout.open("ex_mmin4.dat"); x[0]=1.0; x[1]=0.0; x[2]=7.0*o2scl_const::pi; gm4.mmin(3,x,fmin,f1); acl.fout.close(); cout << gm4.last_ntrial << endl; cout << "Found minimum at: " << x << endl; t.test_rel(x[0],1.0,1.0e-4,"4a"); t.test_rel(x[1],0.0,1.0e-4,"4b"); t.test_rel(x[2],0.0,1.0e-4,"4c"); t.report(); return 0; } // End of example
This example uses the multi_min_fix class to minimize the function
while fixing some of the parameters.
/* Example: ex_mmin_fix.cpp ------------------------------------------------------------------- Example usage of the mmin_fix class, which fixes some of the paramters for a multidimensional minimization. */ #include <cmath> #include <o2scl/test_mgr.h> #include <o2scl/multi_funct.h> #include <o2scl/gsl_mmin_simp2.h> #include <o2scl/multi_min_fix.h> using namespace std; using namespace o2scl; class cl { public: double mfn(size_t nv, const ovector_base &x) { return (x[0]-2.0)*(x[0]-2.0)+(x[1]-1.0)*(x[1]-1.0)+x[2]*x[2]; } }; int main(void) { cl acl; ovector x(3); double fmin; test_mgr t; t.set_output_level(1); cout.setf(ios::scientific); /* Perform the minimization the standard way, with the simplex2 minimizer */ multi_funct_mfptr<cl> f1(&acl,&cl::mfn); gsl_mmin_simp2<> gm1; x[0]=0.5; x[1]=0.5; x[2]=0.5; gm1.mmin(3,x,fmin,f1); cout << gm1.last_ntrial << " iterations." << endl; cout << "Found minimum at: " << x << endl; t.test_rel(x[0],2.0,1.0e-4,"1a"); t.test_rel(x[1],1.0,1.0e-4,"1b"); t.test_rel(x[2],0.0,1.0e-4,"1c"); // Create a new multi_min_fix object multi_min_fix<bool[3]> gmf; // Create a base minimizer which can be used by the multi_min_fix // object. Note that we can't use 'gm1' here, because it has a // different type than 'gm2', even though its functionality is // effectively the same. gsl_mmin_simp2<multi_funct_mfptr<multi_min_fix<bool[3]> > > gm2; // Set the base minimizer gmf.set_mmin(gm2); /* First perform the minimization as above. */ x[0]=0.5; x[1]=0.5; x[2]=0.5; gmf.mmin(3,x,fmin,f1); cout << gmf.last_ntrial << " iterations." << endl; cout << "Found minimum at: " << x << endl; t.test_rel(x[0],2.0,1.0e-4,"2a"); t.test_rel(x[1],1.0,1.0e-4,"2b"); t.test_rel(x[2],0.0,1.0e-4,"2c"); /* Now fix the 2nd variable, and re-minimize. */ bool fix[3]={false,true,false}; x[0]=0.5; x[1]=0.5; x[2]=0.5; gmf.mmin_fix(3,x,fmin,fix,f1); cout << gmf.last_ntrial << " iterations." << endl; cout << "Found minimum at: " << x << endl; t.test_rel(x[0],2.0,1.0e-4,"3a"); t.test_rel(x[1],0.5,1.0e-4,"3b"); t.test_rel(x[2],0.0,1.0e-4,"3c"); t.report(); return 0; } // End of example
This example computes first and second derivatives of
/* Example: ex_deriv.cpp ------------------------------------------------------------------- An example to demonstrate numerical differentiation */ #include <cmath> #include <o2scl/test_mgr.h> #include <o2scl/funct.h> #include <o2scl/ovector_tlate.h> #include <o2scl/gsl_deriv.h> #include <o2scl/cern_deriv.h> using namespace std; using namespace o2scl; class cl { public: // This is the function we'll take the derivative of double function(double x) { return sin(2.0*x)+0.5; } }; int main(void) { cl acl; ovector x(2); double xa[2]; int i; size_t tmp; int r1, r2, r3; bool done; test_mgr t; t.set_output_level(2); funct_mfptr<cl> f1(&acl,&cl::function); gsl_deriv<> gd; // Note that the GSL derivative routine requires an initial stepsize gd.h=1.0e-3; cern_deriv<> cd; // Compute the first derivative using the gsl_deriv class and // verify that the answer is correct double d1=gd.calc(1.0,f1); t.test_rel(d1,2.0*cos(2.0),1.0e-10,"gsl_deriv"); // Compute the first derivative using the cern_deriv class and // verify that the answer is correct double d2=cd.calc(1.0,f1); t.test_rel(d2,2.0*cos(2.0),1.0e-10,"cern_deriv"); // Compute the second derivative also double d3=gd.calc2(1.0,f1); t.test_rel(d3,-4.0*sin(2.0),5.0e-7,"gsl_deriv"); double d4=cd.calc2(1.0,f1); t.test_rel(d4,-4.0*sin(2.0),1.0e-8,"cern_deriv"); t.report(); return 0; } // End of example
This example computes the integrals
and compares the computed results with the exact results.
/* Example: ex_inte.cpp ------------------------------------------------------------------- An example to demonstrate numerical integration. */ #include <cmath> #include <o2scl/test_mgr.h> #include <o2scl/constants.h> #include <o2scl/funct.h> #include <o2scl/gsl_inte_qag.h> #include <o2scl/gsl_inte_qagi.h> #include <o2scl/gsl_inte_qagiu.h> #include <o2scl/gsl_inte_qagil.h> #include <o2scl/cern_adapt.h> using namespace std; using namespace o2scl; using namespace o2scl_const; class cl { public: // We'll use this to count the number of function // evaulations required by the integration routines int nf; // A function to be integrated double integrand(double x) { nf++; return exp(-x*x); } // Another function to be integrated double integrand2(double x) { nf++; return sin(2.0*x)+0.5; } }; int main(void) { cl acl; test_mgr t; t.set_output_level(1); funct_mfptr<cl> f1(&acl,&cl::integrand); funct_mfptr<cl> f2(&acl,&cl::integrand2); // We don't need to specify the function type in the integration // objects, because we're using the default function type (type // funct). gsl_inte_qag<> g; gsl_inte_qagi<> gi; gsl_inte_qagiu<> gu; gsl_inte_qagil<> gl; cern_adapt<> ca; // The result and the uncertainty double res, err; // An integral from -infinity to +infinity (the limits are ignored) acl.nf=0; int ret1=gi.integ_err(f1,0.0,0.0,res,err); cout << "gsl_inte_qagi: " << endl; cout << "Return value: " << ret1 << endl; cout << "Result: " << res << " Uncertainty: " << err << endl; cout << "Number of iterations: " << gi.last_iter << endl; cout << "Number of function evaluations: " << acl.nf << endl; cout << endl; t.test_rel(res,sqrt(pi),1.0e-8,"inte 1"); // An integral from 0 to +infinity (the second limit argument is // ignored in the line below) acl.nf=0; gu.integ_err(f1,0.0,0.0,res,err); cout << "gsl_inte_qagiu: " << endl; cout << "Return value: " << ret1 << endl; cout << "Result: " << res << " Uncertainty: " << err << endl; cout << "Number of iterations: " << gu.last_iter << endl; cout << "Number of function evaluations: " << acl.nf << endl; cout << endl; t.test_rel(res,sqrt(pi)/2.0,1.0e-8,"inte 2"); // An integral from -infinity to zero (the first limit argument is // ignored in the line below) acl.nf=0; gl.integ_err(f1,0.0,0.0,res,err); cout << "gsl_inte_qagil: " << endl; cout << "Return value: " << ret1 << endl; cout << "Result: " << res << " Uncertainty: " << err << endl; cout << "Number of iterations: " << gl.last_iter << endl; cout << "Number of function evaluations: " << acl.nf << endl; cout << endl; t.test_rel(res,sqrt(pi)/2.0,1.0e-8,"inte 3"); // An integral from 0 to 1 acl.nf=0; g.integ_err(f2,0.0,1.0,res,err); cout << "gsl_inte_qag: " << endl; cout << "Return value: " << ret1 << endl; cout << "Result: " << res << " Uncertainty: " << err << endl; cout << "Number of iterations: " << g.last_iter << endl; cout << "Number of function evaluations: " << acl.nf << endl; cout << endl; t.test_rel(res,0.5+sin(1.0)*sin(1.0),1.0e-8,"inte 4"); // An integral from 0 to 1 acl.nf=0; ca.integ_err(f2,0.0,1.0,res,err); cout << "cern_adapt: " << endl; cout << "Return value: " << ret1 << endl; cout << "Result: " << res << " Uncertainty: " << err << endl; cout << "Number of iterations: " << ca.last_iter << endl; cout << "Number of function evaluations: " << acl.nf << endl; cout << endl; t.test_rel(res,0.5+sin(1.0)*sin(1.0),1.0e-8,"inte 5"); t.report(); return 0; } // End of example
This example solves the differential equations defining the the Bessel and Airy functions with both the Cash-Karp and Prince-Dormand Steppers. It demonstrates the use of gsl_rkck, gsl_rk8pd, gsl_astep, and ode_iv_solve.
The Bessel functions are defined by
The Bessel functions of the first kind, are finite at the origin, and the example solves the
case, where
and
.
The Airy functions are defined by
This example solves for the Airy function of the first kind, .
Note that, when the step size is fixed, the Bessel function example is one case where the Prince-Dormand stepper (even though of higher order than the Cash-Karp stepper) is actually less accurate!
/* Example: ex_ode.cpp ------------------------------------------------------------------- An example to demonstrate solving differential equations */ #include <gsl/gsl_sf_bessel.h> #include <gsl/gsl_sf_airy.h> #include <gsl/gsl_sf_gamma.h> #include <o2scl/test_mgr.h> #include <o2scl/ovector_tlate.h> #include <o2scl/ode_funct.h> #include <o2scl/gsl_rkck.h> #include <o2scl/gsl_rk8pd.h> #include <o2scl/gsl_astep.h> #include <o2scl/ode_iv_solve.h> #include <o2scl/table.h> #ifdef O2SCL_HDF_IN_EXAMPLES #include <o2scl/hdf_file.h> #include <o2scl/hdf_io.h> #endif using namespace std; using namespace o2scl; #ifdef O2SCL_HDF_IN_EXAMPLES using namespace o2scl_hdf; #endif // Differential equation defining the Bessel function. This assumes // the second derivative at x=0 is 0 and thus only works for odd alpha. int derivs(double x, size_t nv, const ovector_base &y, ovector_base &dydx, double &alpha) { dydx[0]=y[1]; if (x==0.0) dydx[1]=0.0; else dydx[1]=(-x*y[1]+(-x*x+alpha*alpha)*y[0])/x/x; return 0; } // Differential equation defining the Airy function, Ai(x) int derivs2(double x, size_t nv, const ovector_base &y, ovector_base &dydx, double &alpha) { dydx[0]=y[1]; dydx[1]=y[0]*x; return 0; } int main(void) { cout.setf(ios::scientific); cout.setf(ios::showpos); // The independent variable and stepsize double x, dx=1.0e-1; // The function and derivative values and the estimated errors ovector y(2), dydx(2), yout(2), yerr(2), dydx_out(2); test_mgr t; t.set_output_level(1); // The parameter for the Bessel function double alpha=1.0; // Specify the differential equations to solve ode_funct_fptr_param<double,ovector_base> od(derivs,alpha); ode_funct_fptr_param<double,ovector_base> od2(derivs2,alpha); // The basic ODE steppers gsl_rkck<> ode; gsl_rk8pd<> ode2; // ------------------------------------------------------------ // Store the results in tables table tab[8]; tab[0].line_of_names("x calc exact diff err"); tab[1].line_of_names("x calc exact diff err"); tab[2].line_of_names("x calc exact diff err"); tab[3].line_of_names("x calc exact diff err"); tab[4].line_of_names("x calc exact diff err0 err1"); tab[5].line_of_names("x calc exact diff err0 err1"); tab[6].line_of_names("x calc exact diff err0 err1"); tab[7].line_of_names("x calc exact diff"); // ------------------------------------------------------------ // Solution 1: Solve using the non-adaptive Cash-Karp stepper. cout << "Bessel function, Cash-Karp: " << endl; // Initial values at x=0 x=0.0; y[0]=0.0; y[1]=0.5; // The non-adaptive ODE steppers require the derivatives as // input derivs(x,2,y,dydx,alpha); cout << " x J1(calc) J1(exact) rel. diff. " << "err" << endl; while (x<1.0) { // Perform a step. Since the fourth and sixth arguments are // the same, the values in 'y' are updated with the new values // at x+dx. ode.step(x,dx,2,y,dydx,y,yerr,dydx,od); // Update the x value x+=dx; // Print and test cout << x << " " << y[0] << " " << gsl_sf_bessel_J1(x) << " "; cout << fabs((y[0]-gsl_sf_bessel_J1(x))/gsl_sf_bessel_J1(x)) << " "; cout << yerr[0] << endl; t.test_rel(y[0],gsl_sf_bessel_J1(x),5.0e-5,"rkck"); // Also output the results to a table double line[5]={x,y[0],gsl_sf_bessel_J1(x), fabs((y[0]-gsl_sf_bessel_J1(x))/gsl_sf_bessel_J1(x)), yerr[0]}; tab[0].line_of_data(5,line); } // Compare with the exact result at the last point cout << "Accuracy at end: " << fabs(y[0]-gsl_sf_bessel_J1(x))/gsl_sf_bessel_J1(x) << endl; cout << endl; // ------------------------------------------------------------ // Solution 2: Solve using the non-adaptive Prince-Dormand stepper. // Note that for the Bessel function, the 8th order stepper performs // worse than the 4th order. The error returned by the stepper is // larger near x=0, as expected. cout << "Bessel function, Prince-Dormand: " << endl; x=0.0; y[0]=0.0; y[1]=0.5; derivs(x,2,y,dydx,alpha); cout << " x J1(calc) J1(exact) rel. diff. " << "err" << endl; while (x<1.0) { ode2.step(x,dx,2,y,dydx,y,yerr,dydx,od); x+=dx; cout << x << " " << y[0] << " " << gsl_sf_bessel_J1(x) << " "; cout << fabs((y[0]-gsl_sf_bessel_J1(x))/gsl_sf_bessel_J1(x)) << " "; cout << yerr[0] << endl; t.test_rel(y[0],gsl_sf_bessel_J1(x),5.0e-4,"rk8pd"); // Also output the results to a table double line[5]={x,y[0],gsl_sf_bessel_J1(x), fabs((y[0]-gsl_sf_bessel_J1(x))/gsl_sf_bessel_J1(x)), yerr[0]}; tab[1].line_of_data(5,line); } cout << "Accuracy at end: " << fabs(y[0]-gsl_sf_bessel_J1(x))/gsl_sf_bessel_J1(x) << endl; cout << endl; // ------------------------------------------------------------ // Solution 3: Solve using the non-adaptive Cash-Karp stepper. cout << "Airy function, Cash-Karp: " << endl; x=0.0; y[0]=1.0/pow(3.0,2.0/3.0)/gsl_sf_gamma(2.0/3.0); y[1]=-1.0/pow(3.0,1.0/3.0)/gsl_sf_gamma(1.0/3.0); derivs2(x,2,y,dydx,alpha); cout << " x Ai(calc) Ai(exact) rel. diff. " << "err" << endl; while (x<1.0) { ode.step(x,dx,2,y,dydx,y,yerr,dydx,od2); x+=dx; cout << x << " " << y[0] << " " << gsl_sf_airy_Ai(x,GSL_PREC_DOUBLE) << " "; cout << fabs((y[0]-gsl_sf_airy_Ai(x,GSL_PREC_DOUBLE))/ gsl_sf_airy_Ai(x,GSL_PREC_DOUBLE)) << " "; cout << yerr[0] << endl; t.test_rel(y[0],gsl_sf_airy_Ai(x,GSL_PREC_DOUBLE),1.0e-8,"rkck"); // Also output the results to a table double line[5]={x,y[0],gsl_sf_airy_Ai(x,GSL_PREC_DOUBLE), fabs((y[0]-gsl_sf_airy_Ai(x,GSL_PREC_DOUBLE))/ gsl_sf_airy_Ai(x,GSL_PREC_DOUBLE)), yerr[0]}; tab[2].line_of_data(5,line); } cout << "Accuracy at end: " << fabs(y[0]-gsl_sf_airy_Ai(x,GSL_PREC_DOUBLE))/ gsl_sf_airy_Ai(x,GSL_PREC_DOUBLE) << endl; cout << endl; // ------------------------------------------------------------ // Solution 4: Solve using the non-adaptive Prince-Dormand stepper. // On this function, the higher-order routine performs significantly // better. cout << "Airy function, Prince-Dormand: " << endl; x=0.0; y[0]=1.0/pow(3.0,2.0/3.0)/gsl_sf_gamma(2.0/3.0); y[1]=-1.0/pow(3.0,1.0/3.0)/gsl_sf_gamma(1.0/3.0); derivs2(x,2,y,dydx,alpha); cout << " x Ai(calc) Ai(exact) rel. diff. " << "err" << endl; while (x<1.0) { ode2.step(x,dx,2,y,dydx,y,yerr,dydx,od2); x+=dx; cout << x << " " << y[0] << " " << gsl_sf_airy_Ai(x,GSL_PREC_DOUBLE) << " "; cout << fabs((y[0]-gsl_sf_airy_Ai(x,GSL_PREC_DOUBLE))/ gsl_sf_airy_Ai(x,GSL_PREC_DOUBLE)) << " "; cout << yerr[0] << endl; t.test_rel(y[0],gsl_sf_airy_Ai(x,GSL_PREC_DOUBLE),1.0e-14,"rk8pd"); // Also output the results to a table double line[5]={x,y[0],gsl_sf_airy_Ai(x,GSL_PREC_DOUBLE), fabs((y[0]-gsl_sf_airy_Ai(x,GSL_PREC_DOUBLE))/ gsl_sf_airy_Ai(x,GSL_PREC_DOUBLE)), yerr[0]}; tab[3].line_of_data(5,line); } cout << "Accuracy at end: " << fabs(y[0]-gsl_sf_airy_Ai(x,GSL_PREC_DOUBLE))/ gsl_sf_airy_Ai(x,GSL_PREC_DOUBLE) << endl; cout << endl; // ------------------------------------------------------------ // Solution 5: Solve using the GSL adaptive stepper // Lower the output precision to fit in 80 columns cout.precision(5); cout << "Adaptive stepper: " << endl; gsl_astep<> ode3; x=0.0; y[0]=0.0; y[1]=0.5; cout << " x J1(calc) J1(exact) rel. diff."; cout << " err_0 err_1" << endl; int k=0; while (x<10.0) { int retx=ode3.astep(x,dx,10.0,2,y,dydx,yerr,od); if (k%3==0) { cout << retx << " " << x << " " << y[0] << " " << gsl_sf_bessel_J1(x) << " "; cout << fabs((y[0]-gsl_sf_bessel_J1(x))/gsl_sf_bessel_J1(x)) << " "; cout << yerr[0] << " " << yerr[1] << endl; } t.test_rel(y[0],gsl_sf_bessel_J1(x),5.0e-3,"astep"); t.test_rel(y[1],0.5*(gsl_sf_bessel_J0(x)-gsl_sf_bessel_Jn(2,x)), 5.0e-3,"astep 2"); t.test_rel(yerr[0],0.0,4.0e-6,"astep 3"); t.test_rel(yerr[1],0.0,4.0e-6,"astep 4"); t.test_gen(retx==0,"astep 5"); // Also output the results to a table double line[6]={x,y[0],gsl_sf_bessel_J1(x), fabs((y[0]-gsl_sf_bessel_J1(x))/gsl_sf_bessel_J1(x)), yerr[0],yerr[1]}; tab[4].line_of_data(6,line); k++; } cout << "Accuracy at end: " << fabs(y[0]-gsl_sf_bessel_J1(x))/gsl_sf_bessel_J1(x) << endl; cout << endl; // ------------------------------------------------------------ // Solution 6: Solve using the GSL adaptive stepper. // Decrease the tolerances, and the adaptive stepper takes // smaller step sizes. cout << "Adaptive stepper with smaller tolerances: " << endl; ode3.con.eps_abs=1.0e-8; ode3.con.a_dydt=1.0; x=0.0; y[0]=0.0; y[1]=0.5; cout << " x J1(calc) J1(exact) rel. diff."; cout << " err_0 err_1" << endl; k=0; while (x<10.0) { int retx=ode3.astep(x,dx,10.0,2,y,dydx,yerr,od); if (k%3==0) { cout << retx << " " << x << " " << y[0] << " " << gsl_sf_bessel_J1(x) << " "; cout << fabs((y[0]-gsl_sf_bessel_J1(x))/gsl_sf_bessel_J1(x)) << " "; cout << yerr[0] << " " << yerr[1] << endl; } t.test_rel(y[0],gsl_sf_bessel_J1(x),5.0e-3,"astep"); t.test_rel(y[1],0.5*(gsl_sf_bessel_J0(x)-gsl_sf_bessel_Jn(2,x)), 5.0e-3,"astep 2"); t.test_rel(yerr[0],0.0,4.0e-8,"astep 3"); t.test_rel(yerr[1],0.0,4.0e-8,"astep 4"); t.test_gen(retx==0,"astep 5"); // Also output the results to a table double line[6]={x,y[0],gsl_sf_bessel_J1(x), fabs((y[0]-gsl_sf_bessel_J1(x))/gsl_sf_bessel_J1(x)), yerr[0],yerr[1]}; tab[5].line_of_data(6,line); k++; } cout << "Accuracy at end: " << fabs(y[0]-gsl_sf_bessel_J1(x))/gsl_sf_bessel_J1(x) << endl; cout << endl; // ------------------------------------------------------------ // Solution 7: Solve using the GSL adaptive stepper. // Use the higher-order stepper, and less steps are required. The // stepper automatically takes more steps near x=0 in order since // the higher-order routine has more trouble there. cout << "Adaptive stepper, Prince-Dormand: " << endl; ode3.set_step(ode2); x=0.0; y[0]=0.0; y[1]=0.5; cout << " x J1(calc) J1(exact) rel. diff."; cout << " err_0 err_1" << endl; k=0; while (x<10.0) { int retx=ode3.astep(x,dx,10.0,2,y,dydx,yerr,od); if (k%3==0) { cout << retx << " " << x << " " << y[0] << " " << gsl_sf_bessel_J1(x) << " "; cout << fabs((y[0]-gsl_sf_bessel_J1(x))/gsl_sf_bessel_J1(x)) << " "; cout << yerr[0] << " " << yerr[1] << endl; } t.test_rel(y[0],gsl_sf_bessel_J1(x),5.0e-3,"astep"); t.test_rel(y[1],0.5*(gsl_sf_bessel_J0(x)-gsl_sf_bessel_Jn(2,x)), 5.0e-3,"astep"); t.test_rel(yerr[0],0.0,4.0e-8,"astep 3"); t.test_rel(yerr[1],0.0,4.0e-8,"astep 4"); t.test_gen(retx==0,"astep 5"); // Also output the results to a table double line[6]={x,y[0],gsl_sf_bessel_J1(x), fabs((y[0]-gsl_sf_bessel_J1(x))/gsl_sf_bessel_J1(x)), yerr[0],yerr[1]}; tab[6].line_of_data(6,line); k++; } cout << "Accuracy at end: " << fabs(y[0]-gsl_sf_bessel_J1(x))/gsl_sf_bessel_J1(x) << endl; cout << endl; // ------------------------------------------------------------ // Solution 8: Solve using the O2scl initial value solver // Return the output precision to the default cout.precision(6); cout << "Initial value solver: " << endl; ode_iv_solve<> ode4; // Define the grid and the storage for the solution const size_t ngrid=101; ovector xg(ngrid), yinit(2); omatrix yg(ngrid,2), ypg(ngrid,2); for(size_t i=0;i<ngrid;i++) xg[i]=((double)i)/10.0; // Set the initial value yinit[0]=0.0; yinit[1]=0.5; // Perform the full solution ode4.solve_grid<omatrix,omatrix_row,omatrix_alloc> (0.0,10.0,0.1,2,yinit,ngrid,xg,yg,ypg,od); // Output and test the results cout << " x J1(calc) J1(exact) rel. diff." << endl; for(size_t i=1;i<ngrid;i+=10) { cout << xg[i] << " " << yg[i][0] << " " << gsl_sf_bessel_J1(xg[i]) << " "; cout << fabs((yg[i][0]-gsl_sf_bessel_J1(xg[i]))/ gsl_sf_bessel_J1(xg[i])) << endl; t.test_rel(yg[i][0],gsl_sf_bessel_J1(xg[i]),5.0e-7,"astep"); t.test_rel(yg[i][1],0.5*(gsl_sf_bessel_J0(xg[i])- gsl_sf_bessel_Jn(2,xg[i])),5.0e-7,"astep 2"); // Also output the results to a table double line[4]={xg[i],yg[i][0],gsl_sf_bessel_J1(xg[i]), fabs((yg[i][0]-gsl_sf_bessel_J1(xg[i]))/ gsl_sf_bessel_J1(xg[i]))}; tab[7].line_of_data(4,line); } cout << "Accuracy at end: " << fabs(yg[ngrid-1][0]-gsl_sf_bessel_J1(xg[ngrid-1]))/ gsl_sf_bessel_J1(xg[ngrid-1]) << endl; cout << endl; // ------------------------------------------------------------ // Output results to a file #ifdef O2SCL_HDF_IN_EXAMPLES hdf_file hf; hf.open("ex_ode.o2"); for(size_t i=0;i<8;i++) { hdf_output(hf,tab[i],((string)"table_")+itos(i)); } hf.close(); #endif // ------------------------------------------------------------ cout.unsetf(ios::showpos); t.report(); return 0; } // End of example
This example solves the differential equations
which have the exact solution
using both the stiff stepper gsl_bsimp and the standard adaptive stepper gsl_astep . The adaptive stepper fails as becomes larger.
/* Example: ex_stiff.cpp ------------------------------------------------------------------- An example to demonstrate solving stiff differential equations */ #include <o2scl/test_mgr.h> #include <o2scl/ovector_tlate.h> #include <o2scl/funct.h> #include <o2scl/ode_funct.h> #include <o2scl/gsl_astep.h> #include <o2scl/gsl_bsimp.h> using namespace std; using namespace o2scl; int derivs(double x, size_t nv, const ovector_base &y, ovector_base &dydx) { dydx[0]=480.0*y[0]+980.0*y[1]; dydx[1]=-490.0*y[0]-990.0*y[1]; return 0; } int jac(double x, size_t nv, const ovector_base &y, omatrix_base &dfdy, ovector_base &dfdx) { dfdy[0][0]=480.0; dfdy[0][1]=980.0; dfdy[1][0]=-490.0; dfdy[1][1]=-990.0; dfdx[0]=0.0; dfdx[1]=0.0; return 0; } int main(void) { test_mgr t; t.set_output_level(1); cout.setf(ios::scientific); cout.precision(3); // Specification of the differential equations and the Jacobian ode_funct_fptr<ovector_base> od(derivs); ode_jac_funct_fptr<ovector_base> oj(jac); // ------------------------------------------------------------ // First solve with gsl_bsimp, designed to handle stiff ODEs gsl_bsimp<ode_funct_fptr<>,ode_jac_funct_fptr<> > gb; double x1, dx=1.0e-1; ovector y1(2), dydx1(2), yout1(2), yerr1(2), dydx_out1(2); x1=0.0; y1[0]=1.0; y1[1]=0.0; derivs(x1,2,y1,dydx1); for(size_t i=1;i<=40;i++) { gb.step(x1,dx,2,y1,dydx1,y1,yerr1,dydx1,od,oj); x1+=dx; cout.setf(ios::showpos); cout << x1 << " " << y1 << " " << yerr1 << " " << -exp(-500.0*x1)+2.0*exp(-10.0*x1) << " " << exp(-500.0*x1)-exp(-10.0*x1) << endl; cout.unsetf(ios::showpos); t.test_rel(y1[0],-exp(-500.0*x1)+2.0*exp(-10.0*x1),3.0e-4,"y0"); t.test_rel(y1[1],exp(-500.0*x1)-exp(-10.0*x1),3.0e-4,"y1"); } cout << endl; // ------------------------------------------------------------ // Now compare to the traditional adaptive stepper gsl_astep<ode_funct_fptr<> > ga; double x2; ovector y2(2), dydx2(2), yout2(2), yerr2(2), dydx_out2(2); x2=0.0; y2[0]=1.0; y2[1]=0.0; derivs(x2,2,y2,dydx2); size_t j=0; while (x2<4.0) { ga.astep(x2,dx,4.0,2,y2,dydx2,yerr2,od); if (j%25==0) { cout.setf(ios::showpos); cout << x2 << " " << y2 << " " << yerr2 << " " << -exp(-500.0*x2)+2.0*exp(-10.0*x2) << " " << exp(-500.0*x2)-exp(-10.0*x2) << endl; cout.unsetf(ios::showpos); } j++; } cout << endl; t.report(); return 0; } // End of example
/* Example: ex_anneal.cpp ------------------------------------------------------------------- An example to demonstrate minimization by simulated annealing */ #include <iostream> #include <cmath> #include <gsl/gsl_sf_bessel.h> #include <o2scl/ovector_tlate.h> #include <o2scl/multi_funct.h> #include <o2scl/funct.h> #include <o2scl/gsl_anneal.h> #include <o2scl/test_mgr.h> using namespace std; using namespace o2scl; // A simple function with many local minima. A "greedy" minimizer // would likely fail to find the correct minimum. double function(size_t nvar, const ovector_base &x) { double a, b; a=(x[0]-2.0); b=(x[1]+3.0); return -gsl_sf_bessel_J0(a)*gsl_sf_bessel_J0(b); } int main(int argc, char *argv[]) { test_mgr t; t.set_output_level(1); cout.setf(ios::scientific); gsl_anneal<> ga; double result; ovector init(2); multi_funct_fptr<> fx(function); ga.ntrial=1000; ga.verbose=1; ga.tolx=1.0e-7; ga.T_dec=1.1; // Choose an initial point at a local minimum away from // the global minimum init[0]=9.0; init[1]=9.0; // Perform the minimization ga.mmin(2,init,result,fx); cout << "x: " << init[0] << " " << init[1] << ", minimum function value: " << result << endl; cout << endl; // Test that it found the global minimum t.test_rel(init[0],2.0,1.0e-2,"another test - value"); t.test_rel(init[1],-3.0,1.0e-2,"another test - value 2"); t.test_rel(result,-1.0,1.0e-2,"another test - min"); t.report(); return 0; } // End of example
/* Example: ex_minte.cpp ------------------------------------------------------------------- An example to demonstrate multidimensional integration */ #include <o2scl/test_mgr.h> #include <o2scl/multi_funct.h> #include <o2scl/composite_inte.h> #include <o2scl/gsl_inte_qng.h> #include <o2scl/gsl_vegas.h> /// For M_PI #include <gsl/gsl_math.h> using namespace std; using namespace o2scl; double test_fun(size_t nv, const ovector_base &x) { double y=1.0/(1.0-cos(x[0])*cos(x[1])*cos(x[2]))/M_PI/M_PI/M_PI; return y; } int main(void) { test_mgr t; t.set_output_level(1); cout.setf(ios::scientific); double exact=1.3932039296; double res; double err; gsl_vegas<multi_funct<> > gm; ovector a(3), b(3); a.set_all(0.0); b.set_all(M_PI); multi_funct_fptr<> tf(test_fun); gm.n_points=100000; gm.minteg_err(tf,3,a,b,res,err); cout << res << " " << exact << " " << (res-exact)/err << endl; t.test_rel(res,exact,err*10.0,"O2scl"); t.report(); return 0; } // End of example
This example generates contour lines of the function
/* Example: ex_contour.cpp ------------------------------------------------------------------- Example for generating contour lines */ #include <iostream> #include <o2scl/test_mgr.h> #include <o2scl/contour.h> #include <o2scl/ovector_tlate.h> using namespace std; using namespace o2scl; // A function defining the three-dimensional surface // for which we want to compute contour levels double fun(double x, double y) { return 15.0*exp(-pow(x-20.0,2.0)/400.0-pow(y-5.0,2.0)/25.0) +40.0*exp(-pow(x-70.0,2.0)/500.0-pow(y-2.0,2.0)/4.0); } // A function for outputting the data to cout int print_data(int nx, int ny, ovector_base &x, ovector_base &y, omatrix_base &data); // A function for printing the contour information to a file int file_out(vector<contour_line> &conts, vector<contour_line> &conts2); int main(void) { test_mgr t; t.set_output_level(1); cout.setf(ios::scientific); contour co; // Initialize the data ovector x(12), y(10); omatrix data(10,12); for(size_t i=0;i<10;i++) { y[i]=((double)i); } for(size_t i=0;i<12;i++) { x[i]=((double)i)*((double)i); } for(size_t j=0;j<12;j++) { for(size_t k=0;k<10;k++) { data[k][j]=fun(x[j],y[k]); } } co.set_data(12,10,x,y,data); // Print out the data print_data(12,10,x,y,data); // Set the contour levels ovector levels(7); levels[0]=5.0; levels[1]=10.0; levels[2]=0.002; levels[3]=20.0; levels[4]=0.2; levels[5]=30.0; levels[6]=2.0; co.set_levels(7,levels); // Compute the contours vector<contour_line> conts; co.calc_contours(conts); // Print the contours to the screen and test to make sure // that they match the requested level size_t nc=conts.size(); for(size_t i=0;i<nc;i++) { cout << "Contour " << i << " at level " << conts[i].level << ":" << endl; size_t cs=conts[i].x.size(); for(size_t j=0;j<cs;j++) { cout << "(" << conts[i].x[j] << ", " << conts[i].y[j] << ") " << fun(conts[i].x[j],conts[i].y[j]) << endl; t.test_rel(fun(conts[i].x[j],conts[i].y[j]),conts[i].level, 1.0,"curve"); } cout << endl; } // Refine the data using cubic spline interpolation def_interp_mgr<ovector_const_view,cspline_interp> dim1; def_interp_mgr<ovector_const_subvector,cspline_interp> dim2; co.regrid_data(5,5,dim1,dim2); // Recompute the contours vector<contour_line> conts2; co.calc_contours(conts2); // Output the contour information to a file for the documentation file_out(conts,conts2); t.report(); return 0; } // End of example
The figure below shows contour lines in the region . The data grid is represented by plus signs, and the associated generated contours. The figure clearly shows the obvious peaks at
and
.
The contour class can also use interpolation to attempt to refine the data grid. The new contours after a refinement of a factor of 5 is given in the figure below.
/* Example: ex_twod_intp.cpp ------------------------------------------------------------------- A simple example for two-dimensional interpolation using the twod_intp class. */ #include <o2scl/twod_intp.h> #include <o2scl/test_mgr.h> using namespace std; using namespace o2scl; // A function for filling the data and comparing results double f(double x, double y) { return pow(sin(0.1*x+0.3*y),2.0); } int main(void) { int i,j; test_mgr t; t.set_output_level(1); // Create the sample data ovector x(3), y(3); omatrix data(3,3); cout.setf(ios::scientific); // Set the grid x[0]=0.0; x[1]=1.0; x[2]=2.0; y[0]=3.0; y[1]=2.0; y[2]=1.0; // Set and print out the data cout << endl; cout << "Data: " << endl; cout << " x | "; for(i=0;i<3;i++) cout << x[i] << " "; cout << endl; cout << " y |" << endl; cout << "-------------|-"; for(i=0;i<3;i++) cout << "-------------"; cout << endl; for(i=0;i<3;i++) { cout << y[i] << " | "; for(j=0;j<3;j++) { data[i][j]=f(x[j],y[i]); cout << data[i][j] << " "; } cout << endl; } cout << endl; // Perform the interpolation cout << "x y Calc. Exact" << endl; twod_intp ti; // Interpolation, x-first double tol=0.05; double tol2=0.4; ti.set_data(3,3,x,y,data,true); double x0, y0, x1, y1; x0=0.5; y0=1.5; cout << x0 << " " << y0 << " " << ti.interp(x0,y0) << " " << f(x0,y0) << endl; x0=0.99; y0=1.99; cout << x0 << " " << y0 << " " << ti.interp(x0,y0) << " " << f(x0,y0) << endl; x0=1.0; y0=2.0; cout << x0 << " " << y0 << " " << ti.interp(x0,y0) << " " << f(x0,y0) << endl; cout << endl; // Interpolation, y-first ti.set_data(3,3,x,y,data,false); x0=0.5; y0=1.5; cout << x0 << " " << y0 << " " << ti.interp(x0,y0) << " " << f(x0,y0) << endl; x0=0.99; y0=1.99; cout << x0 << " " << y0 << " " << ti.interp(x0,y0) << " " << f(x0,y0) << endl; x0=1.0; y0=2.0; cout << x0 << " " << y0 << " " << ti.interp(x0,y0) << " " << f(x0,y0) << endl; cout << endl; t.report(); return 0; } // End of example
This example creates a sample 3 by 3 grid of data with the function and performs some interpolations and compares them with the exact result.
Data: x | 0.000000e+00 1.000000e+00 2.000000e+00 y | -------------|---------------------------------------- 3.000000e+00 | 6.136010e-01 7.080734e-01 7.942506e-01 2.000000e+00 | 3.188211e-01 4.150164e-01 5.145998e-01 1.000000e+00 | 8.733219e-02 1.516466e-01 2.298488e-01 x y Calc. Exact 5.000000e-01 1.500000e+00 2.380255e-01 2.298488e-01 9.900000e-01 1.990000e+00 4.112589e-01 4.110774e-01 1.000000e+00 2.000000e+00 4.150164e-01 4.150164e-01 5.000000e-01 1.500000e+00 2.380255e-01 2.298488e-01 9.900000e-01 1.990000e+00 4.112589e-01 4.110774e-01 1.000000e+00 2.000000e+00 4.150164e-01 4.150164e-01
/* Example: ex_mandel.cpp ------------------------------------------------------------------- Mandelbrot example demonstrating table3d and complex arithmetic */ #include <iostream> #include <o2scl/cx_arith.h> #include <o2scl/test_mgr.h> #include <o2scl/table3d.h> #ifdef O2SCL_HDF_IN_EXAMPLES #include <o2scl/hdf_file.h> #include <o2scl/hdf_io.h> #endif using namespace std; using namespace o2scl; #ifdef O2SCL_HDF_IN_EXAMPLES using namespace o2scl_hdf; #endif int main(void) { test_mgr tm; tm.set_output_level(2); // Create a table3d object table3d t; // Add parameters double delta=0.001, minx=-1.5, maxx=0.8, miny=-1.0, maxy=1.0; size_t maxtime=0, limit=100; t.add_constant("delta",delta); t.add_constant("minx",minx); t.add_constant("maxx",maxx); t.add_constant("miny",miny); t.add_constant("maxy",maxy); // Set grid ovector ox, oy; for(double x=minx;x<=maxx;x+=delta) ox.push_back(x); for(double y=miny;y<=maxy;y+=delta) oy.push_back(y); t.set_xy("x",ox.size(),ox,"y",oy.size(),oy); // Create slice t.new_slice("time"); // Compute escape times for(size_t i=0;i<ox.size();i++) { for(size_t j=0;j<oy.size();j++) { gsl_complex c={{ox[i],oy[j]}}; gsl_complex z={{0,0}}; size_t time=0; for(size_t k=0;k<limit;k++) { // Arithmetic with gsl_complex objects z=z*z+c; if (abs(z)>10.0) { time=k; k=limit; } } t.set(i,j,"time",time); if (time>maxtime) maxtime=time; } } // Maximum escape time for color normalization t.add_constant("maxtime",maxtime); // Output to file if O2scl is compiled with HDF support #ifdef O2SCL_HDF_IN_EXAMPLES hdf_file hf; hf.open("ex_mandel.o2"); hdf_output(hf,t,"mandel"); hf.close(); #endif tm.test_gen(maxtime==99,"maxtime test"); tm.report(); return 0; } // End of example
The information stored in the table3d object in ex_mandel.out can be plotted:
This example solves the ODEs
given the boundary conditions
by linearizing the ODEs on a mesh and using an iterative method (sometimes called relaxation). The ode_it_solve class demonstrates how this works, but is slow for large grid sizes because the matrix is very sparse. See O2scl_iml which shows how a similar problem can be done more efficiently using the native iterative method and sparse matrix format.
/* Example: ex_ode_it.cpp ------------------------------------------------------------------- Demonstrate the iterative method for solving ODEs */ #include <o2scl/ode_it_solve.h> #include <o2scl/ode_iv_solve.h> #include <o2scl/linear_solver.h> using namespace std; using namespace o2scl; using namespace o2scl_linalg; // The three-dimensional ODE system class ode_system { public: // The LHS boundary conditions double left(size_t ieq, double x, ovector_base &yleft) { if (ieq==0) return yleft[0]-1.0; return yleft[1]*yleft[1]+yleft[2]*yleft[2]-2.0; } // The RHS boundary conditions double right(size_t ieq, double x, ovector_base &yright) { return yright[1]-3.0; } // The differential equations double derivs(size_t ieq, double x, ovector_base &y) { if (ieq==1) return y[0]+y[1]; else if (ieq==2) return y[0]+y[2]; return y[1]; } // This is the alternative specification for ode_iv_solve for // comparison int shoot_derivs(double x, size_t nv, const ovector_base &y, ovector_base &dydx) { dydx[0]=y[1]; dydx[1]=y[0]+y[1]; dydx[2]=y[0]+y[2]; return 0; } }; int main(void) { test_mgr t; t.set_output_level(1); cout.setf(ios::scientific); // The ODE solver ode_it_solve<ode_it_funct<ovector_base>,ovector_base, omatrix_base,omatrix_row,ovector_base,omatrix_base> oit; // The class which contains the functions to solve ode_system os; // Make function objects for the derivatives and boundary conditions ode_it_funct_mfptr<ode_system> f_d(&os,&ode_system::derivs); ode_it_funct_mfptr<ode_system> f_l(&os,&ode_system::left); ode_it_funct_mfptr<ode_system> f_r(&os,&ode_system::right); // Grid size size_t ngrid=40; // Number of ODEs size_t neq=3; // Number of LHS boundary conditions size_t nbleft=2; // Create space for the solution and make an initial guess ovector x(ngrid); omatrix y(ngrid,neq); for(size_t i=0;i<ngrid;i++) { x[i]=((double)i)/((double)(ngrid-1)); y[i][0]=1.0+x[i]+1.0; y[i][1]=3.0*x[i]; y[i][2]=-0.1*x[i]-1.4; } int pa=0; // Workspace objects omatrix A(ngrid*neq,ngrid*neq); ovector rhs(ngrid*neq), dy(ngrid*neq); // Perform the solution oit.verbose=1; oit.solve(ngrid,neq,nbleft,x,y,f_d,f_l,f_r,A,rhs,dy); // Compare with the initial value solver ode_iv_solve ode_iv_solve<> ois; ode_funct_mfptr<ode_system> f_sd(&os,&ode_system::shoot_derivs); ovector ystart(neq), yend(neq); for(size_t i=0;i<neq;i++) ystart[i]=y[0][i]; ois.solve_final_value(0.0,1.0,0.01,neq,ystart,yend,f_sd); // Test the result t.test_rel(y[0][0],1.0,1.0e-3,"ya"); t.test_rel(y[ngrid-1][0],yend[0],1.0e-3,"yb"); t.test_rel(y[0][1],0.25951,1.0e-3,"yc"); t.test_rel(y[ngrid-1][1],yend[1],1.0e-3,"yd"); t.test_rel(y[0][2],-1.3902,1.0e-3,"ye"); t.test_rel(y[ngrid-1][2],yend[2],1.0e-3,"yf"); t.report(); return 0; } // End of example
This examples creates a Markov chain for an aritrary distribution using the Metropolis-Hastings algorithm. It generates the one-dimensional distribution
for .
/* Example: ex_markov.cpp ------------------------------------------------------------------- An example to demonstrate generation of an arbitrary distribution through the creation of a Markov chain using the Metropolis-Hastings (MH) algorithm. */ #include <iostream> #include <cmath> #include <o2scl/test_mgr.h> #include <o2scl/table.h> #include <o2scl/gsl_rnga.h> using namespace std; using namespace o2scl; /* An unusual two-peaked probability distribution. This distribution is interesting because it is strongly bimodal, and thus the MH algorithm has to step over a region where the probability distribution is small. */ double function(double x) { return exp(-x*x)*(sin(x-1.4)+1.0); } int main(int argc, char *argv[]) { test_mgr t; t.set_output_level(1); cout.setf(ios::scientific); // The square root of the number of iterations static const size_t N=1000; // The histogram stepsize static const size_t hs=101; // The stepsize for the MH algorithm. If this stepsize was too // small, the MH algorithm would fail to step between the two peaks // and give incorrect results. double step=1.0; // The random number generator gsl_rnga gr; // Use a table object for a histogram. Initialize the grid spacing // with a unform grid between -5 and 5. table tab; tab.line_of_names("x dat"); tab.set_nlines(hs); for(size_t i=0;i<hs;i++) { tab.set("x",i,-5.0+((double)i)*10.0/(hs-1)); tab.set("dat",i,0.0); } // An initial point and the initial weight double x_old=0.01; double w_old=function(x_old); for(size_t k=0;k<N;k++) { for(size_t i=0;i<N;i++) { // Perform a step and compute the new weight double r=gr.random(); double x_new=x_old+r*step*2.0-step; double w_new=function(x_new); // The MH algorithm double r2=gr.random(); if (r2<w_new/w_old && x_new>-5.0 && x_new<5.0) { x_old=x_new; w_old=w_new; } // Update the histogram tab.hist_update("x","dat",x_old); } } // Normalize by the value of the distribution at x=1.05 double norm=tab.hist_get("x","dat",1.05)/function(1.05); // Output the generated distribution and compare to the real // distribution. for(size_t i=0;i<hs-1;i++) { cout.width(2); cout << i << " "; cout.setf(ios::showpos); double xx=(tab.get("x",i)+tab.get("x",i+1))/2.0; cout << xx << " "; cout.unsetf(ios::showpos); cout << tab.get("dat",i)/norm << " " << function(xx) << endl; // Only test regions where we'll have enough statistics if (function(xx)>5.0e-3) { t.test_rel(tab.get("dat",i)/norm,function(xx),1.0e-1,"dist"); } } t.report(); return 0; } // End of example
Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information). Project hosting by |
|