0
$\begingroup$

I've been working on implementing Branch-and-Benders Cut using CPLEX version 20.1 with the C++ API, but I'm encountering some difficulties. I've followed the example provided by CPLEX, specifically ilobendersatsp.cpp, and have also looked through various resources online, including past questions on this platform, but I'm still struggling to get my code to work.

The problem I'm trying to solve is relatively simple, aimed at testing out Benders'. I've structured my code with a Main.cpp file where I define the problem and callbacks, and I have separate files for the CutClass and the SubProblem function. I've verified that these components are working correctly as they were initially designed for iterative Benders' decomposition, which I've successfully implemented.

Currently, my code compiles without errors, but it fails to solve the master problem as expected. Upon debugging, I've found that the feasibility cut in the first iteration is generated correctly, but the values of the master problem solution don't change as they should.

Here's the code of the Main.cpp file:

#include "Header.h"
#include <ilcplex/ilocplex.h>

ILOSTLBEGIN

// Declare these variables globally so they can be used in the callback
IloEnv env;  
IloNumVar Eta;
IloIntVarArray MP_X;
vector<Cut> Cuts;
int* Xs;

// Callback function to generate Benders cuts
class MyBranchCallback : public IloCplex::LazyConstraintCallbackI {
public:
    MyBranchCallback(IloEnv& env, int* Xs, vector<Cut>& Cuts) : IloCplex::LazyConstraintCallbackI(env), Xs(Xs), Cuts(Cuts) {}

    [[nodiscard]] IloCplex::CallbackI* duplicateCallback() const override {
        return new(env) MyBranchCallback{ *this };
    }

    // Implement the main() function
    void main() override {
        try {
            // Save the current solution of the MP in the Xs vector
            for (int i = 0; i < 3; i++) {
                Xs[i] = getValue(MP_X[i]);
                std::cout << "Xs[" << i << "]: " << Xs[i] << std::endl;
            }

            // Solve the subproblem with current Xs vector, store dual coefficients in the Cuts vector
            double SP_obj = SubProblem(Xs, Cuts);

            // Generate Benders cuts using the latest cut
            if (Cuts[Cuts.size() - 1].add_optimality_cut) {
                IloExpr exp(env);
                exp += -3 * MP_X[0] - 2 * MP_X[1] + 4 * MP_X[2] + Cuts[Cuts.size() - 1].Us[0] * (-4 + 2 * MP_X[0] - 4 * MP_X[1] + MP_X[2]) + Cuts[Cuts.size() - 1].Us[1] * (2 + MP_X[0] + 2 * MP_X[1] - 4 * MP_X[2]);
                add(exp <= Eta);
                exp.end();
            }

            if (Cuts[Cuts.size() - 1].add_feasibility_cut) {
                IloExpr exp2(env);
                exp2 += Cuts[Cuts.size() - 1].Vs[0] * (-4 + 2 * MP_X[0] - 4 * MP_X[1] + MP_X[2]) + Cuts[Cuts.size() - 1].Vs[1] * (2 + MP_X[0] + 2 * MP_X[1] - 4 * MP_X[2]);
                add(exp2 >= 0);
                exp2.end();
            }
        }
        catch (IloException& e) {
            cerr << "IloException: " << e.getMessage() << endl;
        }
        catch (...) {
            cerr << "Unknown exception caught" << endl;
        }
    }

private:
    int* Xs;
    vector<Cut>& Cuts;
};

int main() {
    try {
        // Initialize environment and CPLEX model
        env = IloEnv();
        IloModel ModelMP(env);
        Eta = IloNumVar(env, -IloInfinity, IloInfinity, ILOFLOAT);
        MP_X = IloIntVarArray(env, 3, 0, IloIntMax);
        ModelMP.add(IloMaximize(env, Eta));

        // Initialize Xs vector (with zeros)
        Xs = new int[3];
        for (int i = 0; i < 3; i++) {
            Xs[i] = 1;
        }

        // Callback object with Xs and Cuts arguments
        MyBranchCallback mycb(env, Xs, Cuts);

        // Add constraints that only involve integer variables to the MP
        for (int i = 0; i < MP_X.getSize(); i++) {
            ModelMP.add(MP_X[i] <= 6);
        }

        // Create the IloCplex object and use the callback
        IloCplex cplex(ModelMP);
        cplex.setParam(IloCplex::Param::Preprocessing::Presolve, IloFalse);
        cplex.use(&mycb);

        // Solve the master problem
        if (!cplex.solve()) {
            cerr << "Failed to optimize the Master Problem!!!" << endl;
            throw(-1);
        }
        double MP_obj = cplex.getObjValue();

        // Free memory and finish
        delete[] Xs;
        env.end();
        return 0;
    }
    catch (IloException& e) {
        cerr << "IloException: " << e.getMessage() << endl;
        env.end();
    }
    catch (...) {
        cerr << "Unknown exception caught" << endl;
        env.end();
    }
} 

Did I implement the callback class correctly?

If further code or information is necessary, I will gladly provide that.

$\endgroup$

0

Your Answer

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