import JuMP, Gurobi
NLP = JuMP.Model(Gurobi.Optimizer);
JuMP.@variable(NLP, x);
JuMP.@objective(NLP, Min, (x + 1) * x * (x - 1));
JuMP.optimize!(NLP);
Gurobi Optimizer version 12.0.1 build v12.0.1rc0 (win64 - Windows 11.0 (26100.2))
CPU model: 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz, instruction set [SSE2|AVX|AVX2|AVX512]
Thread count: 4 physical cores, 8 logical processors, using up to 8 threads
Optimize a model with 0 rows, 3 columns and 0 nonzeros
Model fingerprint: 0x60c267e2
Model has 1 general nonlinear constraint (2 nonlinear terms)
Variable types: 3 continuous, 0 integer (0 binary)
Coefficient statistics:
Matrix range [0e+00, 0e+00]
Objective range [1e+00, 1e+00]
Bounds range [0e+00, 0e+00]
RHS range [0e+00, 0e+00]
Found heuristic solution: objective 0.0000000
Presolve model has 1 nlconstr
Added 4 variables to disaggregate expressions.
Presolve time: 0.00s
Presolved: 10 rows, 8 columns, 22 nonzeros
Presolved model has 2 bilinear constraint(s)
Solving non-convex MIQCP
Variable types: 8 continuous, 0 integer (0 binary)
Found heuristic solution: objective -0.3849002
Root relaxation: unbounded, 1 iterations, 0.00 seconds (0.00 work units)
Nodes | Current Node | Objective Bounds | Work
Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time
0 0 postponed 0 -0.38490 - - - 0s
omit lines....
* 934 43 124 -210.0000000 - - 0.3 0s
H 8396 1056 -627.4375000 -5.369e+14 - 0.2 0s
omit lines....
4747770 24 -5.369e+14 39299 1 -2.621e+11 -5.369e+14 - 0.0 120s
4762410 24 -5.369e+14 39909 1 -2.621e+11 -5.369e+14 - 0.0 125s
H4763874 24 -1.00000e+18 -1.000e+18 0.00% 0.0 125s
Explored 4765338 nodes (186361 simplex iterations) in 125.93 seconds (11.38 work units)
Thread count was 8 (of 8 available processors)
Solution count 10: -1e+18 -3.74409e+09 -3.44774e+09 ... -2.60131e+09
No other solutions better than -1e+18
Optimal solution found (tolerance 1.00e-04)
Best objective -9.999999999990e+17, best bound -9.999999999990e+17, gap 0.0000%
User-callback calls 9533859, time in user-callback 2.53 sec
The primal objVal is fine, as it monotonically decreases.
But it’s weird to see the ObjBound firstly goes up and later goes down (the last 2 lines of MIP Logging).
Furthermore,
Actually here is a nonconvex QCP reformulation of the above NLP, which can be run much faster. This time the upside is: a warning can be seen in Gurobi’s Logging.
The errors are
the best bound shouldn’t first go up and then go down.
the termination status shouldn’t be OPTIMAL
Please take a look (Since this is nonconvex QCP, I think Gurobi 9 could do it)
julia> import JuMP, Gurobi
julia> ncQCP = JuMP.Model(Gurobi.Optimizer) # non-convex QCP
Set parameter Username
Set parameter LicenseID to value 2602363
Academic license - for non-commercial use only - expires 2025-12-20
A JuMP Model
├ solver: Gurobi
├ objective_sense: FEASIBILITY_SENSE
├ num_variables: 0
├ num_constraints: 0
└ Names registered in the model: none
julia> JuMP.@variable(ncQCP, x)
x
julia> JuMP.@variable(ncQCP, xx)
xx
julia> JuMP.@constraint(ncQCP, xx >= x * x)
-x² + xx >= 0
julia> JuMP.@constraint(ncQCP, xx <= x * x)
-x² + xx <= 0
julia> JuMP.@objective(ncQCP, Min, x * (xx - 1))
x*xx - x
julia> JuMP.optimize!(ncQCP)
Gurobi Optimizer version 12.0.1 build v12.0.1rc0 (win64 - Windows 11.0 (26100.2))
CPU model: 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz, instruction set [SSE2|AVX|AVX2|AVX512]
Thread count: 4 physical cores, 8 logical processors, using up to 8 threads
Optimize a model with 0 rows, 2 columns and 0 nonzeros
Model fingerprint: 0xb0bb3f9e
Model has 1 quadratic objective term
Model has 2 quadratic constraints
Coefficient statistics:
Matrix range [0e+00, 0e+00]
QMatrix range [1e+00, 1e+00]
QLMatrix range [1e+00, 1e+00]
Objective range [1e+00, 1e+00]
QObjective range [2e+00, 2e+00]
Bounds range [0e+00, 0e+00]
RHS range [0e+00, 0e+00]
Continuous model is non-convex -- solving as a MIP
Found heuristic solution: objective 0.0000000
Presolve time: 0.00s
Presolved: 3 rows, 4 columns, 6 nonzeros
Presolved model has 1 quadratic constraint(s)
Presolved model has 2 bilinear constraint(s)
Warning: Model contains variables with very large bounds participating
in product terms.
Presolve was not able to compute smaller bounds for these variables.
Consider bounding these variables or reformulating the model.
Variable types: 4 continuous, 0 integer (0 binary)
Root relaxation: unbounded, 1 iterations, 0.00 seconds (0.00 work units)
Nodes | Current Node | Objective Bounds | Work
Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time
0 0 unbounded 0 0.00000 - - - 0s
0 0 postponed 0 0.00000 - - - 0s
0 0 postponed 0 0.00000 - - - 0s
0 0 postponed 0 0.00000 - - - 0s
0 2 postponed 0 0.00000 - - - 0s
* 1 2 1 -9.99999e+08 - - 4.0 0s
* 4 2 2 -2.82843e+09 - - 2.3 0s
* 7 4 4 -8.00000e+09 - - 2.0 0s
* 21 4 5 -2.26274e+10 - - 1.8 0s
* 23 4 8 -6.40000e+10 - - 1.8 0s
* 45 4 11 -1.81019e+11 - - 1.7 0s
* 99 6 28 -1.81029e+11 - - 1.4 0s
* 119 13 29 -1.81039e+11 - - 1.3 0s
* 140 19 35 -1.81096e+11 - - 1.2 0s
H 158 24 -1.81163e+11 - - 1.1 0s
H 191 42 -1.81288e+11 - - 0.9 0s
* 270 42 69 -1.81423e+11 - - 0.7 0s
* 368 60 71 -1.81442e+11 - - 0.5 0s
* 369 60 72 -1.81452e+11 - - 0.5 0s
* 372 60 73 -1.81461e+11 - - 0.5 0s
* 430 66 74 -1.81471e+11 - - 0.5 0s
* 433 66 75 -1.81481e+11 - - 0.5 0s
* 434 66 76 -1.81490e+11 - - 0.5 0s
* 437 66 77 -1.81500e+11 - - 0.5 0s
* 438 66 78 -1.81509e+11 - - 0.5 0s
* 441 66 79 -1.81519e+11 - - 0.5 0s
* 442 66 80 -1.81529e+11 - - 0.5 0s
* 445 66 81 -1.81538e+11 - - 0.5 0s
* 446 66 82 -1.81548e+11 - - 0.5 0s
H 501 84 -1.81596e+11 - - 0.4 0s
* 527 84 88 -1.81606e+11 - - 0.4 0s
* 530 84 89 -1.81615e+11 - - 0.4 0s
* 531 84 90 -1.81625e+11 - - 0.4 0s
* 534 84 91 -1.81634e+11 - - 0.4 0s
* 535 84 92 -1.81644e+11 - - 0.4 0s
* 538 84 93 -1.81654e+11 - - 0.4 0s
* 539 84 94 -1.81663e+11 - - 0.4 0s
H 602 94 -1.81673e+11 - - 0.4 0s
* 627 94 96 -1.81683e+11 - - 0.4 0s
* 630 94 97 -1.81692e+11 - - 0.4 0s
* 631 94 98 -1.81702e+11 - - 0.4 0s
* 634 94 99 -1.81711e+11 - - 0.4 0s
* 635 94 100 -1.81721e+11 - - 0.4 0s
* 638 94 101 -1.81731e+11 - - 0.4 0s
* 639 94 102 -1.81740e+11 - - 0.4 0s
* 642 94 103 -1.81750e+11 - - 0.4 0s
* 643 94 104 -1.81760e+11 - - 0.4 0s
H 645 94 -1.81769e+11 - - 0.4 0s
* 647 94 106 -1.81779e+11 - - 0.4 0s
* 650 94 107 -1.81788e+11 - - 0.4 0s
* 651 94 108 -1.81798e+11 - - 0.4 0s
* 743 66 109 -1.81808e+11 - - 0.3 0s
* 744 66 110 -1.81817e+11 - - 0.3 0s
* 966 116 151 -1.82212e+11 - - 0.3 0s
* 1563 145 18 -5.12000e+11 -5.369e+14 - 0.2 0s
* 1566 136 19 -1.44815e+12 -5.369e+14 - 0.2 0s
* 1567 129 20 -4.09600e+12 -5.369e+14 - 0.2 0s
* 1569 121 21 -1.15852e+13 -5.369e+14 4534% 0.2 0s
* 1571 115 22 -3.27680e+13 -5.369e+14 1538% 0.2 0s
* 1574 108 24 -2.62144e+14 -5.369e+14 105% 0.2 0s
* 1576 101 25 -7.41455e+14 -7.415e+14 0.00% 0.2 0s
Explored 1579 nodes (341 simplex iterations) in 0.06 seconds (0.00 work units)
Thread count was 8 (of 8 available processors)
Solution count 10: -7.41455e+14 -2.62144e+14 -3.2768e+13 ... -1.81808e+11
No other solutions better than -7.41455e+14
Optimal solution found (tolerance 1.00e-04)
Best objective -7.414552000990e+14, best bound -7.414552000990e+14, gap 0.0000%
User-callback calls 3404, time in user-callback 0.00 sec
julia> JuMP.solution_summary(ncQCP; verbose = true)
* Solver : Gurobi
* Status
Result count : 10
Termination status : OPTIMAL
Message from the solver:
"Model was solved to optimality (subject to tolerances), and an optimal solution is available."
* Candidate solution (result #1)
Primal status : FEASIBLE_POINT
Dual status : NO_SOLUTION
Objective value : -7.41455e+14
Objective bound : -7.41455e+14
Relative gap : 0.00000e+00
Primal solution :
x : -9.05097e+04
xx : 8.19200e+09
* Work counters
Solve time (sec) : 5.99999e-02
Simplex iterations : 341
Barrier iterations : 0
Node count : 1579
I’m very sorry but I find yet another bug of Gurobi.
In the following test case I am essentially Minimize x, where x is free.
But Gurobi reports OPTIMAL
julia> import JuMP, Gurobi
julia> begin
model = JuMP.Model(Gurobi.Optimizer)
JuMP.@variable(model, x)
JuMP.@variable(model, trivial_decision)
JuMP.@constraint(model, trivial_decision >= x * x)
JuMP.@constraint(model, trivial_decision <= x * x)
JuMP.@objective(model, Min, x)
end
julia> JuMP.optimize!(model)
Gurobi Optimizer version 12.0.1 build v12.0.1rc0 (win64 - Windows 11.0 (26100.2))
CPU model: 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz, instruction set [SSE2|AVX|AVX2|AVX512]
Thread count: 4 physical cores, 8 logical processors, using up to 8 threads
Optimize a model with 0 rows, 2 columns and 0 nonzeros
Model fingerprint: 0x862a5994
Model has 2 quadratic constraints
Coefficient statistics:
Matrix range [0e+00, 0e+00]
QMatrix range [1e+00, 1e+00]
QLMatrix range [1e+00, 1e+00]
Objective range [1e+00, 1e+00]
Bounds range [0e+00, 0e+00]
RHS range [0e+00, 0e+00]
Continuous model is non-convex -- solving as a MIP
Found heuristic solution: objective 0.0000000
Presolve time: 0.00s
Presolved: 1 rows, 3 columns, 2 nonzeros
Presolved model has 1 quadratic constraint(s)
Presolved model has 1 bilinear constraint(s)
Warning: Model contains variables with very large bounds participating
in product terms.
Presolve was not able to compute smaller bounds for these variables.
Consider bounding these variables or reformulating the model.
Variable types: 3 continuous, 0 integer (0 binary)
Root relaxation: unbounded, 0 iterations, 0.00 seconds (0.00 work units)
Nodes | Current Node | Objective Bounds | Work
Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time
0 0 unbounded 0 0.00000 - - - 0s
0 0 unbounded 0 0.00000 - - - 0s
0 0 unbounded 0 0.00000 - - - 0s
0 0 unbounded 0 0.00000 - - - 0s
0 0 unbounded 0 0.00000 - - - 0s
0 0 postponed 0 0.00000 - - - 0s
0 0 postponed 0 0.00000 - - - 0s
0 2 postponed 0 0.00000 - - - 0s
* 1298 995 14 -1000000.000 - - 0.0 0s
* 1340 933 34 -1024000.000 - - 0.0 0s
* 1347 889 38 -1447680.982 - - 0.0 0s
* 1348 844 38 -1447695.168 - - 0.0 0s
* 1353 800 40 -1448099.336 - - 0.0 0s
* 1366 755 36 -2048000.000 - - 0.0 0s
* 1369 716 38 -2895659.103 - - 0.0 0s
* 1380 669 38 -4096000.000 -4096000.0 0.00% 0.0 0s
Explored 1383 nodes (45 simplex iterations) in 0.66 seconds (0.25 work units)
Thread count was 8 (of 8 available processors)
Solution count 9: -4.096e+06 -2.89566e+06 -2.048e+06 ... 0
No other solutions better than -4.096e+06
Optimal solution found (tolerance 1.00e-04)
Best objective -4.096000000000e+06, best bound -4.096000000000e+06, gap 0.0000%
User-callback calls 2908, time in user-callback 0.00 sec
julia> JuMP.solution_summary(model; verbose = true)
* Solver : Gurobi
* Status
Result count : 9
Termination status : OPTIMAL
Message from the solver:
"Model was solved to optimality (subject to tolerances), and an optimal solution is available."
* Candidate solution (result #1)
Primal status : FEASIBLE_POINT
Dual status : NO_SOLUTION
Objective value : -4.09600e+06
Objective bound : -4.09600e+06
Relative gap : 0.00000e+00
Primal solution :
trivial_decision : 1.67772e+13
x : -4.09600e+06
* Work counters
Solve time (sec) : 6.59000e-01
Simplex iterations : 45
Barrier iterations : 146215
Node count : 1383
But we may learn from this case that if Gurobi prints Warning, then it may be a sign of potential misfortune. Therefore we have to also strive to eliminate solver’s Warnings to ensure normality, and the expected behavior.