Xpress Julia API has bug with fixing variables

Fixing variables does not seems to be working with the Xpress solver. I used the example below (which was posted by someone on this forum) to create this MWE.

I fix one of the variables as zero but it seems like JuMP is not passing it to the Xpress solver as you will see from the results. Running the same example with HiGHS works.

This seems to happen when variables are binary.

Is this a bug in Xpress.jl? Is there a quick fix for it?

using JuMP, Xpress, HiGHS

function xpress_error(;solver=Xpress)

    profit = [5, 3, 2, 7, 4]
    weight = [2, 8, 4, 2, 5]
    capacity = 10
    model = Model()
    @variable(model, x[1:5], Bin)
    @objective(model, Max, profit' * x)
    @constraint(model, weight' * x <= capacity)
    fix.(x[5], 0; force=true)

    set_optimizer(model, solver.Optimizer)
    print(model)
    optimize!(model)
    value.(x)
end

xpress_error(;solver = Xpress)

Xpress output

Max 5 x[1] + 3 x[2] + 2 x[3] + 7 x[4] + 4 x[5]
Subject to
 2 x[1] + 8 x[2] + 4 x[3] + 2 x[4] + 5 x[5] <= 10.0
 x[5] == 0.0
 x[1] binary
 x[2] binary
 x[3] binary
 x[4] binary
 x[5] binary
FICO Xpress v8.13.3, Hyper, solve started 21:57:58, Jun 16, 2022
Heap usage: 75KB (peak 75KB, 565KB system)
Maximizing MILP  using up to 8 threads, with these control settings:
OUTPUTLOG = 1
MPSNAMELENGTH = 64
CALLBACKFROMMASTERTHREAD = 1
Original problem has:
         1 rows            5 cols            5 elements         5 globals
Presolved problem has:
         1 rows            5 cols            5 elements         5 globals
Presolve finished in 0 seconds
Heap usage: 101KB (peak 114KB, 567KB system)

Coefficient range                    original                 solved
  Coefficients   [min,max] : [ 2.00e+00,  8.00e+00] / [ 2.50e-01,  1.00e+00]
  RHS and bounds [min,max] : [ 1.00e+00,  1.00e+01] / [ 1.00e+00,  1.25e+00]
  Objective      [min,max] : [ 2.00e+00,  7.00e+00] / [ 2.00e+00,  7.00e+00]
Autoscaling applied standard scaling

Will try to keep branch and bound tree memory usage below 4.2GB
 *** Solution found:      .000000   Time:   0    Heuristic: T ***
 *** Solution found:    16.000000   Time:   0    Heuristic: e ***
Starting concurrent solve with dual (1 thread)

 Concurrent-Solve,   0s
            Dual
    objective   dual inf
 D  16.500000   .0000000
-------- cutoff --------
Concurrent statistics:
      Dual: 1 simplex iterations, 0.00s
Problem is cut off
 *** Search completed ***
Uncrunching matrix
Final MIP objective                   : 1.600000000000000e+01
Final MIP bound                       : 1.600000000000000e+01
  Solution time / primaldual integral :         0s/ 70.444893%
  Number of solutions found / nodes   :         2 /         0
  Max primal violation      (abs/rel) :       0.0 /       0.0
  Max integer violation     (abs    ) :       0.0
5-element Vector{Float64}:
 1.0
 0.0
 0.0
 1.0
 1.0

HiGHS output

xpress_error(;solver = HiGHS)

Max 5 x[1] + 3 x[2] + 2 x[3] + 7 x[4] + 4 x[5]
Subject to
 2 x[1] + 8 x[2] + 4 x[3] + 2 x[4] + 5 x[5] <= 10.0
 x[5] == 0.0
 x[1] binary
 x[2] binary
 x[3] binary
 x[4] binary
 x[5] binary
Presolving model
1 rows, 4 cols, 4 nonzeros
1 rows, 4 cols, 4 nonzeros
Objective function is integral with scale 1

Solving MIP model with:
   1 rows
   4 cols (4 binary, 0 integer, 0 implied int., 0 continuous)
   4 nonzeros

( 0.0s) Starting symmetry detection
( 0.0s) No symmetry present

        Nodes      |    B&B Tree     |            Objective Bounds              |  Dynamic Constraints |       Work
     Proc. InQueue |  Leaves   Expl. | BestBound       BestSol              Gap |   Cuts   InLp Confl. | LpIters     Time

         0       0         0   0.00%   15              -inf                 inf        0      0      0         0     0.0s

Solving report
  Status            Optimal
  Primal bound      14
  Dual bound        14
  Gap               0% (tolerance: 0.01%)
  Solution status   feasible
                    14 (objective)
                    0 (bound viol.)
                    0 (int. viol.)
                    0 (row viol.)
  Timing            0.02 (total)
                    0.00 (presolve)
                    0.00 (postsolve)
  Nodes             1
  LP iterations     0 (total)
                    0 (strong br.)
                    0 (separation)
                    0 (heuristics)
5-element Vector{Float64}:
 1.0
 0.0
 1.0
 1.0
 0.0
1 Like

I don’t have Xpress so I can’t test this, but can you try:

model = Model(Xpress.Optimizer)
@variable(model, x, Bin)
@objective(model, Max, x)
fix(x, 0; force = true)
optimize!(model)
value(x)

Thank you. I have shown the outputs below for your example. Also tried setting upper and lower bounds to zero but it doesn’t work either.


julia> model = Model(Xpress.Optimizer)
A JuMP Model
Feasibility problem with:
Variables: 0
Model mode: AUTOMATIC
CachingOptimizer state: EMPTY_OPTIMIZER
Solver name: Xpress

julia> @variable(model, x, Bin)
x

julia> @objective(model, Max, x)
x

julia> fix(x, 0; force = true)

julia> optimize!(model)
FICO Xpress v8.13.3, Hyper, solve started 0:09:54, Jun 17, 2022
Heap usage: 74KB (peak 74KB, 360KB system)
Maximizing MILP  using up to 8 threads, with these control settings:
OUTPUTLOG = 1
MPSNAMELENGTH = 64
CALLBACKFROMMASTERTHREAD = 1
Original problem has:
         0 rows            1 cols            0 elements         1 globals
Presolved problem has:
         0 rows            1 cols            0 elements         1 globals
Presolve finished in 0 seconds
Heap usage: 75KB (peak 89KB, 362KB system)

Coefficient range                    original                 solved
  Coefficients   [min,max] : [      0.0,       0.0] / [      0.0,       0.0]
  RHS and bounds [min,max] : [ 1.00e+00,  1.00e+00] / [ 1.00e+00,  1.00e+00]
  Objective      [min,max] : [ 1.00e+00,  1.00e+00] / [ 1.00e+00,  1.00e+00]
Autoscaling applied standard scaling

Will try to keep branch and bound tree memory usage below 10.7GB
 *** Solution found:      .000000   Time:   0    Heuristic: T ***
 *** Solution found:     1.000000   Time:   0    Heuristic: T ***
STOPPING - MIPRELSTOP target reached (MIPRELSTOP=0.0001  gap=-0).
 *** Search completed ***
Uncrunching matrix
Final MIP objective                   : 1.000000000000000e+00
Final MIP bound                       : 1.000000000000000e+00
  Solution time / primaldual integral :         0s/ 92.741939%
  Number of solutions found / nodes   :         2 /         0
  Max primal violation      (abs/rel) :       0.0 /       0.0
  Max integer violation     (abs    ) :       0.0

julia> value(x)
1.0
1 Like

That looks like a bug in Xpress, not reflecting bounds on binary variables. Can you open an issue here? Issues · jump-dev/Xpress.jl · GitHub

Instead of Bin, I’d use:

@variable(model, 0 <= x <= 1, Int)

This is a bug in the MOI within Xpress.jl. In the Xpress library, calling XPRSchgcoltype to make a variable into a binary variable resets the bounds of the variable to 0 and 1. What is happening here is that the function XPRSchgbounds is called first, to set the upper bound of the variable to 0, and the call to XPRSchgcoltype comes afterwards, which resets the bounds again. The MOI should be updated to re-apply the variable bounds after calling XPRSchgcoltype.

2 Likes

We have tests for this in MOI, so not sure how this one slipped through. I opened an issue:

https://github.com/jump-dev/Xpress.jl/issues/171

1 Like