6.2. Callback

MindOpt adopts the classical branch and bound method to solve MIP problems. MindOpt provides users with callback functions to track and modify the optimization process of MIP problems. Users can use callbacks to modify the behavior of the MIP optimizer, including:

  • Add cutting planes to cut off branches that will not lead to the optimal solutions.

  • Modify the branch selection strategy of MindOpt to control node branching methods and traversal order.

  • Add feasible solutions (e.g., solutions obtained through self-implemented heuristic algorithms). A good feasible solution can improve the solving efficiency of MindOpt .

Note

Users need to ensure that the cutting planes added through the callback function must truly be cutting planes. If the node containing the optimal solutions is cut off, it may prevent MindOpt from finding an optimal solution.

6.2.1. Callback API

6.2.2. Callback Code

When a user callback function is called, the where argument informs the user about the optimizer status. Possible where values are:

Where

Value

The MIP optimizer Status

MIPSTART

3

In the initialization phase

MIPSOL

4

Found a new incumbent

MIPNODE

5

Currently exploring a node

When the cbGet is called in a user callback function, an integer argument named what is needed. Allowable what values are:

What

Value

Result type

Result length

Result description

PRE_NUMVARS

200

int

The number of variables in the presolved model

PRE_NUMCONSTRS

201

int

The number of constraints in the presolved model

PRE_NUMNZS

202

int

The number of nonzero elements in the presolved model

MIP_OBJBST

300

double

Current best objective

MIP_OBJBND

301

double

Current best objective bound

MIP_RELVAL

302

double

Current objective of the relaxation model

MIP_NODCNT

306

int

Current explored node count

MIP_SOLCNT

307

int

Current count of feasible solutions found

MIP_CUTCNT

308

int

Current count of cutting planes applied

MIP_NODLFT

309

int

Current unexplored node count

MIP_NODEID

310

int

ID of current node

MIP_DEPTH

311

int

Depth of current node

MIP_PHASE

312

int

Current phase in the MIP solution process (0:no solution, 2:far from optimal, 3:near to optimal)

MIP_SOL

316

double array

MODEL_NUMVARS

Current best solution

MIP_REL

317

double array

MODEL_NUMVARS

Current relaxation solution

Note

When developing with MindOpt C SDK, for write operations (MDOcbcut()MDOcbbranch()MDOcbsolution()), the variable indices to be passed should be the indices in the presolved model rather than the original model.

6.2.3. Callback SDK

  • C SDK

    /**
     * The model argument is the original model.
     * The cbdata argument is the callback context for read or write operations.
     * The where argument indicates where in the optimization process the callback function is being called.
     * The userdata argument is the user-defined context.
     * The callback function should return zero by default.
     */
    int callbackfn(const MDOmodel* model, void* cbdata, int where, const void* usrdata);
    
  • C++ SDK

    /**
     * The model argument is the original model.
     * The cbdata argument is the callback context for read or write operations.
     * The where argument indicates where in the optimization process the callback function is being called.
     * The userdata argument is the user-defined context.
     * The callback function should return zero by default.
     */
    int cbfn(const MDOmodel* model, void* cbdata, int where, const void* usrdata);
    
  • Java SDK

    /**
     * The model argument is the original model.
     * The cbdata argument is the callback context for read or write operations.
     * The where argument indicates where in the optimization process the callback function is being called.
     * The userdata argument is the user-defined context.
     * The callback function should return zero by default.
     */
    int java_callback(const MDOmodel* model, void* cbdata, int where, const void* usrdata)
    
  • Python SDK

    # The model argument is the presolved model.
    # The where argument indicates the current phase in the optimization process.
    # The return value is ignored.
    def cbfn(model, where)
    

6.2.4. Example

The following example shows you how to use callback in the Python API of MindOpt.

from mindoptpy import *

m = Model()
m.modelsense = MDO.MAXIMIZE

x = m.addMVar((3,), obj=[20, 6, 8], vtype=['C', 'I', 'I'])

A = [
    [0.8, 0.2, 0.3],
    [0.4, 0.3, 0],
    [0.2, 0, 0.1]
]

b = [4, 2, 1]

c = m.addMConstr(A, x, '<', b)

def callback(model, where):
    where_names = {
        3: "MIPSTART",
        4: "MIPSOL",
        5: "MIPNODE"
    }

    print("where = {}".format(where_names[where]))

    # Count call times
    model._calls += 1

    # When using the Python SDK, the model passed to the callback is a presolved model. Note that the C SDK uses the original model.
    # Print the constraint matrix of the presolved model here. The getA() function returns a scipy.sparse.csc_matrix.
    # The constraint matrix returned by getA() is a reference, and any modifications to the constraint matrix should not be allowed as it may lead to unforeseen issues.
    print(model.getA())

    cur_sols = model.cbGetSolution(model.getVars())

    # Print the current best solution
    print(cur_sols)

    rel_sols = model.cbGetNodeRel(model.getVars())

    # Print the current relaxation solution
    print(rel_sols)


# Member variables starting with "_" can be added to the model.
# The member variable "_calls" in this context is used to show the passing of the callback context.
m._calls = 0

# Pass the callback function to the solver
m.optimize(callback)

print("Number of calls: {}".format(m._calls))

# Print the optimization result
if m.status == MDO.OPTIMAL:
    print("Objective value: {}".format(m.objval))
    print("Solution")
    sol = x.X
    for i in range(len(sol)):
        print("  x[{}] = {}".format(i, sol[i]))

else:
    print("No feasible solution found so far")