odow
March 13, 2025, 11:04pm
21
We’re open to suggestions for improving the solution summary. How about:
Solution summary
├ solver_name : Gurobi
├ Overall status
│ ├ termination_status : OPTIMAL
│ ├ result_count : 3
│ ├ objective_bound : -3.00000e+00
│ ├ relative_gap : 0.00000e+00
│ └ raw_status
│ └ "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 : -3.00000e+00
│ └ dual_objective_value : -3.00000e+00
└ Work counters
├ solve_time (sec) : 3.03030e-04
├ simplex_iterations : 0
├ barrier_iterations : 0
└ node_count : 0
I would suggest that add a dynamic (3-possibilities) lb and ub hint.
(part of summary are something like):
For a Min-Program:
├ ObjSense: MIN_SENSE
├ termination_status: TIME_LIMIT
├ objective_bound (lb): -3.0
├ Candidate solution (; result = 1)
│ ├ objective_value (ub): -2.0
For a Max-Program
├ ObjSense: MAX_SENSE
├ termination_status: TIME_LIMIT
├ objective_bound (ub): -2.0
├ Candidate solution (; result = 1)
│ ├ objective_value (lb): -3.0
For a Feasibility-Problem
ObjSense: FEASIBILITY_SENSE (Did you forget to specify?)
termination_status: TIME_LIMIT
Candidate solution (; result = 1)
Which smart solver showcases this behavior? I wonder.
odow
March 20, 2025, 3:05am
25
Also following up to say that the next release of JuMP features a revamped solution summary:
julia> solution_summary(model; verbose = true)
solution_summary(; result = 1, verbose = true)
├ solver_name : Gurobi
├ Termination
│ ├ termination_status : OPTIMAL
│ ├ result_count : 3
│ ├ raw_status : Model was solved to optimality (subject to tolerances), and an optimal solution is available.
│ └ objective_bound : -3.00000e+00
├ Solution (result = 1)
│ ├ primal_status : FEASIBLE_POINT
│ ├ dual_status : NO_SOLUTION
│ ├ objective_value : -3.00000e+00
│ ├ relative_gap : 0.00000e+00
│ └ value
│ ├ x : 1.00000e+00
│ └ y : 4.00000e+00
└ Work counters
├ solve_time (sec) : 3.06129e-04
├ simplex_iterations : 0
├ barrier_iterations : 0
└ node_count : 0
1 Like
Fortunately I have never used Cplex. It’s awkward.
I think it should report INFEASIBLE
directly in this case.
OPTIMAL
should be a definite answer which by itself implies normality.
1 Like
odow
March 20, 2025, 3:19am
27
We cannot report termination_status(model) == INFEASIBLE
because CPLEX did not prove that the problem is infeasible.
I looked at the code. We actually report the termination status as ALMOST_INFEASIBLE
which seems somewhat appropriate:
CPX_STAT_INForUNBD => MOI.INFEASIBLE_OR_UNBOUNDED,
CPX_STAT_MULTIOBJ_INFEASIBLE => MOI.INFEASIBLE,
CPX_STAT_MULTIOBJ_INForUNBD => MOI.INFEASIBLE_OR_UNBOUNDED,
CPX_STAT_MULTIOBJ_NON_OPTIMAL => MOI.LOCALLY_SOLVED,
CPX_STAT_MULTIOBJ_OPTIMAL => MOI.OPTIMAL,
CPX_STAT_MULTIOBJ_STOPPED => MOI.INTERRUPTED,
CPX_STAT_MULTIOBJ_UNBOUNDED => MOI.DUAL_INFEASIBLE,
CPX_STAT_NUM_BEST => MOI.NUMERICAL_ERROR,
CPX_STAT_OPTIMAL => MOI.OPTIMAL,
CPX_STAT_OPTIMAL_FACE_UNBOUNDED => MOI.DUAL_INFEASIBLE,
CPX_STAT_OPTIMAL_INFEAS => MOI.ALMOST_INFEASIBLE,
CPX_STAT_OPTIMAL_RELAXED_INF => MOI.LOCALLY_SOLVED,
CPX_STAT_OPTIMAL_RELAXED_QUAD => MOI.LOCALLY_SOLVED,
CPX_STAT_OPTIMAL_RELAXED_SUM => MOI.LOCALLY_SOLVED,
CPX_STAT_UNBOUNDED => MOI.DUAL_INFEASIBLE,
CPXMIP_ABORT_FEAS => MOI.INTERRUPTED,
CPXMIP_ABORT_INFEAS => MOI.INTERRUPTED,
CPXMIP_ABORT_RELAXATION_UNBOUNDED => MOI.INFEASIBLE_OR_UNBOUNDED,
CPXMIP_ABORT_RELAXED => MOI.LOCALLY_SOLVED,
CPXMIP_DETTIME_LIM_FEAS => MOI.TIME_LIMIT,
CPXMIP_DETTIME_LIM_INFEAS => MOI.TIME_LIMIT,
My larger point is that you should not rely on termination_status
alone. You must always check it in combination with primal_status
.
Yes, there are circumstances where we have no primal solution but the JuMP.objective_bound
functions (verb) properly, and it may function properly both in pure-LP and MIP. I can furnish code instances to reproduce this situation, with Gurobi.