Error using CPXcallbackgetrelaxationpoint at CPLEX.jl solver specifc callback

Hey guys, you know how I get this right? I’m getting an error on “CPXcallbackgetrelaxationpoint” call on CPLEX solver-specific callback.

Here’s a example:

using JuMP, CPLEX, Test


cb_calls = Clong[]
function my_callback_function(cb_data::CPLEX.CallbackContext, context_id::Clong)
    push!(cb_calls, context_id)

    # You can select where the callback is run: https://www.ibm.com/docs/en/icos/12.9.0?topic=manual-callback-context
    if context_id == CPX_CALLBACKCONTEXT_BRANCHING
        # Get the id of the thread on which the callback is invoked.
        valueP = Ref{CPXINT}()
        status = CPXcallbackgetinfoint(cb_data, CPXCALLBACKINFO_THREADID, valueP)
        @info "The id of the thread is: $(valueP[])"

        if Bool(status) 
            @error "CPXcallbackgetinfoint failed."
        end 

        # For sake of illustration prune every node that has a depth larger than 1000.
        depth = Ref{CPXLONG}()
        status = CPXcallbackgetinfolong(cb_data, CPXCALLBACKINFO_NODEDEPTH, depth)

        if Bool(status) 
            @error "CPXcallbackgetinfolong failed."
        end 

        if depth[] > 1000
            @info "Pruning node with depth $(depth[])"
            status = CPXcallbackprunenode(cb_data)
            if Bool(status) 
                @error "CPXcallbackprunenode failed."
            end
        end

        # Get the solution status of the current relaxation.
        lpstat = Ref{Cint}()
        status = CPXcallbackgetrelaxationstatus(cb_data, lpstat, 0)

        if Bool(status) 
            @error "CPXcallbackgetrelaxationstatus failed."
        end
        println("The solution status of the current relaxation is: $(lpstat[])")

        # If the relaxation is infeasible, then prune the node.
        if lpstat[] == CPX_STAT_INFEASIBLE
            @info "Pruning node because of infeasibility."
            status = CPXcallbackprunenode(cb_data)
            if Bool(status) 
                @error "CPXcallbackprunenode failed."
            end
        end
        
        # Only branch if the current node relaxation could be solved to optimality.
        if (lpstat[] == CPX_STAT_OPTIMAL) || (lpstat[] == CPX_STAT_OPTIMAL_INFEAS)
            # Relaxation is optimal. Find the integer variable that is most fractional.
            println("Branching")
            obj_p = Ref{Cdouble}()
            status = CPXcallbackgetrelaxationpoint(cb_data, x, 0, 1, obj_p)
            
            if Bool(status) 
                @error "CPXcallbackgetrelaxationpoint failed."
            else 
                @info "Relaxation point: $(x[])"
                @info "Relaxation objective: $(obj_p[])"
            end
        end 
    end 
end

N = 50

# Modelo 
model = direct_model(CPLEX.Optimizer())

MOI.set(model, MOI.NumberOfThreads(), 1)
set_optimizer_attribute(model, "CPXPARAM_MIP_Limits_Nodes", 10)
set_optimizer_attribute(model, "CPXPARAM_MIP_Display", 2)

#deactivate general purpose cuts
set_optimizer_attribute(model, "CPXPARAM_MIP_Cuts_BQP", -1)
set_optimizer_attribute(model, "CPXPARAM_MIP_Cuts_Cliques", -1)
set_optimizer_attribute(model, "CPXPARAM_MIP_Cuts_Covers", -1)
set_optimizer_attribute(model, "CPXPARAM_MIP_Cuts_Disjunctive", -1)
set_optimizer_attribute(model, "CPXPARAM_MIP_Cuts_FlowCovers", -1)
set_optimizer_attribute(model, "CPXPARAM_MIP_Cuts_Gomory", -1)
set_optimizer_attribute(model, "CPXPARAM_MIP_Cuts_GUBCovers", -1)
set_optimizer_attribute(model, "CPXPARAM_MIP_Cuts_Implied", -1)
set_optimizer_attribute(model, "CPXPARAM_MIP_Cuts_LiftProj", -1)
set_optimizer_attribute(model, "CPXPARAM_MIP_Cuts_LocalImplied", -1)
set_optimizer_attribute(model, "CPXPARAM_MIP_Cuts_MCFCut", -1)
set_optimizer_attribute(model, "CPXPARAM_MIP_Cuts_MIRCut", -1)
set_optimizer_attribute(model, "CPXPARAM_MIP_Cuts_PathCut", -1)
set_optimizer_attribute(model, "CPXPARAM_MIP_Cuts_RLT", -1)
set_optimizer_attribute(model, "CPXPARAM_MIP_Cuts_ZeroHalfCut", -1)
set_optimizer_attribute(model, "CPXPARAM_MIP_Limits_EachCutLimit", CPX_OFF)
set_optimizer_attribute(model, "CPXPARAM_MIP_Strategy_CallbackReducedLP", CPX_OFF)

#deactivate preprocessing
set_optimizer_attribute(model, "CPXPARAM_Preprocessing_Presolve", CPX_OFF)
set_optimizer_attribute(model, "CPXPARAM_Preprocessing_Relax", CPX_OFF)
set_optimizer_attribute(model, "CPXPARAM_Preprocessing_RepeatPresolve", CPX_OFF)
set_optimizer_attribute(model, "CPXPARAM_MIP_Strategy_PresolveNode", -1)
set_optimizer_attribute(model, "CPXPARAM_MIP_Strategy_Probe", -1)

#deactivate  heuristics
set_optimizer_attribute(model, "CPXPARAM_MIP_Strategy_HeuristicFreq", -1)
set_optimizer_attribute(model, "CPXPARAM_MIP_Strategy_RINSHeur", -1)
set_optimizer_attribute(model, "CPXPARAM_MIP_Strategy_FPHeur", -1)
set_optimizer_attribute(model, "CPXPARAM_MIP_Strategy_LBHeur", CPX_OFF)

@variable(model, x[i=1:N, j=1:N], Bin)

@objective(model, Max, sum(x[i,j] for i in 1:N, j in 1:N))

@constraint(model, horizontal[j in 1:N], sum(x[i,j] for i in 1:N) <= 1)

@constraint(model, vertical[i in 1:N], sum(x[i,j] for j in 1:N) <= 1)

@constraint(model, diag_pos[k in -(N-2):(N-2)], sum(x[i,j] for i in 1:N, j in 1:N if (i-j) == k) <= 1)

@constraint(model, diag_neg[k in 3:2*(N-1)], sum(x[i,j] for i in 1:N, j in 1:N if (i + j) == k) <= 1)


MOI.set(model, CPLEX.CallbackFunction(), my_callback_function)
optimize!(model)

status = CPXcallbackgetrelaxationpoint(cb_data, x, 0, 1, obj_p)
@info “Relaxation point: $(x)”

There are a few problems here:

  • x is not defined yet. You should typically write your callback function after creating the model, etc
  • x gets defined later as a Matrix{VariableRef}, whereas CPLEX needs to be passed a Vector{Float64}.
  • x[] is the syntax for Ref variables, not vectors or matrices.

You could instead pass something like this (although I didn’t try it, so there might be a mistake):

    if (lpstat[] == CPX_STAT_OPTIMAL) || (lpstat[] == CPX_STAT_OPTIMAL_INFEAS)
        # Relaxation is optimal. Find the integer variable that is most fractional.
        println("Branching")
        obj_p = Ref{Cdouble}()
        x_val = Vector{Cdouble}(undef, N^2)
        status = CPXcallbackgetrelaxationpoint(cb_data, x_val, 0, N^2 - 1, obj_p)
        if Bool(status) 
            @error "CPXcallbackgetrelaxationpoint failed."
        else 
            @info "Relaxation point: $(x_val)"
            @info "Relaxation objective: $(obj_p[])"
        end
    end

It’s working! As always, you are very thoughtful. Thanks @odow. In my thesis you will certainly be in the acknowledgments. :slight_smile:

2 Likes