diff --git a/README.md b/README.md index 9b3b0011..27e19337 100644 --- a/README.md +++ b/README.md @@ -160,8 +160,6 @@ function my_callback_function(cb_data) @assert XPRSgetdblattrib(prob, XPRS_BESTBOUND, p_bound) == 0 rel_gap = abs((p_obj[] - p_bound[]) / p_obj[]) @info "Relative gap = $rel_gap" - # Before querying `callback_value`, you must call: - Xpress.get_cb_solution(unsafe_backend(model), cb_data.model) x_val = callback_value(cb_data, x) y_val = callback_value(cb_data, y) # You can submit solver-independent MathOptInterface attributes such as diff --git a/src/MOI/MOI_callbacks.jl b/src/MOI/MOI_callbacks.jl index bdaa4974..68d875ce 100644 --- a/src/MOI/MOI_callbacks.jl +++ b/src/MOI/MOI_callbacks.jl @@ -61,23 +61,6 @@ function MOI.set(model::Optimizer, ::CallbackFunction, f::Function) return end -function get_cb_solution(model::Optimizer, model_inner::XpressProblem) - model.callback_cached_solution = _reset_cached_solution( - model.callback_cached_solution, - length(model.variable_info), - length(model.affine_constraint_info), - ) - ret = XPRSgetlpsol( - model_inner, - model.callback_cached_solution.variable_primal, - model.callback_cached_solution.linear_primal, - model.callback_cached_solution.linear_dual, - model.callback_cached_solution.variable_dual, - ) - _check(model_inner, ret) - return -end - function _load_existing_cuts(model::Optimizer, cb_data::CallbackData) if isempty(model.cb_cut_data.cutptrs) return false @@ -126,7 +109,6 @@ function default_moi_callback(model::Optimizer) if pInt[] > 1 return end - get_cb_solution(model, cb_data.model) if model.heuristic_callback !== nothing model.callback_state = CB_HEURISTIC model.heuristic_callback(cb_data) @@ -159,11 +141,14 @@ end function MOI.get( model::Optimizer, - ::MOI.CallbackVariablePrimal{CallbackData}, + attr::MOI.CallbackVariablePrimal{CallbackData}, x::MOI.VariableIndex, ) - column = _info(model, x).column - return model.callback_cached_solution.variable_primal[column] + c = _info(model, x).column - 1 + xP = Ref{Cdouble}() + ret = XPRSgetcallbacksolution(attr.callback_data.model, C_NULL, xP, c, c) + _check(model, ret) + return xP[] end function callback_exception(model::Optimizer, cb, err::Exception) @@ -314,3 +299,6 @@ function MOI.submit( end MOI.supports(::Optimizer, ::MOI.HeuristicSolution{CallbackData}) = true + +# Kept for backward compatibility with v0.18 +get_cb_solution(::Optimizer, ::XpressProblem) = nothing diff --git a/src/MOI/MOI_wrapper.jl b/src/MOI/MOI_wrapper.jl index 97a2f49c..16e4339b 100644 --- a/src/MOI/MOI_wrapper.jl +++ b/src/MOI/MOI_wrapper.jl @@ -248,7 +248,6 @@ mutable struct Optimizer <: MOI.AbstractOptimizer backward_sensitivity_cache::Union{Nothing,SensitivityCache} # Callback fields. - callback_cached_solution::Union{Nothing,CachedSolution} cb_cut_data::CallbackCutData callback_state::CallbackState cb_exception::Union{Nothing,Exception} @@ -373,7 +372,6 @@ function MOI.empty!(model::Optimizer) # solve_method model.forward_sensitivity_cache = nothing model.backward_sensitivity_cache = nothing - model.callback_cached_solution = nothing model.cb_cut_data = CallbackCutData(false, XPRScut[]) model.callback_state = CB_NONE model.cb_exception = nothing @@ -405,7 +403,6 @@ function MOI.is_empty(model::Optimizer) model.termination_status == MOI.OPTIMIZE_NOT_CALLED && model.primal_status == MOI.NO_SOLUTION && model.dual_status == MOI.NO_SOLUTION && - model.callback_cached_solution === nothing && model.callback_state == CB_NONE && model.cb_exception === nothing && model.lazy_callback === nothing && diff --git a/test/test_MOI_wrapper.jl b/test/test_MOI_wrapper.jl index 78a12f28..cf416f5c 100644 --- a/test/test_MOI_wrapper.jl +++ b/test/test_MOI_wrapper.jl @@ -1155,7 +1155,6 @@ function test_callback_function_LazyConstraint() global generic_lazy_called = false function callback_function(cb_data) push!(cb_calls, 1) - Xpress.get_cb_solution(model, cb_data.model) x_val = MOI.get(model, MOI.CallbackVariablePrimal(cb_data), x) y_val = MOI.get(model, MOI.CallbackVariablePrimal(cb_data), y) if y_val - x_val > 1 + 1e-6 @@ -1196,7 +1195,6 @@ function test_callback_function_UserCut() if pInt[] > 1 return end - Xpress.get_cb_solution(model, cb_data.model) terms = MOI.ScalarAffineTerm{Float64}[] accumulated = 0.0 for (i, xi) in enumerate(x) @@ -1235,7 +1233,6 @@ function test_callback_function_HeuristicSolution() if pInt[] > 1 return end - Xpress.get_cb_solution(model, cb_data.model) x_vals = MOI.get.(model, MOI.CallbackVariablePrimal(cb_data), x) @test MOI.submit( @@ -1547,7 +1544,6 @@ end function test_callback_function_nothing() model, x, y = callback_simple_model() function callback_function(cb_data) - Xpress.get_cb_solution(model, cb_data.model) x_val = MOI.get(model, MOI.CallbackVariablePrimal(cb_data), x) y_val = MOI.get(model, MOI.CallbackVariablePrimal(cb_data), y) if y_val - x_val > 1 + 1e-6 @@ -1583,7 +1579,6 @@ end function test_callback_function_replace() model, x, y = callback_simple_model() function callback_function(cb_data) - Xpress.get_cb_solution(model, cb_data.model) x_val = MOI.get(model, MOI.CallbackVariablePrimal(cb_data), x) y_val = MOI.get(model, MOI.CallbackVariablePrimal(cb_data), y) if y_val - x_val > 1 + 1e-6 @@ -2332,6 +2327,12 @@ function test_InterruptException() return end +function test_get_cb_solution() + model = Xpress.Optimizer() + @test Xpress.get_cb_solution(model, model.inner) === nothing + return +end + end # TestMOIWrapper TestMOIWrapper.runtests()