1

I am trying to build an optimization library in C++ for parameters optimization.

The problem and the parameters type may vary, e.g. if the problem is to minimize the Ackley Function, then we have a vector<double> of size 2 (index 0 for the x, and index 1 for the y). However, we may have problems where the parameters are integers, or even strings.

Many algorithm exist for this type of optimization, like Genetic Algorithm, Differential Evolution, etc. In most of them, once we modify the parameters based on their optimization strategy, we have to call an evaluation function that receives the parameters, and given a objective function, will return a value (fitness).

My question is how could I implement an abstract class Problem in C++ such that it contains an virtual double evaluate function in which receives as reference a vector of the generic type of the related problem? For example, user's problem should inherit Problem and he needs to specify a type T, in this case, the evaluation function should be like virtual double evaluate(const vector<T> &parameters){}.

If the strategy which I mentioned above is not feasible for C++. Please, suggest alternatives strategies.

Bibeviwi
  • 13
  • 3
  • 1
    Possible duplicate of [Can a class member function template be virtual?](https://stackoverflow.com/questions/2354210/can-a-class-member-function-template-be-virtual) – walnut Oct 14 '19 at 08:51
  • 1
    I am seeking a way to solve my issue. The question is related to solve the problem, not related to the C++ language. If you understand that I am proposing something that is not feasible for C++, suggest alternative strategies. – Bibeviwi Oct 14 '19 at 08:52
  • @Bibeviwi if making `Problem` itself a template suits your needs, it won't get simpler than that. – Quentin Oct 14 '19 at 08:55
  • 1
    @Quentin sorry but I did not understand your comment. Could you formulate it as an answer? – Bibeviwi Oct 14 '19 at 08:58
  • 1
    @Quentin how could I make it "easy" for the user of the library to understand that once he inherit from Problem, he needs to override an evaluation function, but only the one which receives the vector of type that is realted to his problem? – Bibeviwi Oct 14 '19 at 09:01
  • 2
    @Bibeviwi you'd declare `template struct Problem`, and use `std::vector const &` as the parameter of the single `evaluate` function. This enables your user to instanciate a `Problem` for their specific type. – Quentin Oct 14 '19 at 09:04
  • @WillEnsaba same thing. `const` applies to the left, except when there's nothing on the left. – Quentin Oct 14 '19 at 12:43

2 Answers2

0

Would something like this do?

#include <memory>
#include <iostream>
#include <vector>

class Problem {
public:
    virtual double evaluate() = 0;
};

class MyProblem : public Problem {
public:
    MyProblem(const std::vector<float>& parameters) : mParameters(parameters) {}
    double evaluate() override {
        // Do evaluation based on mParameters
        return 47.11;
    }

private:
    const std::vector<float>& mParameters;
};


int main() {
    std::vector<float> v = {1.0f, 2.0f};

    std::unique_ptr<Problem> p{new MyProblem(v)};
    std::cout << p->evaluate() << '\n';  // Calls MyProblem::evaluate()

    return 0;
}
Pibben
  • 1,876
  • 14
  • 28
0

Based on @Quentin comment and your details I would say that you could first declare Problem as a class template

#include <vector>
#include <typeinfo>
#include <iostream>

using namespace std;

template<class T>
class Problem
{
public:
    Problem() {
        if(typeid(T) == typeid(double)){
            cout << "The problem is of type double" << endl;
        }
    }

    virtual double evaluate(const vector<T> &decisionVariables) = 0;
};

Then you can inherit from it and override the evaluate function based on your needs. Since you mentioned Ackley Function, I implemented an AckleyFunction which inherits from Problem with type double

#include "problem.h"
#include "math.h"

using namespace std;

class AckleyFunction : public Problem<double>
{
public:
    AckleyFunction() {}

    double evaluate(const vector<double> &decisionVariables) override {
        const double x = decisionVariables[0];
        const double y = decisionVariables[1];
        return -20 * exp(-0.2 * sqrt(0.5 * (pow(x, 2) + pow(y, 2)))) - exp(0.5 * (cos(2 * M_PI * x) + cos(2 * M_PI * y))) + exp(1) + 20;
    }
};

The global minimum for the Ackley function is x = 0, and y = 0. You can see that bellow in the main.cpp

#include <ackleyfunction.h>
#include <memory>

using namespace std;

int main(int argc, char *argv[])
{
    shared_ptr<Problem<double>> prob(new AckleyFunction());
    vector<double> decisionVariables = {5.1, 3.3};
    cout << "Value at coordinates (5.1, 3.3): " << prob->evaluate(decisionVariables) << endl;

    decisionVariables = {0., 0.};
    cout << "Value at coordinates (0.0, 0.0): "  << prob->evaluate(decisionVariables) << endl;
}

Output:

The problem is of type double
Value at coordinates (5.1, 3.3): 12.9631
Value at coordinates (0.0, 0.0): 0
WillEnsaba
  • 756
  • 1
  • 8
  • 23