Gather Optimal Tableau Information using CPLEX.jl

Hey! I’m currently working on implementing fractional Gomory cuts, and I need to know the optimal simplex tableau in order to obtain these constraints.

In this post on Simplex tableau, they suggested using ccall and mentioned the following code: ccall((:CPXbinvarow,CPLEX.libcplex),Cint,(Ptr{Void},Ptr{Void},Cint,Ptr{Cdouble}),ci.env.ptr, ci.lp, j,row)

I tried using this code, but the row results are only 1 or 0.

To better understand the result, I started with a small problem. Here’s the code:

# Create a model with the CPLEX solver

model = Model(CPLEX.Optimizer)

# Define variables as continuous (for the linear relaxation)

@variable(model, x1 >= 0)

@variable(model, x2 >= 0)

# Define constraints

@constraint(model, x1 + x2 <= 7)

@constraint(model, 2*x1 <= 11)

@constraint(model, 2*x2 <= 7)

# Define the objective function

@objective(model, Max, x1 + 2*x2)

I attempted to retrieve the tableau like this:

# Solve the model

# Retrieve the number of constraints
num_const = MOI.get(model, MOI.NumberOfConstraints{MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}}())

# Retrieve the number of variables plus slack variables
num_vars = MOI.get(model, MOI.NumberOfVariables()) + num_const

# Initialize the tableau
tableau = zeros(num_const, num_vars)

for j in 0:num_const-1
    tableau[j+1,:] = getrow(j, model)

The getrow function is defined as follows:

function getrow(j, model)
    ci = backend(model).optimizer.model
    num_vars = MOI.get(model, MOI.NumberOfVariables()) + MOI.get(model, MOI.NumberOfConstraints{MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}}())
    row = zeros(num_vars)
    status = ccall((:CPXbinvarow, CPLEX.libcplex), Cint, 
                   (Ptr{Nothing}, Ptr{Nothing}, Cint, Ptr{Cdouble}), 
                   ci.env.ptr, ci.lp, j, row)
    if status != 0
        error("CPXbinvarow failed, return code $status.")
    return row

In a video I watched, I learned that the optimal tableau should look like this:

Can you please help me with this?

Did you want CPXbinvrow instead? Here’s how I would call it:

using JuMP, CPLEX
model = direct_model(CPLEX.Optimizer())
@variable(model, x1 >= 0)
@variable(model, x2 >= 0)
@constraint(model, x1 + x2 <= 7)
@constraint(model, 2*x1 <= 11)
@constraint(model, 2*x2 <= 7)
@objective(model, Max, x1 + 2*x2)
num_const = num_constraints(model, AffExpr, MOI.LessThan{Float64})
num_vars = num_variables(model) + num_const
tableau = zeros(num_const, num_vars)
cpx = backend(model)
data = zeros(num_vars)
for j in 1:num_const
    status = CPLEX.CPXbinvrow(cpx.env, cpx.lp, Cint(j - 1), data)
    @assert status == 0
    tableau[j, :] .= data

Here are the docs: IBM Documentation

If I understood correctly, CPXbinvrow is used to gather the inverse basis, while CPXbinvarow is used for the tableau. Could you please confirm if my understanding is accurate? Thank you very much for your quick response as always, @odow.

I wanted to update you and let you know that I have figured out what was causing the issue. Thanks to @odow for clarifying the functions. As I initially mentioned, I’ve been using the CPXbinvarow to gather rows from the tableau. The error occurred because I hadn’t incorporated the slack variables into the model. Once I added these slack variables, the results from CPXbinvarow matched up correctly.

1 Like