Search code examples
c++pointersintegralalglib

Integrate a public but non static member function with ALGLIB


I am trying to integrate a member function of a class, and needs some help! I cannot declare the function static because this function uses non-static private members (more specifically use a private member which is another class). I am using C++17 and cannot downgrade

I write below a Minimum (Non) Working Example that mimic my problem. The aim is to find what to put instead of the four question marks '????' in alglib::autogkintegrate(s, ????, params).

The alglib::autogkintegrate function takes three arguments:

  1. a 'state' which contains the current value of the integration, integral boundaries, other stuff?)
  2. The function f to integrate which must be of the prototype void f(double x, double xminusa, double bminusx, double &y, void *ptr)
  3. an optional pointer void *ptr which contains extra parameters for the function f

Here is the non working example:

#include <functional>
#include <iostream>
#include <cmath>

#include "integration.h"

class Foo;
class Bar;

/*****************************
    Class Foo
*****************************/
class Foo
{
    public:
        // Constructor
        Foo(Bar *b, int toto);

        // Function to integrate
        void f(double x, double xminusa, double bminusx, double &y, void *ptr);
        
    private:
        Bar *m_bar;
        int m_toto;
};

Foo::Foo(Bar *b, int toto) : m_bar(b), m_toto(toto)
{}

void Foo::f(double x, double xminusa, double bminusx, double &y, void *ptr)
{
    double *param = (double *) ptr;
    double p1 = param[0];
    double p2 = param[1];

    y = exp(this->m_toto*x)/(p1 * p2);
}

/*****************************
    Class Bar
*****************************/
class Bar
{
    friend Foo;
    public:
        // Constructor
        Bar();
        
    private:
        int m_a, m_b;
};

Bar::Bar() : m_a(2), m_b(5)
{}

/*****************************
    Main program
*****************************/
int main(int argc, char *argv[])
{
    Bar* b = new Bar();

    Foo f(b, 87);

    double arrayParams[2] = {1, 2};
    double (*params)[2] = &arrayParams;

    alglib::autogkstate s;
    double v;
    alglib::autogkreport rep;
    alglib::autogksmooth(0, 1, s);
    alglib::autogkintegrate(s, ????, params);
    alglib::autogkresults(s, v, rep);

    return 0;
}

If I declare the function f as static (and remove this->m_totoin f), then I can integrate fby using alglib::autogkintegrate(s, Foo::f, params);. So the problem is really to get access to the function f.

I tried to define a pointer to member function (which explains #include <functional>) but failed to use it in alglib::autogkintegrate(s, ????, params);

To repeat my question: I want to integrate a member function of a class using ``Alglib``` in C++

Useful links:

  1. https://www.alglib.net/translator/man/manual.cpp.html#gs_using section 8.5
  2. https://www.alglib.net/translator/man/manual.cpp.html#example_autogk_d1

P.S.: I also posted this question at http://forum.alglib.net/viewtopic.php?f=2&t=4352 which is a dedicated forum to Alglib (but looks much less active than Stack Overflow, hence my double post. If I get an answer there, I will copy-paste here, and vice-versa)


Solution

  • I found a solution on http://www.newty.de/fpt/callback.html using a global variable (sorry...). I post here the code adapted to my question if anyone needs it:

    #include <functional>
    #include <iostream>
    #include <cmath>
    
    #include "integration.h"
    
    class Foo;
    class Bar;
    
    void* pt2Object; // global variable which points to an arbitrary object
    
    /*****************************
        Class Foo
    *****************************/
    class Foo
    {
        public:
            // Constructor
            Foo(Bar *b, int toto);
    
            // Function to integrate
            void f(double x, double xminusa, double bminusx, double &y, void *ptr);
    
            // Wrapper
            static void Wrapper_To_Call_f(double x, double xminusa, double bminusx, double &y, void *ptr);
            
        private:
            Bar *m_bar;
            int m_toto;
    };
    
    Foo::Foo(Bar *b, int toto) : m_bar(b), m_toto(toto)
    {}
    
    void Foo::f(double x, double xminusa, double bminusx, double &y, void *ptr)
    {
        double *param = (double *) ptr;
        double p1 = param[0];
        double p2 = param[1];
    
        y = exp(this->m_toto*x)/(p1 * p2);
        // y = exp(x)/(p1 * p2);
    }
    
    void Foo::Wrapper_To_Call_f(double x, double xminusa, double bminusx, double &y, void *ptr)
    {
        // explicitly cast global variable <pt2Object> to a pointer to TClassB
        // warning: <pt2Object> MUST point to an appropriate object!
        Foo* mySelf = (Foo*) pt2Object;
    
        // call member
        mySelf->f(x, xminusa, bminusx, y, ptr);
    }
    
    /*****************************
        Class Bar
    *****************************/
    class Bar
    {
        friend Foo;
        public:
            // Constructor
            Bar();
            
        private:
            int m_a, m_b;
    };
    
    Bar::Bar() : m_a(2), m_b(5)
    {}
    
    /*****************************
        Main program
    *****************************/
    int main(int argc, char *argv[])
    {
        Bar* b = new Bar();
    
        // Create Foo
        Foo myFoo(b, 1);
        // Assign global variable which is used in the static wrapper function
        // important: never forget to do this!!
        pt2Object = (void*) &myFoo;
    
        double arrayParams[2] = {1, 2};
        double (*params)[2] = &arrayParams;
    
        alglib::autogkstate s;
        double v;
        alglib::autogkreport rep;
        alglib::autogksmooth(0, 1, s);
        alglib::autogkintegrate(s, Foo::Wrapper_To_Call_f, params);
        alglib::autogkresults(s, v, rep);
    
        std::cout << v << std::endl;
    
        return 0;
    }