0

I'm trying to write a numeric optimizer in C++ that allows the user to specify what type of input they want to use. The inputs all have the same "API" style, where all classes have methods of the same name. Example (only showing part of the code since the full detail doesn't matter):

OLS::OLS(int num_data_cols, float learning_rate, int num_epochs){

    learningRate = learning_rate;
    numEpochs = num_epochs;
    numDataCols = num_data_cols;

    // Generate Random Beta Start point
    for (int i=0; i<numDataCols; i++){
        beta.push_back( float(rand()%10)/float(rand()%10) );
    }
    intercept = float(rand()%10)/float(rand()%10);
}

void OLS::updateParameters(float target, vector<float> data)
{
    float prediction = makePrediction(data);
    float error = getError(target, prediction);
    for (int i=0; i<numDataCols; i++){
        beta.at(i) = beta.at(i) - learningRate*error*data.at(i);
    }
    intercept = intercept - learningRate*error;
}
...

There's another class called Hinge that has all the same methods. I want the user to be able to specify via command line which of these classes to use in the solver.

However, I'm unsure how to specify the variable that stores the "class to optimize on" object. At present I have this in as another class that wraps around the optimizers:

class GradientDescent {

private:

   ...
   ...
   OLS* cost_function;
   ...
   ...

public:

   GradientDescent(OLS objectHere);
   GradientDescent(Hinge objectHere);
   ...
   ...
}

You can see two things - one I've overloaded to allow the user to choose which type of object to use. However, the cost_function is pre-specified as an OLS object. The behavior I'd like to have is cost_function is specified as a class object, but I don't want to pre-specify that it's OLS. I want to allow the user to tell me which of these optimizers they want, and then store that object and its substructure under the name cost_function.

How do I forward declare cost_function such that it will accept either a OLS or a Hinge object in the constructor for the class that uses the optimization the user requests? I have a method for using user input to choose which optimizer, I'm not worried about that, I just need to know how to handle the multiple possible types.

4
  • What exactly do you mean by " is specified as a class object?" No such thing as a "class object." Commented Aug 23, 2018 at 21:00
  • Hey @3Dave. I don't really know how to describe it otherwise. I want to tell the GradientDescent class to expect an object that's some other class, whether it be an OLS class or a Hinge class. I really just need some placeholder that can switch types once I know what the user has requested - but I don't know how to tell C++ to expect something when I don't know exactly which class the user will request. Commented Aug 23, 2018 at 21:06
  • Are you familiar with templates? Commented Aug 23, 2018 at 21:25
  • @txtechhelp I'm not familiar with templates, sorry. Commented Aug 23, 2018 at 21:49

1 Answer 1

1

Isn't this a case for virtual inheritance?

#include <vector>
#include <memory>

// engine concept
struct Engine
{
    virtual void updateParameters(float target, std::vector<float> data) = 0;

    virtual ~Engine() = default;
};

struct OLS: Engine
{
    virtual void updateParameters(float target, std::vector<float> data) override;    
};

struct Hinge : Engine
{
    virtual void updateParameters(float target, std::vector<float> data) override;    
};



struct Solver
{
    void useOLS() {
        engine_ = std::make_unique<OLS>();
    }

    void useHinge() {
        engine_ = std::make_unique<Hinge>();
    }

    void updateParameters(float target, std::vector<float> data)
    {
        engine_->updateParameters(target, data);
    }


    std::unique_ptr<Engine> engine_;
};

Another option would be to use boost::variant to hold the engine (cost function) and use a visitor to update its parameters.

Sign up to request clarification or add additional context in comments.

2 Comments

This looks like what I think I need. How do I tell the struct OLS where the "correct definition of updateParameters for OLS" is since the methods behave differently? Forgive me, I've not had to use virtual inheritance before (I'm coming back to C++ after several years away and a lot of the "best practices" seem to have changed in the mean time)
@Zach as you were doing before. You'd provide a definition of OLS::updateParameters and a definition of Hinge::updateParameters().

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.