Object-oriented Scientific Computing Library: Version 0.910
Function Objects

Functions are passed to numerical routines using template-based function classes, sometimes called "functors". There are several basic kinds of function objects:

The 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.

Connection to STL and Boost

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".

Function object details

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.

Function object example

This example shows how to provide functions to O2scl classes by solving the equation

\[ \left\{ 1+\frac{1}{p_2} \sin \left[ 50 \left( x-p_1 \right) \right] \right\} \tan^{-1} \left[ 4 \left( x-p_1 \right) \right] = 0 \]

Where $ p_1 = 0.01 $ and $ p_2 = 1.1 $. The parameter $ p_1 $ is stored as member data for the class, and the parameter $ p_2 $ is an argument to the member function.

The image below shows how the solver progresses to the solution of the example function.

ex_fptr_plot.png
Function object example plot
/* 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

 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).

Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads.