![]() |
Object-oriented Scientific Computing Library: Version 0.910
|
Functions are passed to numerical routines using template-based function classes, sometimes called "functors". There are several basic kinds of function objects:
n
functions of n
variablesn
fitting parametersn
derivatives as a function of n
function values and the value of the independent variableThe class name suffixes denote children of a generic function type which are created using different kinds of inputs:
See the Function object example and the Multi-dimensional solver which provide detailed examples of how functions can be specified to classes through these function objects.
The O2scl function types are very closely related to similar types in the Standard Template Library (STL) and in Boost. In the language of the STL, funct implements the concept of a Unary Function where the argument and return types are both double
. In turn, most O2scl classes which have a template parameter func_t
will accept all classes which implement this same concept. Note that in the STL, Unary Functions also implement the Assignable concept, and O2scl classes often do not require this for objects of type func_t
. The Boost library handles things in a very similar way, except that STL concepts are referred to as "traits", and there is a much more complete list of "type traits".
There is a small overhead associated with the indirection: a "user class" accesses the function class which then calls function which was specified in the constructor of the function class. In many problems, the overhead associated with the indirection is small. Some of this overhead can always be avoided by inheriting directly from the function class and thus the user class will make a direct virtual function call. To eliminate the overhead entirely, one can specify a new type for the template parameter in the user class.
Virtual functions can be specified through this mechanism as well. For example, if cern_mroot is used to solve a set of equations specified as
class my_type_t { virtual member_func(); }; my_type_t my_instance; class my_derived_type_t : public my_type_t { virtual member_func(); }; my_derived_type_t my_inst2; mm_funct_mfptr<my_type_t> func(&my_inst2,&my_instance::member_func);
Then the solver will solve the member function in the derived type, not the parent type.
Note that providing a user access to a function object instantiatied with a protected or private member function is (basically) the same as providing them access to that function.
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. 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); // Obtain and summarize test results t.test_abs(c.function_to_solve(x1,p),0.0,1.0e-10,"ex_fptr"); t.report(); return 0; } // End of example
Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).