GSL function adapters

Wrappers for GSL functions. More...

Classes

class  julian::GslFunctionAdapter< F >
 Class implements adapter for gsl_function. More...
 
class  julian::GslFunctionFdfAdapter< F, dF >
 Class implements adapter for gsl_function_fdf. More...
 
class  julian::GslMultiminFunctionAdapter< F >
 Class implements adapter for gsl_multimin_function. More...
 
class  julian::GslMultiminFunctionFdfAdapter< F, dF, FdF >
 Class implements adapter for gsl_multimin_function. More...
 

Detailed Description

Wrappers for GSL functions.

The most important aspect of numerical routines is providing the function to the numerical algorithm. The GSL is a library written in C, so it does not take of the advantages of OOP. Instead of objects, GSL is using structures containing pointer to functions. The C functions are free functions and can't hold state. The fact that C functions can't hold state, makes parametrization of the function harder. In GSL this problem was solved by adding the void pointer to interface of the functions that are passed to numerical routines.

Those void pointers reference the structure holding the function's parameters. The numerical algorithm does not have any information about the structure pointed to void pointer, it just passed is to function, where pointer is casted to proper structure and dereferenced.

As this mechanism is quite complicated and hard to use, we provided the wrapper objects that map C++ functors (structure/classes with overloaded operator() method) to GSL functions. Wrapper decouples data and method of functor and passes them as void pointer and free function.

Simple example below:

1 #include <iostream>
2 #include <cmath>
3 
4 //
5 // Lines contain definition of structure holding parameters of quadratic function
6 //
7 struct params_quadratic {
8  double a,b,c;
9 };
10 
11 //
12 // Definition of quadratic function. Note that quadratic function accepts:
13 // argument x and void pointer, which is later casted to structure holding function's parameters.
14 //
15 double quadratic(double x, void* p) {
16  struct params_quadratic * pp = (struct params_quadratic*)p;
17  return pp->a*x*x + pp->b*x + pp->c;
18 }
19 
20 struct params_sinus {
21  double A,w,fi;
22 };
23 
24 //
25 // Definition of another function. Note that sin_ function has the same
26 // interface as the quadratic function, despite being parametrized with different structure.
27 //
28 double sinus(double x, void* p) {
29  struct params_sinus * pp = (struct params_sinus*)p;
30  return pp->A*sin(pp->w*x+pp->fi);
31 }
32 
33 //
34 // Definition of numerical algorithm. We define structure holding function and its parameters.
35 // fwdDiff approximates derivative using numerical scheme.
36 //
37 struct functional_struct {
38  double (*f)(double, void*);
39  void* p;
40 };
41 
42 double fwdDiff(functional_struct func, double x) {
43  double h = 1e-5;
44  return (func.f(x+h, func.p) - func.f(x, func.p)) / h;
45 }
46 
47 //
48 // We define C++ adapter for functional structure.
49 // Adapter inherits functional_structure's fields. Apart from those fields it has also a functor object.
50 // Function call transform functor's operator() with into free function with interface accepted by numerical algorithm fwdDiff.
51 // The whole Adapter object is passed to fwdDiff by void pointer, which allows passing all data hold by Functor to numerical algorithm.
52 //
53 template<typename F>
54 class Adapter : public functional_struct {
55  public:
56  Adapter(const F& functor) : functor_(functor) {
57  f = &Adapter::call;
58  p = this;
59  }
60  private:
61  static double call(double x, void *params) {
62  return static_cast<Adapter*>(params)->functor_(x);
63  }
64  const F& functor_;
65 };
66 
67 //
68 // Wrapper function casts Adapter to functional_struct and calls numerical algorithm.
69 // Thanks to this construction user can call numerical algorithm just by defining lambda expression and calling wrapper function.
70 // There is no need to define separate parameter structures or free functions. In case more advanced setting up algorithm is more complex.
71 // Wrapper function helps us to hide this procedure.
72 //
73 template<typename F>
74 double fwdDiffWrapper(F f, double x) {
75  Adapter<decltype(f)> adapter(f);
76  functional_struct* lambda_f = static_cast<functional_struct*>(&adapter);
77  return fwdDiff(*lambda_f, x);
78 }
79 
80 int main() {
81  params_quadratic params1 {4.0, 2.0, 1.0};
82 
83  functional_struct f1;
84  f1.f = &quadratic;
85  f1.p = &params1;
86 
87  params_sinus params2 {2.0, 1.0, 5.0};
88 
89  functional_struct f2;
90  f2.f = &sinus;
91  f2.p = &params2;
92 
93  std::cout << "Numerical algorithm - using pointer to function\n";
94  std::cout << "Quadratic function\t" << fwdDiff(f1, 1.0) << std::endl;
95  std::cout << "Sin function\t\t" << fwdDiff(f2, 1.0) << std::endl;
96 
97  double a = 4.0, b = 2.0, c = 1.0;
98  auto lambda1 =[a, b, c](double x)->double {
99  return a*x*x + b*x + c;
100  };
101 
102  double A = 2.0, w = 1.0, fi = 5.0;
103  auto lambda2 =[A, w, fi](double x)->double {
104  return A*sin(w*x+fi);
105  };
106 
107  std::cout << "Numerical algorithm - using wrapper\n";
108  std::cout << "Quadratic function\t" << fwdDiffWrapper(lambda1, 1.0) << std::endl;
109  std::cout << "Sin function\t\t" << fwdDiffWrapper(lambda2, 1.0);
110 }

Output

Numerical algorithm - using pointer to function
Quadratic function	10
Sin function		1.92034
Numerical algorithm - using wrapper
Quadratic function	10
Sin function		1.92034