4

So, while I am pretty happy to find a lot of answers on Stack Overflow I decided it is time to ask a question myself.
I am trying to use a root finding algorithm with derivatives. In accordance with the GSL I have to define the function and its derivative in advance. But I wonder if this can be done more elegant with a wrapper.

Some time ago I found a very handy template (GSL C++ wrapper) which works fine for one function to e.g. integrate and I make heavy usage of it.

Now I am wondering if this approach can be extended to provide two functions for the GSL, namely the function itself and its derivative.

Edit: Solution

template <typename F, typename G>
class gsl_root_deriv : public gsl_function_fdf
{
private:
    const F&    _f;
    const G&    _df;

    static double invoke_f(double x, void* params){
        return static_cast<gsl_root_deriv*>(params) -> _f(x);
    }

    static double invoke_df(double x, void* params){
        return static_cast<gsl_root_deriv*>(params) -> _df(x);
    }

    static void     invoke_fdf(double x, void* params, double* f, double* df){
        (*f)    = static_cast<gsl_root_deriv*>(params)  ->  _f(x);
        (*df)   = static_cast<gsl_root_deriv*>(params)  ->  _df(x);
    }

public:
    gsl_root_deriv(const F& f_init, const G& df_init)
    : _f(f_init), _df(df_init)
    {
        f               = &gsl_root_deriv::invoke_f;
        df          = &gsl_root_deriv::invoke_df;
        fdf         = &gsl_root_deriv::invoke_fdf;
        params  = this;
    }
};

And a minimal example which resembles the example from the GSL:

#include <iostream>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_roots.h>
#include <memory>

#include "gsl_root_deriv.h"

int main()
{
auto f = [](double x) -> double { return 0.25 * x*x - 1.0; };
auto df = [](double x) -> double { return 0.5 * x; };

gsl_root_deriv<decltype(f),decltype(df)> Fp(f,df);

int status(0), iter(0), max_iter(100);

const gsl_root_fdfsolver_type* T( gsl_root_fdfsolver_newton);

std::unique_ptr<gsl_root_fdfsolver,void(*)(gsl_root_fdfsolver*)>
    s(gsl_root_fdfsolver_alloc(T),gsl_root_fdfsolver_free);

double x_0(0.0), x(5.0);

gsl_root_fdfsolver_set( s.get(), &Fp, x );

do
{
    iter++;
    std::cout << "Iteration " << iter << std::endl;
    status = gsl_root_fdfsolver_iterate( s.get() );
    x_0 = x;
    x = gsl_root_fdfsolver_root( s.get() );
    status = gsl_root_test_delta( x, x_0, 0.0, 1.0e-3 );
} while( status == GSL_CONTINUE && iter < max_iter );

std::cout << "Converged to root " << x << std::endl;

return 0;
}

Kind regards,
-- Klaus

Community
  • 1
  • 1
  • If you liked so much, you could give a vote up to that answer :p – Vivian Miranda Jul 07 '14 at 03:04
  • Need a second template parameter. I Forgot about that! – Vivian Miranda Jul 07 '14 at 16:07
  • One more thing. If you have a more efficient way to calculate fdf (f and df at the same time), you may add a third argument in the constructor. Here I just showed a basic implementation. – Vivian Miranda Jul 07 '14 at 16:17
  • To be honest, I do not get the idea of your comment. Furthermore I must confess that I do not get the reason why a second template argument is needed. I mean, both f and df (from the gsl_function_fdf struct) are pointer to functions returning a double, thus they are of the same 'type' or not? Thus why does a single typename F not suffice? Do not hesitate to answer 'it is time for me to read a book' ;) Regards -- –  Jul 07 '14 at 17:28
  • GSL ask the third fdf function in case the user has an optimized way to calculate f and df at the same time. If you do have a better implementation in this case, it might be worth adding a third function in the constructor. – Vivian Miranda Jul 07 '14 at 19:01
  • It is good C++ question to ask @stackoverflow why the second template parameter is needed. I also got confused. – Vivian Miranda Jul 07 '14 at 19:03

1 Answers1

1

You will need to do some modifications

Gsl fdf struct is the following

struct gsl_function_fdf_struct 
{
  double (* f) (double x, void * params);
  double (* df) (double x, void * params);
  void (* fdf) (double x, void * params, double * f, double * df);
  void * params;
};

typedef struct gsl_function_fdf_struct gsl_function_fdf ;

If you understood what the wrapper actually does, then you will see that generalization is quite straightforward

class gsl_function_fdf_pp : public gsl_function_fdf
{
   public:
   gsl_function_fdf_pp
   (
     std::function<double(double)> const& kf, 
     std::function<double(double)> const& kdf
   ) : _f(kf), _df(kdf)
   {
      f   = &gsl_function_fdf_pp::invoke;
      df  = &gsl_function_fdf_pp::invoke2;
      fdf = &gsl_function_fdf_pp::invoke3;
      params=this;
   }     
   private:
   std::function<double(double)> _f;
   std::function<double(double)> _df;

   static double invoke(double x, void *params) 
   {
     return static_cast<gsl_function_fdf_pp*>(params)->_f(x);
   }

   static double invoke2(double x, void *params) 
   {
     return static_cast<gsl_function_fdf_pp*>(params)->_df(x);
   }

   static void invoke3(double x, void * params, double* f, double* df)
   {
     (*f)  = static_cast<gsl_function_fdf_pp*>(params)->_f(x);
     (*df) = static_cast<gsl_function_fdf_pp*>(params)->_df(x);
   }
};

The template version.

template< typename F, typename U >  class gsl_function_fdf_pp : public gsl_function_fdf 
{
  public:
  gsl_function_fdf_pp(const F& kf, const U& kdf) : _f(kf), _df(kdf)
  {
    f   = &gsl_function_fdf_pp::invoke;
    df  = &gsl_function_fdf_pp::invoke2;
    fdf = &gsl_function_fdf_pp::invoke3;
    params=this;
  }
  private:
  const F& _f;
  const U& _df;

  static double invoke(double x, void *params) 
  {
    return static_cast<gsl_function_fdf_pp*>(params)->_f(x);
  }

  static double invoke2(double x, void *params) 
  {
    return static_cast<gsl_function_fdf_pp*>(params)->_df(x);
  }

  static void invoke3(double x, void * params, double* f, double* df)
  {
    (*f)  = static_cast<gsl_function_fdf_pp*>(params)->_f(x);
    (*df) = static_cast<gsl_function_fdf_pp*>(params)->_df(x);
  }
}; 

EDIT2: After fixing 2 small problems, this example works

int main()
{
  auto f  = [](double x)->double{ return x*x; };
  auto df = [](double x)->double{ return 2.0 * x; };

  gsl_function_fdf_pp<decltype(f),decltype(df)> Fp(f,df);

  return 0;
}
Vivian Miranda
  • 2,467
  • 1
  • 17
  • 27
  • Dear Vinicius, thank you very much for your reply. I digged into the gsl directory and successfully found the gsl_function_fdf struct in math.h. I guess that I understood the idea of the class (template) so far: You derive an inheritance from the gsl_function_fdf struct and modify it according to the C++ interface. Due to inheritance, the gsl_function_fdf_pp object _is_ is gsl_function_fdf object and the gsl can handle it. The only thing I do not fully grasp: Why do you cast the params pointer? Could you elaborate that? Kind regards, Klaus –  Jul 07 '14 at 08:14
  • Because static member functions can't point to non-static member pointers (like, for example, the pointer this!). So we use the params void pointer to reference the current instantaneous of the class! – Vivian Miranda Jul 07 '14 at 14:06
  • Thanks. But the template does not work, please see the minimal example in the edit of my first post. Kind regards –  Jul 07 '14 at 15:30
  • There was a typo in constructor name and I forgot to add second template parameter – Vivian Miranda Jul 07 '14 at 16:06
  • 1
    Okay, I think now you added a comma too much. ;) Regards –  Jul 07 '14 at 17:29