diff --git a/src/Bridges/Constraint/indicator_sos.jl b/src/Bridges/Constraint/indicator_sos.jl index 93505b570a..c4fd9d4ed1 100644 --- a/src/Bridges/Constraint/indicator_sos.jl +++ b/src/Bridges/Constraint/indicator_sos.jl @@ -159,8 +159,8 @@ function MOI.supports( end function MOI.get(model::MOI.ModelLike, attr::MOI.ConstraintPrimal, bridge::IndicatorSOS1Bridge) - zvalue = MOI.get(model, MOI.VariablePrimal(attr.N), bridge.z_variable_index) - wvalue = MOI.get(model, MOI.VariablePrimal(attr.N), bridge.w_variable_index) + zvalue = MOI.get(model, MOI.VariablePrimal(attr.result_index), bridge.z_variable_index) + wvalue = MOI.get(model, MOI.VariablePrimal(attr.result_index), bridge.w_variable_index) lin_primal_start = MOI.get(model, attr, bridge.linear_constraint_index) return [zvalue, lin_primal_start - wvalue] end diff --git a/src/Bridges/Constraint/semi_to_binary.jl b/src/Bridges/Constraint/semi_to_binary.jl index aeef00099f..e3a4a0099e 100644 --- a/src/Bridges/Constraint/semi_to_binary.jl +++ b/src/Bridges/Constraint/semi_to_binary.jl @@ -115,7 +115,7 @@ end function MOI.get(model::MOI.ModelLike, attr::MOI.ConstraintPrimal, bridge::SemiToBinaryBridge) - MOI.get(model, MOI.VariablePrimal(attr.N), bridge.variable_index) + MOI.get(model, MOI.VariablePrimal(attr.result_index), bridge.variable_index) end function MOI.supports( diff --git a/src/Bridges/Constraint/soc_to_nonconvex_quad.jl b/src/Bridges/Constraint/soc_to_nonconvex_quad.jl index 6f6c143f1b..abb0a49bd0 100644 --- a/src/Bridges/Constraint/soc_to_nonconvex_quad.jl +++ b/src/Bridges/Constraint/soc_to_nonconvex_quad.jl @@ -180,7 +180,7 @@ end # Attributes, Bridge acting as a constraint function MOI.get(model::MOI.ModelLike, attr::MOI.ConstraintPrimal, bridge::AbstractSOCtoNonConvexQuadBridge) - vals = MOI.get.(model, MOI.VariablePrimal(attr.N), bridge.vars) + vals = MOI.get.(model, MOI.VariablePrimal(attr.result_index), bridge.vars) return vals end diff --git a/src/Bridges/Constraint/vectorize.jl b/src/Bridges/Constraint/vectorize.jl index a061528681..7351be28cd 100644 --- a/src/Bridges/Constraint/vectorize.jl +++ b/src/Bridges/Constraint/vectorize.jl @@ -110,7 +110,7 @@ function MOI.get( ) x = MOI.get(model, attr, bridge.vector_constraint) @assert length(x) == 1 - if MOIU.is_ray(MOI.get(model, MOI.PrimalStatus(attr.N))) + if MOIU.is_ray(MOI.get(model, MOI.PrimalStatus(attr.result_index))) # If it is an infeasibility certificate, it is a ray and satisfies the # homogenized problem, see https://github.com/jump-dev/MathOptInterface.jl/issues/433 return x[1] diff --git a/src/Bridges/Variable/vectorize.jl b/src/Bridges/Variable/vectorize.jl index 3ec9dbbc59..b881f00424 100644 --- a/src/Bridges/Variable/vectorize.jl +++ b/src/Bridges/Variable/vectorize.jl @@ -76,7 +76,7 @@ function MOI.get(model::MOI.ModelLike, attr::MOI.ConstraintPrimal, x = MOI.get(model, attr, bridge.vector_constraint) @assert length(x) == 1 y = x[1] - if !MOIU.is_ray(MOI.get(model, MOI.PrimalStatus(attr.N))) + if !MOIU.is_ray(MOI.get(model, MOI.PrimalStatus(attr.result_index))) # If it is an infeasibility certificate, it is a ray and satisfies the # homogenized problem, see https://github.com/jump-dev/MathOptInterface.jl/issues/433 # Otherwise, we need to add the set constant since the ConstraintPrimal @@ -98,7 +98,7 @@ function MOI.get(model::MOI.ModelLike, bridge::VectorizeBridge) value = MOI.get(model, attr, bridge.variable) if !(attr isa MOI.VariablePrimal && - MOIU.is_ray(MOI.get(model, MOI.PrimalStatus(attr.N)))) + MOIU.is_ray(MOI.get(model, MOI.PrimalStatus(attr.result_index)))) value += bridge.set_constant end return value diff --git a/src/MathOptInterface.jl b/src/MathOptInterface.jl index 6153434604..88f84aa49a 100644 --- a/src/MathOptInterface.jl +++ b/src/MathOptInterface.jl @@ -139,6 +139,8 @@ include("modifications.jl") include("variables.jl") include("nlp.jl") +include("deprecate.jl") + # submodules include("Utilities/Utilities.jl") # MOI.Utilities include("Test/Test.jl") # MOI.Test diff --git a/src/Utilities/mockoptimizer.jl b/src/Utilities/mockoptimizer.jl index b3069707bb..9b1d58f6f4 100644 --- a/src/Utilities/mockoptimizer.jl +++ b/src/Utilities/mockoptimizer.jl @@ -160,10 +160,10 @@ function MOI.set(mock::MockOptimizer, attr::MOI.DualObjectiveValue, value::Real) mock.dual_objective_value[attr.result_index] = value end function MOI.set(mock::MockOptimizer, attr::MOI.PrimalStatus, value::MOI.ResultStatusCode) - mock.primal_status[attr.N] = value + mock.primal_status[attr.result_index] = value end function MOI.set(mock::MockOptimizer, attr::MOI.DualStatus, value::MOI.ResultStatusCode) - mock.dual_status[attr.N] = value + mock.dual_status[attr.result_index] = value end MOI.set(mock::MockOptimizer, ::MockModelAttribute, value::Integer) = (mock.attribute = value) function MOI.supports(mock::MockOptimizer, attr::MOI.AbstractOptimizerAttribute) @@ -315,17 +315,17 @@ function MOI.get(mock::MockOptimizer, attr::MOI.DualObjectiveValue) end end function MOI.get(mock::MockOptimizer, attr::MOI.PrimalStatus) - if attr.N > mock.result_count + if attr.result_index > mock.result_count return MOI.NO_SOLUTION else - return get(mock.primal_status, attr.N, MOI.NO_SOLUTION) + return get(mock.primal_status, attr.result_index, MOI.NO_SOLUTION) end end function MOI.get(mock::MockOptimizer, attr::MOI.DualStatus) - if attr.N > mock.result_count + if attr.result_index > mock.result_count return MOI.NO_SOLUTION else - return get(mock.dual_status, attr.N, MOI.NO_SOLUTION) + return get(mock.dual_status, attr.result_index, MOI.NO_SOLUTION) end end MOI.get(mock::MockOptimizer, ::MockModelAttribute) = mock.attribute @@ -402,7 +402,7 @@ function _safe_set_result(dict::Dict{K,V}, attr::MOI.AnyAttribute, index::K, if !haskey(dict, xored) dict[xored] = V() end - dict[xored][MOI._result_index_field(attr)] = value + dict[xored][attr.result_index] = value end function _safe_get_result(dict::Dict, attr::MOI.AnyAttribute, index::MOI.Index, name::String) @@ -411,9 +411,9 @@ function _safe_get_result(dict::Dict, attr::MOI.AnyAttribute, index::MOI.Index, if result_to_value === nothing error("No mock $name is set for ", index_name, " `", index, "`.") end - value = get(result_to_value, MOI._result_index_field(attr), nothing) + value = get(result_to_value, attr.result_index, nothing) if value === nothing - error("No mock $name is set for ", index_name, " `", index, "` at result index `", MOI._result_index_field(attr), "`.") + error("No mock $name is set for ", index_name, " `", index, "` at result index `", attr.result_index, "`.") end return value end diff --git a/src/Utilities/results.jl b/src/Utilities/results.jl index 5d83e91466..9fcba71448 100644 --- a/src/Utilities/results.jl +++ b/src/Utilities/results.jl @@ -149,7 +149,7 @@ function get_fallback(model::MOI.ModelLike, attr::MOI.ConstraintPrimal, idx::MOI.ConstraintIndex) f = MOI.get(model, MOI.ConstraintFunction(), idx) # TODO do not include constant if primal solution is a ray - return eval_variables(vi -> MOI.get(model, MOI.VariablePrimal(attr.N), vi), f) + return eval_variables(vi -> MOI.get(model, MOI.VariablePrimal(attr.result_index), vi), f) end ################ Constraint Dual for Variable-wise constraints ################# @@ -267,7 +267,7 @@ function variable_dual(model::MOI.ModelLike, ci::MOI.ConstraintIndex{<:MOI.VectorQuadraticFunction}) func = MOI.get(model, MOI.ConstraintFunction(), ci) set = MOI.get(model, MOI.ConstraintSet(), ci) - primal_attr = MOI.VariablePrimal(attr.N) + primal_attr = MOI.VariablePrimal(attr.result_index) coef = variable_coefficient(func, vi, vi -> MOI.get(model, primal_attr, vi)) dual = MOI.get(model, attr, ci) return set_dot(coef, dual, set) @@ -286,7 +286,7 @@ function variable_dual(model::MOI.ModelLike, vi::MOI.VariableIndex, ci::MOI.ConstraintIndex{<:MOI.ScalarQuadraticFunction}) func = MOI.get(model, MOI.ConstraintFunction(), ci) - primal_attr = MOI.VariablePrimal(attr.N) + primal_attr = MOI.VariablePrimal(attr.result_index) coef = variable_coefficient(func, vi, vi -> MOI.get(model, primal_attr, vi)) dual = MOI.get(model, attr, ci) return coef * dual @@ -369,7 +369,7 @@ function variable_dual(model::MOI.ModelLike, dual += sign * variable_coefficient(f, vi) elseif F <: MOI.ScalarQuadraticFunction f = MOI.get(model, obj_attr) - primal_attr = MOI.VariablePrimal(attr.N) + primal_attr = MOI.VariablePrimal(attr.result_index) dual += sign * variable_coefficient(f, vi, vi -> MOI.get(model, primal_attr, vi)) else error("Fallback getter for variable constraint dual does not", diff --git a/src/attributes.jl b/src/attributes.jl index def5d91ddb..7d4ce8859e 100644 --- a/src/attributes.jl +++ b/src/attributes.jl @@ -123,13 +123,10 @@ struct ResultIndexBoundsError{AttrType} <: Exception attr::AttrType result_count::Int end -# TODO: rename the .N -> .result_index field in necessary attributes (e.g., -# VariablePrimal, ConstraintPrimal, ConstraintDual), and remove this helper -# function. -_result_index_field(attr) = attr.result_index + function check_result_index_bounds(model::ModelLike, attr) result_count = get(model, ResultCount()) - if !(1 <= _result_index_field(attr) <= result_count) + if !(1 <= attr.result_index <= result_count) throw(ResultIndexBoundsError(attr, result_count)) end end @@ -1004,17 +1001,16 @@ A variable attribute for the initial assignment to some primal variable's value struct VariablePrimalStart <: AbstractVariableAttribute end """ - VariablePrimal(N) + VariablePrimal(result_index) VariablePrimal() -A variable attribute for the assignment to some primal variable's value in result `N`. -If `N` is omitted, it is 1 by default. +A variable attribute for the assignment to some primal variable's value in result `result_index`. +If `result_index` is omitted, it is 1 by default. """ struct VariablePrimal <: AbstractVariableAttribute - N::Int + result_index::Int end VariablePrimal() = VariablePrimal(1) -_result_index_field(attr::VariablePrimal) = attr.N """ CallbackVariablePrimal(callback_data) @@ -1090,11 +1086,11 @@ A constraint attribute for the initial assignment to some constraint's dual valu struct ConstraintDualStart <: AbstractConstraintAttribute end """ - ConstraintPrimal(N) + ConstraintPrimal(result_index::Int) ConstraintPrimal() -A constraint attribute for the assignment to some constraint's primal value(s) in result `N`. -If `N` is omitted, it is 1 by default. +A constraint attribute for the assignment to some constraint's primal value(s) +in result `result_index`. If `result_index` is omitted, it is 1 by default. Given a constraint `function-in-set`, the `ConstraintPrimal` is the value of the function evaluated at the primal solution of the variables. For example, given @@ -1103,23 +1099,21 @@ a primal solution of `(x,y) = (4,5)`, the `ConstraintPrimal` solution of the constraint is `1 * 4 + 2 * 5 + 3 = 17`. """ struct ConstraintPrimal <: AbstractConstraintAttribute - N::Int + result_index::Int end ConstraintPrimal() = ConstraintPrimal(1) -_result_index_field(attr::ConstraintPrimal) = attr.N """ - ConstraintDual(N) + ConstraintDual(result_index) ConstraintDual() -A constraint attribute for the assignment to some constraint's dual value(s) in result `N`. -If `N` is omitted, it is 1 by default. +A constraint attribute for the assignment to some constraint's dual value(s) in result `result_index`. +If `result_index` is omitted, it is 1 by default. """ struct ConstraintDual <: AbstractConstraintAttribute - N::Int + result_index::Int end ConstraintDual() = ConstraintDual(1) -_result_index_field(attr::ConstraintDual) = attr.N """ ConstraintBasisStatus(result_index) @@ -1395,32 +1389,30 @@ The values indicate how to interpret the result vector. UNKNOWN_RESULT_STATUS, OTHER_RESULT_STATUS) """ - PrimalStatus(N) + PrimalStatus(result_index::Int) PrimalStatus() -A model attribute for the `ResultStatusCode` of the primal result `N`. -If `N` is omitted, it defaults to 1. If `N` is larger than the value of -[`ResultCount`](@ref) then `NO_SOLUTION` is returned. +A model attribute for the `ResultStatusCode` of the primal result `result_index`. +If `result_index` is omitted, it defaults to 1. If `result_index` is larger than +the value of [`ResultCount`](@ref) then `NO_SOLUTION` is returned. """ struct PrimalStatus <: AbstractModelAttribute - N::Int + result_index::Int end PrimalStatus() = PrimalStatus(1) -_result_index_field(attr::PrimalStatus) = attr.N """ - DualStatus(N) + DualStatus(result_index) DualStatus() -A model attribute for the `ResultStatusCode` of the dual result `N`. -If `N` is omitted, it defaults to 1. If `N` is larger than the value of -[`ResultCount`](@ref) then `NO_SOLUTION` is returned. +A model attribute for the `ResultStatusCode` of the dual result `result_index`. +If `result_index` is omitted, it defaults to 1. If `result_index` is larger than +the value of [`ResultCount`](@ref) then `NO_SOLUTION` is returned. """ struct DualStatus <: AbstractModelAttribute - N::Int + result_index::Int end DualStatus() = DualStatus(1) -_result_index_field(attr::DualStatus) = attr.N # Cost of bridging constrained variable in S diff --git a/src/deprecate.jl b/src/deprecate.jl new file mode 100644 index 0000000000..63b496e3d9 --- /dev/null +++ b/src/deprecate.jl @@ -0,0 +1,20 @@ +# deprecate _result_index_field and accessing attr.N, no export +@deprecate _result_index_field(attr) attr.result_index false + +function Base.getproperty(attr::Attr, f::Symbol) where Attr <:Union{ + ObjectiveValue, + DualObjectiveValue, + VariablePrimal, + ConstraintPrimal, + ConstraintDual, + ConstraintBasisStatus, + PrimalStatus, + DualStatus, + NLPBlockDual, + } + if f === :N + @warn "Field attr.N is deprecated, use attr.result_index" + return getfield(attr, :result_index) + end + return getfield(attr, f) +end diff --git a/src/nlp.jl b/src/nlp.jl index 4f13846ca9..072a2f0358 100644 --- a/src/nlp.jl +++ b/src/nlp.jl @@ -22,17 +22,16 @@ optionally a nonlinear objective. struct NLPBlock <: AbstractModelAttribute end """ - NLPBlockDual(N) + NLPBlockDual(result_index::Int) NLPBlockDual() -The Lagrange multipliers on the constraints from the `NLPBlock` in result `N`. -If `N` is omitted, it is 1 by default. +The Lagrange multipliers on the constraints from the `NLPBlock` in result `result_index`. +If `result_index` is omitted, it is 1 by default. """ struct NLPBlockDual <: AbstractModelAttribute - N::Int + result_index::Int end NLPBlockDual() = NLPBlockDual(1) -_result_index_field(attr::NLPBlockDual) = attr.N is_set_by_optimize(::NLPBlockDual) = true diff --git a/test/attributes.jl b/test/attributes.jl index f51310eb61..c8c0057153 100644 --- a/test/attributes.jl +++ b/test/attributes.jl @@ -29,4 +29,23 @@ @test_throws err MOI.set(model, MOI.VariablePrimalStart(), [x], ones(2)) end + attr = MOI.VariablePrimal() + @test_deprecated begin + @test MOI._result_index_field(attr) == 1 + end + + for attr_type in ( + MOI.ObjectiveValue, + MOI.DualObjectiveValue, + MOI.VariablePrimal, + MOI.ConstraintPrimal, + MOI.ConstraintDual, + MOI.ConstraintBasisStatus, + MOI.PrimalStatus, + MOI.DualStatus, + MOI.NLPBlockDual, + ) + attr = attr_type(1) + @test_logs (:warn, "Field attr.N is deprecated, use attr.result_index") attr.N + end end