diff --git a/src/solvers/jump_solver.jl b/src/solvers/jump_solver.jl index 4d43e23..3d51fc6 100644 --- a/src/solvers/jump_solver.jl +++ b/src/solvers/jump_solver.jl @@ -83,9 +83,10 @@ function _update_solution!(data::JuMPSolverData) try data.sensitivity_report = lp_sensitivity_report(data.model) catch - # solver does not support sensitivity analysis; ignore + @warn("Sensitivity analysis is unavailable; ignoring") end + basis_status_supported = true data.dual_values = Dict() for (ftype, stype) in JuMP.list_of_constraint_types(data.model) for constr in JuMP.all_constraints(data.model, ftype, stype) @@ -93,9 +94,15 @@ function _update_solution!(data::JuMPSolverData) data.dual_values[constr] = -JuMP.dual(constr) # Basis status - if data.sensitivity_report !== nothing - data.basis_status[constr] = - MOI.get(data.model, MOI.ConstraintBasisStatus(), constr) + if basis_status_supported + try + data.basis_status[constr] = + MOI.get(data.model, MOI.ConstraintBasisStatus(), constr) + catch + @warn "Basis status is unavailable; ignoring" + basis_status_supported = false + data.basis_status = Dict() + end end # Build map between variables and bound constraints @@ -360,7 +367,7 @@ function is_infeasible(data::JuMPSolverData) end -function get_variables(data::JuMPSolverData; with_static::Bool) +function get_variables(data::JuMPSolverData; with_static::Bool, with_sa::Bool) vars = JuMP.all_variables(data.model) lb, ub, types = nothing, nothing, nothing sa_obj_down, sa_obj_up = nothing, nothing @@ -396,16 +403,13 @@ function get_variables(data::JuMPSolverData; with_static::Bool) types = [JuMP.is_binary(v) ? "B" : JuMP.is_integer(v) ? "I" : "C" for v in vars] end - # Sensitivity analysis and basis status + # Sensitivity analysis if data.sensitivity_report !== nothing sa_obj_down, sa_obj_up = Float64[], Float64[] sa_lb_down, sa_lb_up = Float64[], Float64[] sa_ub_down, sa_ub_up = Float64[], Float64[] - basis_status = [] for (i, v) in enumerate(vars) - basis_status_v = "B" - # Objective function (delta_down, delta_up) = data.sensitivity_report[v] push!(sa_obj_down, delta_down + obj_coeffs[i]) @@ -417,9 +421,6 @@ function get_variables(data::JuMPSolverData; with_static::Bool) (delta_down, delta_up) = data.sensitivity_report[constr] push!(sa_lb_down, lower_bound(v) + delta_down) push!(sa_lb_up, lower_bound(v) + delta_up) - if data.basis_status[constr] == MOI.NONBASIC - basis_status_v = "L" - end else push!(sa_lb_down, -Inf) push!(sa_lb_up, -Inf) @@ -431,14 +432,30 @@ function get_variables(data::JuMPSolverData; with_static::Bool) (delta_down, delta_up) = data.sensitivity_report[constr] push!(sa_ub_down, upper_bound(v) + delta_down) push!(sa_ub_up, upper_bound(v) + delta_up) - if data.basis_status[constr] == MOI.NONBASIC - basis_status_v = "U" - end else push!(sa_ub_down, Inf) push!(sa_ub_up, Inf) end + end + end + # Basis status + if !isempty(data.basis_status) + basis_status = [] + for v in vars + basis_status_v = "B" + if v.index in keys(data.var_lb_constr) + constr = data.var_lb_constr[v.index] + if data.basis_status[constr] == MOI.NONBASIC + basis_status_v = "L" + end + end + if v.index in keys(data.var_ub_constr) + constr = data.var_ub_constr[v.index] + if data.basis_status[constr] == MOI.NONBASIC + basis_status_v = "U" + end + end push!(basis_status, basis_status_v) end end @@ -451,12 +468,12 @@ function get_variables(data::JuMPSolverData; with_static::Bool) names = to_str_array(names), obj_coeffs = with_static ? obj_coeffs : nothing, reduced_costs = rc, - sa_lb_down = sa_lb_down, - sa_lb_up = sa_lb_up, - sa_obj_down = sa_obj_down, - sa_obj_up = sa_obj_up, - sa_ub_down = sa_ub_down, - sa_ub_up = sa_ub_up, + sa_lb_down = with_sa ? sa_lb_down : nothing, + sa_lb_up = with_sa ? sa_lb_up : nothing, + sa_obj_down = with_sa ? sa_obj_down : nothing, + sa_obj_up = with_sa ? sa_obj_up : nothing, + sa_ub_down = with_sa ? sa_ub_down : nothing, + sa_ub_up = with_sa ? sa_ub_up : nothing, types = to_str_array(types), upper_bounds = ub, values = values, @@ -481,9 +498,10 @@ function get_constraints( if !isempty(data.dual_values) dual_values = Float64[] end - if !isempty(data.basis_status) basis_status = [] + end + if data.sensitivity_report !== nothing sa_rhs_up, sa_rhs_down = Float64[], Float64[] end @@ -530,8 +548,8 @@ function get_constraints( push!(dual_values, data.dual_values[constr]) end + # Basis status if !isempty(data.basis_status) - # Basis status b = data.basis_status[constr] if b == MOI.NONBASIC push!(basis_status, "N") @@ -540,8 +558,10 @@ function get_constraints( else error("Unknown basis status: $b") end + end - # Sensitivity analysis + # Sensitivity analysis + if data.sensitivity_report !== nothing (delta_down, delta_up) = data.sensitivity_report[constr] push!(sa_rhs_down, rhs_c + delta_down) push!(sa_rhs_up, rhs_c + delta_up) @@ -549,7 +569,13 @@ function get_constraints( end end - lhs = sparse(lhs_rows, lhs_cols, lhs_values) + lhs = sparse( + lhs_rows, + lhs_cols, + lhs_values, + length(rhs), + JuMP.num_variables(data.model), + ) if !isempty(data.x) lhs_value = lhs * data.x slacks = abs.(lhs_value - rhs) @@ -561,8 +587,8 @@ function get_constraints( lhs = (with_static && with_lhs) ? sparse(lhs_rows, lhs_cols, lhs_values) : nothing, names = to_str_array(names), rhs = with_static ? rhs : nothing, - sa_rhs_down = sa_rhs_down, - sa_rhs_up = sa_rhs_up, + sa_rhs_down = with_sa ? sa_rhs_down : nothing, + sa_rhs_up = with_sa ? sa_rhs_up : nothing, senses = with_static ? to_str_array(senses) : nothing, slacks = slacks, ) @@ -636,7 +662,7 @@ function __init_JuMPSolver__() end get_variables(self; with_static = true, with_sa = true) = - get_variables(self.data; with_static = with_static) + get_variables(self.data; with_static = with_static, with_sa = with_sa) function get_variable_attrs(self) attrs = [