diff --git a/docs/src/reference/models.md b/docs/src/reference/models.md index 76f9a9154b..7efc192469 100644 --- a/docs/src/reference/models.md +++ b/docs/src/reference/models.md @@ -18,6 +18,7 @@ get get! set supports +attribute_value_type ``` ## Model interface diff --git a/docs/src/tutorials/implementing.md b/docs/src/tutorials/implementing.md index f8e54d68be..432a12be0e 100644 --- a/docs/src/tutorials/implementing.md +++ b/docs/src/tutorials/implementing.md @@ -271,6 +271,11 @@ For each attribute * [`supports`](@ref) returns a `Bool` indicating whether the solver supports the attribute. +!!! info + Use [`attribute_value_type`](@ref) to check the value expected by a given + attribute. You should make sure that your [`get`](@ref) function correctly + infers to this type (or a subtype of it). + Each column in the table indicates whether you need to implement the particular method for each attribute. diff --git a/src/Bridges/Constraint/bridge.jl b/src/Bridges/Constraint/bridge.jl index 5e97bbd3c0..3e17de7b69 100644 --- a/src/Bridges/Constraint/bridge.jl +++ b/src/Bridges/Constraint/bridge.jl @@ -27,10 +27,10 @@ function bridge_constraint end The number of variables created by the bridge `b` in the model. """ -MOI.get(::AbstractBridge, ::MOI.NumberOfVariables) = 0 +MOI.get(::AbstractBridge, ::MOI.NumberOfVariables)::Int64 = 0 """ - MOI.get(b::AbstractBridge, ::MOI.NumberOfVariables) + MOI.get(b::AbstractBridge, ::MOI.ListOfVariableIndices) The list of variables created by the bridge `b` in the model. """ diff --git a/src/Bridges/Constraint/det.jl b/src/Bridges/Constraint/det.jl index e8073392f5..b0a5521391 100644 --- a/src/Bridges/Constraint/det.jl +++ b/src/Bridges/Constraint/det.jl @@ -210,7 +210,10 @@ function subsum( end # Attributes, Bridge acting as a model -MOI.get(b::LogDetBridge, ::MOI.NumberOfVariables) = length(b.Δ) + length(b.l) + +function MOI.get(b::LogDetBridge, ::MOI.NumberOfVariables)::Int64 + return length(b.Δ) + length(b.l) +end MOI.get(b::LogDetBridge, ::MOI.ListOfVariableIndices) = [b.Δ; b.l] @@ -220,21 +223,21 @@ function MOI.get( MOI.VectorAffineFunction{T}, MOI.PositiveSemidefiniteConeTriangle, }, -) where {T} +)::Int64 where {T} return 1 end function MOI.get( b::LogDetBridge{T}, ::MOI.NumberOfConstraints{MOI.VectorAffineFunction{T},MOI.ExponentialCone}, -) where {T} +)::Int64 where {T} return length(b.lcindex) end function MOI.get( ::LogDetBridge{T}, ::MOI.NumberOfConstraints{MOI.ScalarAffineFunction{T},MOI.LessThan{T}}, -) where {T} +)::Int64 where {T} return 1 end @@ -407,7 +410,8 @@ function MOIB.added_constraint_types(::Type{RootDetBridge{T}}) where {T} end # Attributes, Bridge acting as a model -MOI.get(b::RootDetBridge, ::MOI.NumberOfVariables) = length(b.Δ) + +MOI.get(b::RootDetBridge, ::MOI.NumberOfVariables)::Int64 = length(b.Δ) MOI.get(b::RootDetBridge, ::MOI.ListOfVariableIndices) = copy(b.Δ) @@ -417,7 +421,7 @@ function MOI.get( MOI.VectorAffineFunction{T}, MOI.PositiveSemidefiniteConeTriangle, }, -) where {T} +)::Int64 where {T} return 1 end @@ -427,7 +431,7 @@ function MOI.get( MOI.VectorAffineFunction{T}, MOI.GeometricMeanCone, }, -) where {T} +)::Int64 where {T} return 1 end diff --git a/src/Bridges/Constraint/functionize.jl b/src/Bridges/Constraint/functionize.jl index 956dd05dc3..f78e1b42e0 100644 --- a/src/Bridges/Constraint/functionize.jl +++ b/src/Bridges/Constraint/functionize.jl @@ -54,7 +54,7 @@ end function MOI.get( ::ScalarFunctionizeBridge{T,S}, ::MOI.NumberOfConstraints{MOI.ScalarAffineFunction{T},S}, -) where {T,S} +)::Int64 where {T,S} return 1 end @@ -158,7 +158,7 @@ end function MOI.get( ::VectorFunctionizeBridge{T,S}, ::MOI.NumberOfConstraints{MOI.VectorAffineFunction{T},S}, -) where {T,S} +)::Int64 where {T,S} return 1 end diff --git a/src/Bridges/Constraint/geomean.jl b/src/Bridges/Constraint/geomean.jl index 8efc89c21c..d8229baf5c 100644 --- a/src/Bridges/Constraint/geomean.jl +++ b/src/Bridges/Constraint/geomean.jl @@ -164,29 +164,29 @@ function concrete_bridge_type( end # Attributes, Bridge acting as a model -MOI.get(b::GeoMeanBridge, ::MOI.NumberOfVariables) = length(b.xij) +MOI.get(b::GeoMeanBridge, ::MOI.NumberOfVariables)::Int64 = length(b.xij) MOI.get(b::GeoMeanBridge, ::MOI.ListOfVariableIndices) = copy(b.xij) function MOI.get( ::GeoMeanBridge{T,F}, ::MOI.NumberOfConstraints{F,MOI.LessThan{T}}, -) where {T,F} +)::Int64 where {T,F} return 1 # t ≤ x_{l1}/sqrt(N) end function MOI.get( b::GeoMeanBridge{T,F,G}, ::MOI.NumberOfConstraints{G,MOI.RotatedSecondOrderCone}, -) where {T,F,G} +)::Int64 where {T,F,G} return length(b.socrc) end function MOI.get( b::GeoMeanBridge{T,F,G}, ::MOI.NumberOfConstraints{G,MOI.Nonnegatives}, -) where {T,F,G} - return (b.d > 2 ? 0 : 1) +)::Int64 where {T,F,G} + return b.d > 2 ? 0 : 1 end function MOI.get( diff --git a/src/Bridges/Constraint/geomean_to_relentr.jl b/src/Bridges/Constraint/geomean_to_relentr.jl index fd60647810..e25696ca2b 100644 --- a/src/Bridges/Constraint/geomean_to_relentr.jl +++ b/src/Bridges/Constraint/geomean_to_relentr.jl @@ -86,7 +86,7 @@ function concrete_bridge_type( end # Attributes, Bridge acting as a model -MOI.get(bridge::GeoMeantoRelEntrBridge, ::MOI.NumberOfVariables) = 1 +MOI.get(::GeoMeantoRelEntrBridge, ::MOI.NumberOfVariables)::Int64 = 1 function MOI.get(bridge::GeoMeantoRelEntrBridge, ::MOI.ListOfVariableIndices) return [bridge.y] @@ -95,14 +95,14 @@ end function MOI.get( ::GeoMeantoRelEntrBridge{T,F}, ::MOI.NumberOfConstraints{F,MOI.Nonnegatives}, -) where {T,F} +)::Int64 where {T,F} return 1 end function MOI.get( ::GeoMeantoRelEntrBridge{T,F,G}, ::MOI.NumberOfConstraints{G,MOI.RelativeEntropyCone}, -) where {T,F,G} +)::Int64 where {T,F,G} return 1 end diff --git a/src/Bridges/Constraint/indicator_sos.jl b/src/Bridges/Constraint/indicator_sos.jl index 528b1619b0..8e921fb660 100644 --- a/src/Bridges/Constraint/indicator_sos.jl +++ b/src/Bridges/Constraint/indicator_sos.jl @@ -154,9 +154,7 @@ end # Attributes, Bridge acting as a model -function MOI.get(::IndicatorSOS1Bridge, ::MOI.NumberOfVariables) - return 1 -end +MOI.get(::IndicatorSOS1Bridge, ::MOI.NumberOfVariables)::Int64 = 1 function MOI.get(b::IndicatorSOS1Bridge, ::MOI.ListOfVariableIndices) return [b.w_variable] @@ -165,28 +163,28 @@ end function MOI.get( ::IndicatorSOS1Bridge{T,BC,Nothing}, ::MOI.NumberOfConstraints{MOI.SingleVariable,BC}, -) where {T,BC} +)::Int64 where {T,BC} return 0 end function MOI.get( ::IndicatorSOS1Bridge{T,BC,CI}, ::MOI.NumberOfConstraints{MOI.SingleVariable,BC}, -) where {T,BC,CI<:MOI.ConstraintIndex{MOI.SingleVariable,BC}} +)::Int64 where {T,BC,CI<:MOI.ConstraintIndex{MOI.SingleVariable,BC}} return 1 end function MOI.get( ::IndicatorSOS1Bridge, ::MOI.NumberOfConstraints{MOI.VectorOfVariables,<:MOI.SOS1}, -) +)::Int64 return 1 end function MOI.get( ::IndicatorSOS1Bridge{T,BC}, ::MOI.NumberOfConstraints{MOI.ScalarAffineFunction{T},BC}, -) where {T,BC,CI<:MOI.ConstraintIndex{MOI.SingleVariable,BC}} +)::Int64 where {T,BC,CI<:MOI.ConstraintIndex{MOI.SingleVariable,BC}} return 1 end diff --git a/src/Bridges/Constraint/interval.jl b/src/Bridges/Constraint/interval.jl index 89a3f736fb..47ea728a5a 100644 --- a/src/Bridges/Constraint/interval.jl +++ b/src/Bridges/Constraint/interval.jl @@ -86,14 +86,14 @@ end function MOI.get( ::SplitIntervalBridge{T,F,S,LS}, ::MOI.NumberOfConstraints{F,LS}, -) where {T,F,S,LS} +)::Int64 where {T,F,S,LS} return 1 end function MOI.get( ::SplitIntervalBridge{T,F,S,LS,US}, ::MOI.NumberOfConstraints{F,US}, -) where {T,F,S,LS,US} +)::Int64 where {T,F,S,LS,US} return 1 end diff --git a/src/Bridges/Constraint/norm_spec_nuc_to_psd.jl b/src/Bridges/Constraint/norm_spec_nuc_to_psd.jl index 8c083e34cf..be3a8764fd 100644 --- a/src/Bridges/Constraint/norm_spec_nuc_to_psd.jl +++ b/src/Bridges/Constraint/norm_spec_nuc_to_psd.jl @@ -70,9 +70,9 @@ end # Attributes, Bridge acting as a model function MOI.get( - bridge::NormSpectralBridge{T,F,G}, + ::NormSpectralBridge{T,F,G}, ::MOI.NumberOfConstraints{F,MOI.PositiveSemidefiniteConeTriangle}, -) where {T,F,G} +)::Int64 where {T,F,G} return 1 end @@ -282,7 +282,7 @@ function concrete_bridge_type( end # Attributes, Bridge acting as a model -function MOI.get(bridge::NormNuclearBridge, ::MOI.NumberOfVariables) +function MOI.get(bridge::NormNuclearBridge, ::MOI.NumberOfVariables)::Int64 return length(bridge.U) + length(bridge.V) end @@ -291,16 +291,16 @@ function MOI.get(bridge::NormNuclearBridge, ::MOI.ListOfVariableIndices) end function MOI.get( - bridge::NormNuclearBridge{T,F,G,H}, + ::NormNuclearBridge{T,F,G,H}, ::MOI.NumberOfConstraints{F,MOI.GreaterThan{T}}, -) where {T,F,G,H} +)::Int64 where {T,F,G,H} return 1 end function MOI.get( - bridge::NormNuclearBridge{T,F,G,H}, + ::NormNuclearBridge{T,F,G,H}, ::MOI.NumberOfConstraints{G,MOI.PositiveSemidefiniteConeTriangle}, -) where {T,F,G,H} +)::Int64 where {T,F,G,H} return 1 end diff --git a/src/Bridges/Constraint/norm_to_lp.jl b/src/Bridges/Constraint/norm_to_lp.jl index 4c24ab99c9..8f856ce3b6 100644 --- a/src/Bridges/Constraint/norm_to_lp.jl +++ b/src/Bridges/Constraint/norm_to_lp.jl @@ -150,12 +150,14 @@ function concrete_bridge_type( end # Attributes, Bridge acting as a model -MOI.get(b::NormOneBridge, ::MOI.NumberOfVariables) = length(b.y) +MOI.get(b::NormOneBridge, ::MOI.NumberOfVariables)::Int64 = length(b.y) + MOI.get(b::NormOneBridge, ::MOI.ListOfVariableIndices) = copy(b.y) + function MOI.get( - b::NormOneBridge{T,F}, + ::NormOneBridge{T,F}, ::MOI.NumberOfConstraints{F,MOI.Nonnegatives}, -) where {T,F} +)::Int64 where {T,F} return 1 end diff --git a/src/Bridges/Constraint/quad_to_soc.jl b/src/Bridges/Constraint/quad_to_soc.jl index fe61be5ea6..1bef004e07 100644 --- a/src/Bridges/Constraint/quad_to_soc.jl +++ b/src/Bridges/Constraint/quad_to_soc.jl @@ -189,7 +189,7 @@ function MOI.get( MOI.VectorAffineFunction{T}, MOI.RotatedSecondOrderCone, }, -) where {T} +)::Int64 where {T} return 1 end diff --git a/src/Bridges/Constraint/relentr_to_exp.jl b/src/Bridges/Constraint/relentr_to_exp.jl index f2176038c9..f52e7fb328 100644 --- a/src/Bridges/Constraint/relentr_to_exp.jl +++ b/src/Bridges/Constraint/relentr_to_exp.jl @@ -82,7 +82,7 @@ function concrete_bridge_type( end # Attributes, Bridge acting as a model -function MOI.get(bridge::RelativeEntropyBridge, ::MOI.NumberOfVariables) +function MOI.get(bridge::RelativeEntropyBridge, ::MOI.NumberOfVariables)::Int64 return length(bridge.y) end @@ -91,16 +91,16 @@ function MOI.get(bridge::RelativeEntropyBridge, ::MOI.ListOfVariableIndices) end function MOI.get( - bridge::RelativeEntropyBridge{T,F}, + ::RelativeEntropyBridge{T,F}, ::MOI.NumberOfConstraints{F,MOI.GreaterThan{T}}, -) where {T,F} +)::Int64 where {T,F} return 1 end function MOI.get( bridge::RelativeEntropyBridge{T,F,G}, ::MOI.NumberOfConstraints{G,MOI.ExponentialCone}, -) where {T,F,G} +)::Int64 where {T,F,G} return length(bridge.y) end diff --git a/src/Bridges/Constraint/scalarize.jl b/src/Bridges/Constraint/scalarize.jl index 22aae28a3c..2bc1f7632e 100644 --- a/src/Bridges/Constraint/scalarize.jl +++ b/src/Bridges/Constraint/scalarize.jl @@ -58,7 +58,7 @@ end function MOI.get( bridge::ScalarizeBridge{T,F,S}, ::MOI.NumberOfConstraints{F,S}, -) where {T,F,S} +)::Int64 where {T,F,S} return length(bridge.scalar_constraints) end diff --git a/src/Bridges/Constraint/semi_to_binary.jl b/src/Bridges/Constraint/semi_to_binary.jl index d7997a28f6..f51ddabe30 100644 --- a/src/Bridges/Constraint/semi_to_binary.jl +++ b/src/Bridges/Constraint/semi_to_binary.jl @@ -214,9 +214,7 @@ end # Attributes, Bridge acting as a model -function MOI.get(::SemiToBinaryBridge, ::MOI.NumberOfVariables) - return 1 -end +MOI.get(::SemiToBinaryBridge, ::MOI.NumberOfVariables)::Int64 = 1 function MOI.get(b::SemiToBinaryBridge, ::MOI.ListOfVariableIndices) return [b.binary_variable] @@ -225,28 +223,28 @@ end function MOI.get( ::SemiToBinaryBridge{T,S}, ::MOI.NumberOfConstraints{MOI.SingleVariable,MOI.ZeroOne}, -) where {T,S} +)::Int64 where {T,S} return 1 end function MOI.get( ::SemiToBinaryBridge{T,S}, ::MOI.NumberOfConstraints{MOI.SingleVariable,MOI.Integer}, -) where {T,S<:MOI.Semiinteger} +)::Int64 where {T,S<:MOI.Semiinteger} return 1 end function MOI.get( ::SemiToBinaryBridge{T,S}, ::MOI.NumberOfConstraints{MOI.ScalarAffineFunction{T},MOI.GreaterThan{T}}, -) where {T,S} +)::Int64 where {T,S} return 1 end function MOI.get( ::SemiToBinaryBridge{T,S}, ::MOI.NumberOfConstraints{MOI.ScalarAffineFunction{T},MOI.LessThan{T}}, -) where {T,S} +)::Int64 where {T,S} return 1 end diff --git a/src/Bridges/Constraint/set_map.jl b/src/Bridges/Constraint/set_map.jl index d023223d34..ce090d4e3a 100644 --- a/src/Bridges/Constraint/set_map.jl +++ b/src/Bridges/Constraint/set_map.jl @@ -64,7 +64,7 @@ end function MOI.get( ::SetMapBridge{T,S2,S1,F}, ::MOI.NumberOfConstraints{F,S2}, -) where {T,S2,S1,F} +)::Int64 where {T,S2,S1,F} return 1 end diff --git a/src/Bridges/Constraint/slack.jl b/src/Bridges/Constraint/slack.jl index 12433d5905..730625601c 100644 --- a/src/Bridges/Constraint/slack.jl +++ b/src/Bridges/Constraint/slack.jl @@ -15,14 +15,14 @@ end function MOI.get( ::AbstractSlackBridge{T,VF,ZS,F}, ::MOI.NumberOfConstraints{F,ZS}, -) where {T,VF,ZS,F} +)::Int64 where {T,VF,ZS,F} return 1 end function MOI.get( ::AbstractSlackBridge{T,VF,ZS,F,S}, ::MOI.NumberOfConstraints{VF,S}, -) where {T,VF,ZS,F,S} +)::Int64 where {T,VF,ZS,F,S} return 1 end @@ -217,7 +217,7 @@ function concrete_bridge_type( end # Attributes, Bridge acting as a model -MOI.get(b::ScalarSlackBridge, ::MOI.NumberOfVariables) = 1 +MOI.get(b::ScalarSlackBridge, ::MOI.NumberOfVariables)::Int64 = 1 MOI.get(b::ScalarSlackBridge, ::MOI.ListOfVariableIndices) = [b.slack] # Attributes, Bridge acting as a constraint @@ -332,7 +332,8 @@ function concrete_bridge_type( end # Attributes, Bridge acting as a model -MOI.get(b::VectorSlackBridge, ::MOI.NumberOfVariables) = length(b.slack) +MOI.get(b::VectorSlackBridge, ::MOI.NumberOfVariables)::Int64 = length(b.slack) + MOI.get(b::VectorSlackBridge, ::MOI.ListOfVariableIndices) = copy(b.slack) # Attributes, Bridge acting as a constraint diff --git a/src/Bridges/Constraint/soc_to_nonconvex_quad.jl b/src/Bridges/Constraint/soc_to_nonconvex_quad.jl index e58832f39b..be3c0a9d53 100644 --- a/src/Bridges/Constraint/soc_to_nonconvex_quad.jl +++ b/src/Bridges/Constraint/soc_to_nonconvex_quad.jl @@ -172,7 +172,7 @@ end function MOI.get( ::AbstractSOCtoNonConvexQuadBridge{T}, ::MOI.NumberOfConstraints{MOI.ScalarQuadraticFunction{T},MOI.LessThan{T}}, -) where {T} +)::Int64 where {T} return 1 end @@ -189,7 +189,7 @@ end function MOI.get( bridge::AbstractSOCtoNonConvexQuadBridge{T}, ::MOI.NumberOfConstraints{MOI.ScalarAffineFunction{T},MOI.GreaterThan{T}}, -) where {T} +)::Int64 where {T} return length(bridge.var_pos) end diff --git a/src/Bridges/Constraint/square.jl b/src/Bridges/Constraint/square.jl index 4604d9963c..2f80b7ea11 100644 --- a/src/Bridges/Constraint/square.jl +++ b/src/Bridges/Constraint/square.jl @@ -167,14 +167,14 @@ end function MOI.get( ::SquareBridge{T,F,G,TT}, ::MOI.NumberOfConstraints{F,TT}, -) where {T,F,G,TT} +)::Int64 where {T,F,G,TT} return 1 end function MOI.get( bridge::SquareBridge{T,F,G}, ::MOI.NumberOfConstraints{G,MOI.EqualTo{T}}, -) where {T,F,G} +)::Int64 where {T,F,G} return length(bridge.sym) end diff --git a/src/Bridges/Constraint/vectorize.jl b/src/Bridges/Constraint/vectorize.jl index 8baf067467..0ec7f28449 100644 --- a/src/Bridges/Constraint/vectorize.jl +++ b/src/Bridges/Constraint/vectorize.jl @@ -74,7 +74,7 @@ end function MOI.get( ::VectorizeBridge{T,F,S}, ::MOI.NumberOfConstraints{F,S}, -) where {T,F,S} +)::Int64 where {T,F,S} return 1 end diff --git a/src/Bridges/Constraint/zero_one.jl b/src/Bridges/Constraint/zero_one.jl index d7677b2356..230dc69dcb 100644 --- a/src/Bridges/Constraint/zero_one.jl +++ b/src/Bridges/Constraint/zero_one.jl @@ -101,16 +101,16 @@ end # Attributes, Bridge acting as a model function MOI.get( - bridge::ZeroOneBridge{T}, + ::ZeroOneBridge{T}, ::MOI.NumberOfConstraints{MOI.SingleVariable,MOI.Interval{T}}, -) where {T} +)::Int64 where {T} return 1 end function MOI.get( - bridge::ZeroOneBridge, + ::ZeroOneBridge, ::MOI.NumberOfConstraints{MOI.SingleVariable,MOI.Integer}, -) +)::Int64 return 1 end diff --git a/src/Bridges/Objective/functionize.jl b/src/Bridges/Objective/functionize.jl index 1e0590d19f..2d5e705861 100644 --- a/src/Bridges/Objective/functionize.jl +++ b/src/Bridges/Objective/functionize.jl @@ -38,9 +38,7 @@ function MOIB.set_objective_function_type( end # Attributes, Bridge acting as a model -function MOI.get(::FunctionizeBridge, ::MOI.NumberOfVariables) - return 0 -end +MOI.get(::FunctionizeBridge, ::MOI.NumberOfVariables)::Int64 = 0 function MOI.get(::FunctionizeBridge, ::MOI.ListOfVariableIndices) return MOI.VariableIndex[] diff --git a/src/Bridges/Objective/slack.jl b/src/Bridges/Objective/slack.jl index 33259bdfc2..a47af4b502 100644 --- a/src/Bridges/Objective/slack.jl +++ b/src/Bridges/Objective/slack.jl @@ -78,9 +78,7 @@ function concrete_bridge_type( end # Attributes, Bridge acting as a model -function MOI.get(::SlackBridge, ::MOI.NumberOfVariables) - return 1 -end +MOI.get(::SlackBridge, ::MOI.NumberOfVariables)::Int64 = 1 function MOI.get(bridge::SlackBridge, ::MOI.ListOfVariableIndices) return [bridge.slack] @@ -89,7 +87,7 @@ end function MOI.get( bridge::SlackBridge{T,F}, ::MOI.NumberOfConstraints{F,S}, -) where {T,F,S<:Union{MOI.GreaterThan{T},MOI.LessThan{T}}} +)::Int64 where {T,F,S<:Union{MOI.GreaterThan{T},MOI.LessThan{T}}} return bridge.constraint isa MOI.ConstraintIndex{F,S} ? 1 : 0 end diff --git a/src/Bridges/Variable/free.jl b/src/Bridges/Variable/free.jl index e96e39d608..33569a016d 100644 --- a/src/Bridges/Variable/free.jl +++ b/src/Bridges/Variable/free.jl @@ -34,7 +34,7 @@ function MOIB.added_constraint_types(::Type{FreeBridge{T}}) where {T} end # Attributes, Bridge acting as a model -function MOI.get(bridge::FreeBridge, ::MOI.NumberOfVariables) +function MOI.get(bridge::FreeBridge, ::MOI.NumberOfVariables)::Int64 return length(bridge.variables) end @@ -45,7 +45,7 @@ end function MOI.get( ::FreeBridge, ::MOI.NumberOfConstraints{MOI.VectorOfVariables,MOI.Nonnegatives}, -) +)::Int64 return 1 end diff --git a/src/Bridges/Variable/rsoc_to_psd.jl b/src/Bridges/Variable/rsoc_to_psd.jl index 8825c2960c..cc1646cab8 100644 --- a/src/Bridges/Variable/rsoc_to_psd.jl +++ b/src/Bridges/Variable/rsoc_to_psd.jl @@ -89,7 +89,7 @@ function MOIB.added_constraint_types(::Type{RSOCtoPSDBridge{T}}) where {T} end # Attributes, Bridge acting as a model -function MOI.get(bridge::RSOCtoPSDBridge, ::MOI.NumberOfVariables) +function MOI.get(bridge::RSOCtoPSDBridge, ::MOI.NumberOfVariables)::Int64 return length(bridge.variables) end @@ -100,8 +100,12 @@ end function MOI.get( bridge::RSOCtoPSDBridge, ::MOI.NumberOfConstraints{MOI.VectorOfVariables,S}, -) where {S<:Union{MOI.PositiveSemidefiniteConeTriangle,MOI.Nonnegatives}} - return bridge.psd isa MOI.ConstraintIndex{MOI.VectorOfVariables,S} ? 1 : 0 +)::Int64 where {S<:Union{MOI.PositiveSemidefiniteConeTriangle,MOI.Nonnegatives}} + if bridge.psd isa MOI.ConstraintIndex{MOI.VectorOfVariables,S} + return 1 + else + return 0 + end end function MOI.get( @@ -118,7 +122,7 @@ end function MOI.get( bridge::RSOCtoPSDBridge{T}, ::MOI.NumberOfConstraints{MOI.SingleVariable,MOI.EqualTo{T}}, -) where {T} +)::Int64 where {T} return length(bridge.off_diag) end @@ -132,7 +136,7 @@ end function MOI.get( bridge::RSOCtoPSDBridge{T}, ::MOI.NumberOfConstraints{MOI.ScalarAffineFunction{T},MOI.EqualTo{T}}, -) where {T} +)::Int64 where {T} return length(bridge.diag) end diff --git a/src/Bridges/Variable/set_map.jl b/src/Bridges/Variable/set_map.jl index 0f86f7fa96..38896a632d 100644 --- a/src/Bridges/Variable/set_map.jl +++ b/src/Bridges/Variable/set_map.jl @@ -59,7 +59,7 @@ function MOIB.added_constraint_types(::Type{<:SetMapBridge}) end # Attributes, Bridge acting as a model -function MOI.get(bridge::SetMapBridge, ::MOI.NumberOfVariables) +function MOI.get(bridge::SetMapBridge, ::MOI.NumberOfVariables)::Int64 return length(bridge.variables) end @@ -70,14 +70,14 @@ end function MOI.get( ::SetMapBridge{T,S1}, ::MOI.NumberOfConstraints{MOI.SingleVariable,S1}, -) where {T,S1<:MOI.AbstractScalarSet} +)::Int64 where {T,S1<:MOI.AbstractScalarSet} return 1 end function MOI.get( ::SetMapBridge{T,S1}, ::MOI.NumberOfConstraints{MOI.VectorOfVariables,S1}, -) where {T,S1<:MOI.AbstractVectorSet} +)::Int64 where {T,S1<:MOI.AbstractVectorSet} return 1 end diff --git a/src/Bridges/Variable/vectorize.jl b/src/Bridges/Variable/vectorize.jl index 91bc403a73..5fad63075f 100644 --- a/src/Bridges/Variable/vectorize.jl +++ b/src/Bridges/Variable/vectorize.jl @@ -48,9 +48,7 @@ function concrete_bridge_type( end # Attributes, Bridge acting as a model -function MOI.get(::VectorizeBridge, ::MOI.NumberOfVariables) - return 1 -end +MOI.get(::VectorizeBridge, ::MOI.NumberOfVariables)::Int64 = 1 function MOI.get(bridge::VectorizeBridge, ::MOI.ListOfVariableIndices) return [bridge.variable] @@ -59,7 +57,7 @@ end function MOI.get( ::VectorizeBridge{T,S}, ::MOI.NumberOfConstraints{MOI.VectorOfVariables,S}, -) where {T,S} +)::Int64 where {T,S} return 1 end diff --git a/src/Bridges/Variable/zeros.jl b/src/Bridges/Variable/zeros.jl index 381fa3e2cc..63d1b6aff3 100644 --- a/src/Bridges/Variable/zeros.jl +++ b/src/Bridges/Variable/zeros.jl @@ -40,7 +40,7 @@ function MOIB.added_constraint_types(::Type{<:ZerosBridge}) end # Attributes, Bridge acting as a model -MOI.get(bridge::ZerosBridge, ::MOI.NumberOfVariables) = 0 +MOI.get(::ZerosBridge, ::MOI.NumberOfVariables)::Int64 = 0 function MOI.get(bridge::ZerosBridge, ::MOI.ListOfVariableIndices) return MOI.VariableIndex[] diff --git a/src/Bridges/bridge.jl b/src/Bridges/bridge.jl index 7c185aef95..8b84e530a3 100644 --- a/src/Bridges/bridge.jl +++ b/src/Bridges/bridge.jl @@ -34,7 +34,7 @@ end The number of constraints of the type `F`-in-`S` created by the bridge `b` in the model. """ -MOI.get(::AbstractBridge, ::MOI.NumberOfConstraints) = 0 +MOI.get(::AbstractBridge, ::MOI.NumberOfConstraints)::Int64 = 0 """ MOI.get(b::AbstractBridge, ::MOI.ListOfConstraintIndices{F, S}) where {F, S} diff --git a/src/Bridges/bridge_optimizer.jl b/src/Bridges/bridge_optimizer.jl index 9be95eefec..7da990a94b 100644 --- a/src/Bridges/bridge_optimizer.jl +++ b/src/Bridges/bridge_optimizer.jl @@ -726,7 +726,7 @@ function MOI.get( return list end -function MOI.get(b::AbstractBridgeOptimizer, attr::MOI.NumberOfVariables) +function MOI.get(b::AbstractBridgeOptimizer, attr::MOI.NumberOfVariables)::Int64 s = MOI.get(b.model, attr) + Variable.number_of_variables(Variable.bridges(b)) @@ -765,7 +765,7 @@ end function MOI.get( b::AbstractBridgeOptimizer, attr::MOI.NumberOfConstraints{F,S}, -) where {F,S} +)::Int64 where {F,S} s = get_all_including_bridged(b, attr) # The constraints counted in `s` may have been added by bridges for bridge in values(Variable.bridges(b)) diff --git a/src/DeprecatedTest/modellike.jl b/src/DeprecatedTest/modellike.jl index f617171bcb..dd5d50337b 100644 --- a/src/DeprecatedTest/modellike.jl +++ b/src/DeprecatedTest/modellike.jl @@ -401,7 +401,7 @@ abstract type BadModel <: MOI.ModelLike end function MOI.get(::BadModel, ::MOI.ListOfModelAttributesSet) return MOI.AbstractModelAttribute[] end -MOI.get(::BadModel, ::MOI.NumberOfVariables) = 1 +MOI.get(::BadModel, ::MOI.NumberOfVariables)::Int64 = 1 MOI.get(::BadModel, ::MOI.ListOfVariableIndices) = [MOI.VariableIndex(1)] function MOI.get(::BadModel, ::MOI.ListOfVariableAttributesSet) return MOI.AbstractVariableAttribute[] diff --git a/src/Test/Test.jl b/src/Test/Test.jl index f2e3a9e046..622071b2df 100644 --- a/src/Test/Test.jl +++ b/src/Test/Test.jl @@ -387,6 +387,60 @@ function _test_model_solution( return end +# TODO(odow): The following are helper functions for testing the value types of +# different attributes. The following attributes are not tested: +# BarrierIterations() +# CallbackNodeStatus() +# ConflictStatus() +# ConstraintBridgingCost() +# ConstraintConflictStatus() +# LazyConstraintCallback() +# NodeCount +# RelativeGap +# SimplexIterations +# VariableBridgingCost() + +function _test_attribute_value_type( + model::MOI.ModelLike, + attribute::Union{MOI.AbstractModelAttribute,MOI.AbstractOptimizerAttribute}, +) + T = MOI.attribute_value_type(attribute) + @static if VERSION < v"1.5" + @test MOI.get(model, attribute) isa T + else + @test @inferred(T, MOI.get(model, attribute)) isa T + end + return +end + +function _test_attribute_value_type( + model::MOI.ModelLike, + attribute::MOI.AbstractConstraintAttribute, + ci::MOI.ConstraintIndex, +) + T = MOI.attribute_value_type(attribute) + @static if VERSION < v"1.5" + @test MOI.get(model, attribute, ci) isa T + else + @test @inferred(T, MOI.get(model, attribute, ci)) isa T + end + return +end + +function _test_attribute_value_type( + model::MOI.ModelLike, + attribute::MOI.AbstractVariableAttribute, + x::MOI.VariableIndex, +) + T = MOI.attribute_value_type(attribute) + @static if VERSION < v"1.5" + @test MOI.get(model, attribute, x) isa T + else + @test @inferred(T, MOI.get(model, attribute, x)) isa T + end + return +end + ### ### Include all the test files! ### diff --git a/src/Test/test_attribute.jl b/src/Test/test_attribute.jl index 93cae893cc..bf9cf3afd1 100644 --- a/src/Test/test_attribute.jl +++ b/src/Test/test_attribute.jl @@ -14,6 +14,7 @@ function test_attribute_NumberThreads(model::MOI.AbstractOptimizer, ::Config) @test MOI.get(model, MOI.NumberOfThreads()) == 3 MOI.set(model, MOI.NumberOfThreads(), value) @test value == MOI.get(model, MOI.NumberOfThreads()) + _test_attribute_value_type(model, MOI.NumberOfThreads()) return end test_attribute_NumberThreads(::MOI.ModelLike, ::Config) = nothing @@ -41,7 +42,7 @@ function test_attribute_RawStatusString( @requires _supports(config, MOI.RawStatusString) MOI.add_variable(model) MOI.optimize!(model) - @test MOI.get(model, MOI.RawStatusString()) isa AbstractString + _test_attribute_value_type(model, MOI.RawStatusString()) return end test_attribute_RawStatusString(::MOI.ModelLike, ::Config) = nothing @@ -80,6 +81,7 @@ function test_attribute_Silent(model::MOI.AbstractOptimizer, ::Config) @test !value == MOI.get(model, MOI.Silent()) MOI.set(model, MOI.Silent(), value) @test value == MOI.get(model, MOI.Silent()) + _test_attribute_value_type(model, MOI.Silent()) return end test_attribute_Silent(::MOI.ModelLike, ::Config) = nothing @@ -100,7 +102,7 @@ Test that the [`MOI.SolverName`](@ref) attribute is implemented for `model`. """ function test_attribute_SolverName(model::MOI.AbstractOptimizer, config::Config) if _supports(config, MOI.SolverName) - @test MOI.get(model, MOI.SolverName()) isa AbstractString + _test_attribute_value_type(model, MOI.SolverName()) end return end @@ -120,6 +122,7 @@ function test_attribute_SolveTimeSec( MOI.add_variable(model) MOI.optimize!(model) @test MOI.get(model, MOI.SolveTimeSec()) >= 0.0 + _test_attribute_value_type(model, MOI.SolveTimeSec()) return end test_attribute_SolveTimeSec(::MOI.ModelLike, ::Config) = nothing @@ -151,6 +154,7 @@ function test_attribute_TimeLimitSec(model::MOI.AbstractOptimizer, ::Config) @test MOI.get(model, MOI.TimeLimitSec()) == 1.0 MOI.set(model, MOI.TimeLimitSec(), value) @test value == MOI.get(model, MOI.TimeLimitSec()) # Equality should hold + _test_attribute_value_type(model, MOI.TimeLimitSec()) return end test_attribute_TimeLimitSec(::MOI.ModelLike, ::Config) = nothing diff --git a/src/Test/test_basic_constraint.jl b/src/Test/test_basic_constraint.jl index 9bab161480..241ec7965f 100644 --- a/src/Test/test_basic_constraint.jl +++ b/src/Test/test_basic_constraint.jl @@ -135,6 +135,7 @@ function _basic_constraint_test_helper( @test MOI.get(model, MOI.NumberOfConstraints{F,S}()) == 0 c = MOI.add_constraint(model, constraint_function, set) @test MOI.get(model, MOI.NumberOfConstraints{F,S}()) == 1 + _test_attribute_value_type(model, MOI.NumberOfConstraints{F,S}()) ### ### Test MOI.is_valid ### @@ -157,6 +158,7 @@ function _basic_constraint_test_helper( @test MOI.supports(model, MOI.ConstraintName(), typeof(c)) MOI.set(model, MOI.ConstraintName(), c, "c") @test MOI.get(model, MOI.ConstraintName(), c) == "c" + _test_attribute_value_type(model, MOI.ConstraintName(), c) end end ### @@ -166,12 +168,15 @@ function _basic_constraint_test_helper( @test MOI.get(model, MOI.ConstraintFunction(), c) ≈ constraint_function @test MOI.get(model, MOI.CanonicalConstraintFunction(), c) ≈ constraint_function + _test_attribute_value_type(model, MOI.ConstraintFunction(), c) + _test_attribute_value_type(model, MOI.CanonicalConstraintFunction(), c) end ### ### Test MOI.ConstraintSet ### if _supports(config, MOI.ConstraintSet) @test MOI.get(model, MOI.ConstraintSet(), c) == set + _test_attribute_value_type(model, MOI.ConstraintSet(), c) end ### ### Test MOI.ListOfConstraintIndices diff --git a/src/Test/test_linear.jl b/src/Test/test_linear.jl index f71ea70f27..d1f62edeab 100644 --- a/src/Test/test_linear.jl +++ b/src/Test/test_linear.jl @@ -640,6 +640,8 @@ function test_linear_integration_2( @test MOI.get(model, MOI.VariableBasisStatus(), y) == MOI.NONBASIC_AT_LOWER @test MOI.get(model, MOI.ConstraintBasisStatus(), c) == MOI.NONBASIC + _test_attribute_value_type(model, MOI.ConstraintBasisStatus(), c) + _test_attribute_value_type(model, MOI.VariableBasisStatus(), x) end end end diff --git a/src/Test/test_model.jl b/src/Test/test_model.jl index 62d8cea500..e1334c1be2 100644 --- a/src/Test/test_model.jl +++ b/src/Test/test_model.jl @@ -139,6 +139,7 @@ Test that the default ObjectiveSense is FEASIBILITY_SENSE. """ function test_model_default_ObjectiveSense(model::MOI.ModelLike, ::Config) MOI.get(model, MOI.ObjectiveSense()) == MOI.FEASIBILITY_SENSE + _test_attribute_value_type(model, MOI.ObjectiveSense()) return end @@ -152,6 +153,7 @@ function test_model_default_TerminationStatus( ::Config, ) MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMIZE_NOT_CALLED + _test_attribute_value_type(model, MOI.TerminationStatus()) return end @@ -164,6 +166,7 @@ Test that the default PrimalStatus is NO_SOLUTION. """ function test_model_default_PrimalStatus(model::MOI.AbstractOptimizer, ::Config) MOI.get(model, MOI.PrimalStatus()) == MOI.NO_SOLUTION + _test_attribute_value_type(model, MOI.PrimalStatus()) return end @@ -176,6 +179,7 @@ Test that the default DualStatus is NO_SOLUTION. """ function test_model_default_DualStatus(model::MOI.AbstractOptimizer, ::Config) MOI.get(model, MOI.DualStatus()) == MOI.NO_SOLUTION + _test_attribute_value_type(model, MOI.DualStatus()) return end @@ -198,6 +202,7 @@ function test_model_VariableName(model::MOI.ModelLike, ::Config) @test MOI.get(model, MOI.VariableIndex, "x1") == x[2] MOI.set(model, MOI.VariableName(), x[1], "x1") @test_throws ErrorException MOI.get(model, MOI.VariableIndex, "x1") + _test_attribute_value_type(model, MOI.VariableName(), x[1]) return end @@ -265,6 +270,7 @@ function test_model_Name(model::MOI.ModelLike, ::Config) MOI.set(model, MOI.Name(), "Name2") @test MOI.Name() in MOI.get(model, MOI.ListOfModelAttributesSet()) @test MOI.get(model, MOI.Name()) == "Name2" + _test_attribute_value_type(model, MOI.Name()) return end diff --git a/src/Test/test_objective.jl b/src/Test/test_objective.jl index 674d2087de..fd22b1303d 100644 --- a/src/Test/test_objective.jl +++ b/src/Test/test_objective.jl @@ -73,6 +73,8 @@ function test_objective_get_ObjectiveFunction_ScalarAffineFunction( MOI.ObjectiveFunction{MOI.ScalarQuadraticFunction{Float64}}(), ) @test convert(MOI.ScalarAffineFunction{Float64}, quad_obj_fun) ≈ f + _test_attribute_value_type(model, MOI.ObjectiveFunctionType()) + _test_attribute_value_type(model, obj_attr) return end @@ -188,6 +190,11 @@ function test_objective_ObjectiveFunction_SingleVariable( ) MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) c = MOI.add_constraint(model, MOI.SingleVariable(x), MOI.GreaterThan(1.0)) + _test_attribute_value_type(model, MOI.ObjectiveFunctionType()) + _test_attribute_value_type( + model, + MOI.ObjectiveFunction{MOI.SingleVariable}(), + ) _test_model_solution( model, config; diff --git a/src/Test/test_solve.jl b/src/Test/test_solve.jl index 99b47f5c64..b9c6acac2c 100644 --- a/src/Test/test_solve.jl +++ b/src/Test/test_solve.jl @@ -332,7 +332,7 @@ end """ test_solve_result_index(model::MOI.ModelLike, config::Config) -Test that various attributess implement `.result_index` correctly. +Test that various attributes implement `.result_index` correctly. """ function test_solve_result_index(model::MOI.ModelLike, config::Config) @requires _supports(config, MOI.optimize!) @@ -348,6 +348,7 @@ function test_solve_result_index(model::MOI.ModelLike, config::Config) ) MOI.optimize!(model) result_count = MOI.get(model, MOI.ResultCount()) + _test_attribute_value_type(model, MOI.ResultCount()) function result_err(attr) return MOI.ResultIndexBoundsError{typeof(attr)}(attr, result_count) end diff --git a/src/Test/test_variable.jl b/src/Test/test_variable.jl index 43bcc236e7..7bff4366ad 100644 --- a/src/Test/test_variable.jl +++ b/src/Test/test_variable.jl @@ -7,6 +7,7 @@ function test_variable_add_variable(model::MOI.ModelLike, ::Config) @test MOI.get(model, MOI.NumberOfVariables()) == 0 v = MOI.add_variable(model) @test MOI.get(model, MOI.NumberOfVariables()) == 1 + _test_attribute_value_type(model, MOI.NumberOfVariables()) return end diff --git a/src/Utilities/cachingoptimizer.jl b/src/Utilities/cachingoptimizer.jl index 495c5905ba..b9844c61db 100644 --- a/src/Utilities/cachingoptimizer.jl +++ b/src/Utilities/cachingoptimizer.jl @@ -807,7 +807,7 @@ function MOI.get(model::CachingOptimizer, attr::MOI.AbstractModelAttribute) end return map_indices( model.optimizer_to_model_map, - MOI.get(model.optimizer, attr), + MOI.get(model.optimizer, attr)::MOI.attribute_value_type(attr), ) else return MOI.get(model.model_cache, attr) @@ -848,7 +848,11 @@ function MOI.get( end return map_indices( model.optimizer_to_model_map, - MOI.get(model.optimizer, attr, model.model_to_optimizer_map[index]), + MOI.get( + model.optimizer, + attr, + model.model_to_optimizer_map[index], + )::MOI.attribute_value_type(attr), ) else return MOI.get(model.model_cache, attr, index) @@ -872,7 +876,7 @@ function MOI.get( model.optimizer, attr, map(index -> model.model_to_optimizer_map[index], indices), - ), + )::Vector{<:MOI.attribute_value_type(attr)}, ) else return MOI.get(model.model_cache, attr, indices) @@ -941,7 +945,7 @@ function MOI.get(model::CachingOptimizer, attr::MOI.AbstractOptimizerAttribute) end return map_indices( model.optimizer_to_model_map, - MOI.get(model.optimizer, attr), + MOI.get(model.optimizer, attr)::MOI.attribute_value_type(attr), ) end @@ -984,7 +988,7 @@ function MOI.get( @assert m.state == ATTACHED_OPTIMIZER return map_indices( m.optimizer_to_model_map, - MOI.get(m.optimizer, attr.attr), + MOI.get(m.optimizer, attr.attr)::MOI.attribute_value_type(attr.attr), ) end @@ -998,7 +1002,11 @@ function MOI.get( @assert m.state == ATTACHED_OPTIMIZER return map_indices( m.optimizer_to_model_map, - MOI.get(m.optimizer, attr.attr, m.model_to_optimizer_map[idx]), + MOI.get( + m.optimizer, + attr.attr, + m.model_to_optimizer_map[idx], + )::MOI.attribute_value_type(attr.attr), ) end @@ -1016,7 +1024,7 @@ function MOI.get( m.optimizer, attr.attr, getindex.(m.model_to_optimizer_map, idx), - ), + )::Vector{<:MOI.attribute_value_type(attr.attr)}, ) end diff --git a/src/Utilities/functions.jl b/src/Utilities/functions.jl index 16095898fa..9dc87b2103 100644 --- a/src/Utilities/functions.jl +++ b/src/Utilities/functions.jl @@ -63,7 +63,7 @@ function eval_term(varval::Function, t::MOI.ScalarQuadraticTerm) end """ - map_indices(index_map::Function, x) + map_indices(index_map::Function, x::X)::X where {X} Substitute any [`MOI.VariableIndex`](@ref) (resp. [`MOI.ConstraintIndex`](@ref)) in `x` by the [`MOI.VariableIndex`](@ref) (resp. [`MOI.ConstraintIndex`](@ref)) @@ -77,11 +77,17 @@ submittable value. function map_indices end """ - map_indices(variable_map::AbstractDict{T, T}, x) where {T <: MOI.Index} + map_indices( + variable_map::AbstractDict{T,T}, + x::X, + )::X where {T<:MOI.Index,X} Shortcut for `map_indices(vi -> variable_map[vi], x)`. """ -function map_indices(variable_map::AbstractDict{T,T}, x) where {T<:MOI.Index} +function map_indices( + variable_map::AbstractDict{T,T}, + x::X, +)::X where {T<:MOI.Index,X} return map_indices(vi -> variable_map[vi], x) end diff --git a/src/Utilities/model.jl b/src/Utilities/model.jl index 57e1a8014e..56a136cc73 100644 --- a/src/Utilities/model.jl +++ b/src/Utilities/model.jl @@ -485,7 +485,7 @@ end function MOI.get( model::AbstractModel, noc::MOI.NumberOfConstraints{F,S}, -) where {F,S} +)::Int64 where {F,S} return MOI.get(model.constraints, noc) end diff --git a/src/Utilities/struct_of_constraints.jl b/src/Utilities/struct_of_constraints.jl index 20e48e811f..e70559bdea 100644 --- a/src/Utilities/struct_of_constraints.jl +++ b/src/Utilities/struct_of_constraints.jl @@ -117,7 +117,7 @@ end function MOI.get( model::StructOfConstraints, attr::MOI.NumberOfConstraints{F,S}, -) where {F,S} +)::Int64 where {F,S} if !MOI.supports_constraint(model, F, S) return 0 end diff --git a/src/Utilities/universalfallback.jl b/src/Utilities/universalfallback.jl index 00a3b56f17..bf55f26307 100644 --- a/src/Utilities/universalfallback.jl +++ b/src/Utilities/universalfallback.jl @@ -349,7 +349,7 @@ end function MOI.get( uf::UniversalFallback, attr::MOI.NumberOfConstraints{MOI.SingleVariable,S}, -) where {S} +)::Int64 where {S} if MOI.supports_constraint(uf.model, MOI.SingleVariable, S) return MOI.get(uf.model, attr) elseif !haskey(uf.single_variable_constraints, S) @@ -362,7 +362,7 @@ end function MOI.get( uf::UniversalFallback, attr::MOI.NumberOfConstraints{F,S}, -) where {F,S} +)::Int64 where {F,S} return MOI.get(constraints(uf, F, S), attr) end diff --git a/src/Utilities/vector_bounds.jl b/src/Utilities/vector_bounds.jl index 4c7833fc8f..e6cc5a36b8 100644 --- a/src/Utilities/vector_bounds.jl +++ b/src/Utilities/vector_bounds.jl @@ -306,7 +306,7 @@ end function MOI.get( b::SingleVariableConstraints, ::MOI.NumberOfConstraints{MOI.SingleVariable,S}, -) where {S} +)::Int64 where {S} flag = _single_variable_flag(S) return count(mask -> !iszero(flag & mask), b.set_mask) end diff --git a/src/Utilities/vector_of_constraints.jl b/src/Utilities/vector_of_constraints.jl index 3d8df22c01..293c76ef16 100644 --- a/src/Utilities/vector_of_constraints.jl +++ b/src/Utilities/vector_of_constraints.jl @@ -124,7 +124,7 @@ end function MOI.get( v::VectorOfConstraints{F,S}, ::MOI.NumberOfConstraints{F,S}, -) where {F,S} +)::Int64 where {F,S} return length(v.constraints) end diff --git a/src/attributes.jl b/src/attributes.jl index 0f3f6fa838..758dab5981 100644 --- a/src/attributes.jl +++ b/src/attributes.jl @@ -47,6 +47,19 @@ const AnyAttribute = Union{ # embed it in a `Ref` Base.broadcastable(attribute::AnyAttribute) = Ref(attribute) +""" + attribute_value_type(attr::AnyAttribute) + +Given an attribute `attr`, return the type of value expected by [`get`](@ref), +or returned by [`set`](@ref). + +# Notes + + * Only implement this if it make sense to do so. If un-implemented, the default + is `Any`. +""" +attribute_value_type(::AnyAttribute) = Any + """ struct UnsupportedAttribute{AttrType} <: UnsupportedError attr::AttrType @@ -658,8 +671,11 @@ Returns a [`CallbackNodeStatusCode`](@ref) Enum. struct CallbackNodeStatus{CallbackDataType} <: AbstractOptimizerAttribute callback_data::CallbackDataType end + is_set_by_optimize(::CallbackNodeStatus) = true +attribute_value_type(::CallbackNodeStatus) = CallbackNodeStatusCode + ## Optimizer attributes """ @@ -676,6 +692,8 @@ An optimizer attribute for the string identifying the solver/optimizer. """ struct SolverName <: AbstractOptimizerAttribute end +attribute_value_type(::SolverName) = String + """ Silent() @@ -697,6 +715,8 @@ given. """ struct Silent <: AbstractOptimizerAttribute end +attribute_value_type(::Silent) = Bool + """ TimeLimitSec() @@ -706,6 +726,8 @@ to `nothing`, it deactivates the solver time limit. The default value is """ # TODO add a test checking if the solver returns TIME_LIMIT status when the time limit is hit struct TimeLimitSec <: AbstractOptimizerAttribute end +attribute_value_type(::TimeLimitSec) = Union{Nothing,Float64} + """ RawOptimizerAttribute(name::String) @@ -724,6 +746,8 @@ integers. The default value is `nothing`. """ struct NumberOfThreads <: AbstractOptimizerAttribute end +attribute_value_type(::NumberOfThreads) = Union{Nothing,Int} + ### Callbacks """ @@ -769,6 +793,8 @@ commonly called `callback_data`, that can be used for instance in """ abstract type AbstractCallback <: AbstractModelAttribute end +attribute_value_type(::AbstractCallback) = Function + """ LazyConstraintCallback() <: AbstractCallback @@ -878,6 +904,10 @@ of `""` if not set`. """ struct Name <: AbstractModelAttribute end +attribute_value_type(::Name) = String + +@enum OptimizationSense MIN_SENSE MAX_SENSE FEASIBILITY_SENSE + """ ObjectiveSense() @@ -887,7 +917,7 @@ must be an `OptimizationSense`: `MIN_SENSE`, `MAX_SENSE`, or """ struct ObjectiveSense <: AbstractModelAttribute end -@enum OptimizationSense MIN_SENSE MAX_SENSE FEASIBILITY_SENSE +attribute_value_type(::ObjectiveSense) = OptimizationSense """ NumberOfVariables() @@ -896,6 +926,8 @@ A model attribute for the number of variables in the model. """ struct NumberOfVariables <: AbstractModelAttribute end +attribute_value_type(::NumberOfVariables) = Int64 + """ ListOfVariableIndices() @@ -921,6 +953,8 @@ A model attribute for the number of constraints of the type `F`-in-`S` present i """ struct NumberOfConstraints{F,S} <: AbstractModelAttribute end +attribute_value_type(::NumberOfConstraints) = Int64 + """ ListOfConstraintTypesPresent() @@ -942,6 +976,8 @@ it has non-integer coefficient and `F` is `ScalarAffineFunction{Int}`. """ struct ObjectiveFunction{F<:AbstractScalarFunction} <: AbstractModelAttribute end +attribute_value_type(::ObjectiveFunction{F}) where {F} = F + """ ObjectiveFunctionType() @@ -960,6 +996,8 @@ attr = MOI.get(model, MOI.ObjectiveFunctionType()) """ struct ObjectiveFunctionType <: AbstractModelAttribute end +attribute_value_type(::ObjectiveFunctionType) = Type{<:AbstractFunction} + ## Optimizer attributes """ @@ -1001,6 +1039,8 @@ A model attribute for the final relative optimality gap, defined as ``\\frac{|b- """ struct RelativeGap <: AbstractModelAttribute end +attribute_value_type(::RelativeGap) = Float64 + """ SolveTimeSec() @@ -1008,6 +1048,8 @@ A model attribute for the total elapsed solution time (in seconds) as reported b """ struct SolveTimeSec <: AbstractModelAttribute end +attribute_value_type(::SolveTimeSec) = Float64 + @deprecate SolveTime SolveTimeSec """ @@ -1018,6 +1060,8 @@ In particular, for a mixed-integer program (MIP), the total simplex iterations f """ struct SimplexIterations <: AbstractModelAttribute end +attribute_value_type(::SimplexIterations) = Int64 + """ BarrierIterations() @@ -1025,6 +1069,8 @@ A model attribute for the cumulative number of barrier iterations while solving """ struct BarrierIterations <: AbstractModelAttribute end +attribute_value_type(::BarrierIterations) = Int64 + """ NodeCount() @@ -1032,6 +1078,8 @@ A model attribute for the total number of branch-and-bound nodes explored while """ struct NodeCount <: AbstractModelAttribute end +attribute_value_type(::NodeCount) = Int64 + """ RawSolver() @@ -1069,6 +1117,8 @@ results may be alternate certificates, or infeasible points. """ struct ResultCount <: AbstractModelAttribute end +attribute_value_type(::ResultCount) = Int + """ ConflictStatusCode @@ -1098,6 +1148,8 @@ refiner stopped when computing the conflict. """ struct ConflictStatus <: AbstractModelAttribute end +attribute_value_type(::ConflictStatus) = ConflictStatusCode + ## Variable attributes """ @@ -1119,6 +1171,8 @@ set`. """ struct VariableName <: AbstractVariableAttribute end +attribute_value_type(::VariableName) = String + """ VariablePrimalStart() @@ -1199,6 +1253,8 @@ struct VariableBasisStatus <: AbstractVariableAttribute VariableBasisStatus(result_index::Int = 1) = new(result_index) end +attribute_value_type(::VariableBasisStatus) = BasisStatusCode + ## Constraint attributes """ @@ -1232,6 +1288,8 @@ You should _not_ implement `ConstraintName` for `SingleVariable` constraints. """ struct ConstraintName <: AbstractConstraintAttribute end +attribute_value_type(::ConstraintName) = String + """ SingleVariableConstraintNameError() @@ -1325,6 +1383,8 @@ struct ConstraintBasisStatus <: AbstractConstraintAttribute ConstraintBasisStatus(result_index::Int = 1) = new(result_index) end +attribute_value_type(::ConstraintBasisStatus) = BasisStatusCode + function get_fallback( ::ModelLike, ::ConstraintBasisStatus, @@ -1356,6 +1416,8 @@ then it returns the function stored internally instead of a copy. """ struct CanonicalConstraintFunction <: AbstractConstraintAttribute end +attribute_value_type(::CanonicalConstraintFunction) = AbstractFunction + function get_fallback( model::ModelLike, ::CanonicalConstraintFunction, @@ -1384,6 +1446,8 @@ It is guaranteed to be equivalent but not necessarily identical to the function """ struct ConstraintFunction <: AbstractConstraintAttribute end +attribute_value_type(::ConstraintFunction) = AbstractFunction + function throw_set_error_fallback( ::ModelLike, attr::ConstraintFunction, @@ -1415,6 +1479,8 @@ A constraint attribute for the `AbstractSet` object used to define the constrain """ struct ConstraintSet <: AbstractConstraintAttribute end +attribute_value_type(::ConstraintSet) = AbstractSet + function throw_set_error_fallback( ::ModelLike, attr::ConstraintSet, @@ -1468,13 +1534,11 @@ in the conflict. Its type is [`ConflictParticipationStatusCode`](@ref). """ struct ConstraintConflictStatus <: AbstractConstraintAttribute end -## Termination status -""" - TerminationStatus() +function attribute_value_type(::ConstraintConflictStatus) + return ConflictParticipationStatusCode +end -A model attribute for the `TerminationStatusCode` explaining why the optimizer stopped. -""" -struct TerminationStatus <: AbstractModelAttribute end +## Termination status """ TerminationStatusCode @@ -1588,6 +1652,15 @@ This group of statuses means that something unexpected or problematic happened. OTHER_ERROR ) +""" + TerminationStatus() + +A model attribute for the `TerminationStatusCode` explaining why the optimizer stopped. +""" +struct TerminationStatus <: AbstractModelAttribute end + +attribute_value_type(::TerminationStatus) = TerminationStatusCode + """ RawStatusString() @@ -1596,6 +1669,8 @@ stopped. """ struct RawStatusString <: AbstractModelAttribute end +attribute_value_type(::RawStatusString) = String + ## Result status """ @@ -1659,6 +1734,8 @@ struct PrimalStatus <: AbstractModelAttribute PrimalStatus(result_index::Int = 1) = new(result_index) end +attribute_value_type(::PrimalStatus) = ResultStatusCode + """ DualStatus(result_index::Int = 1) @@ -1675,8 +1752,13 @@ struct DualStatus <: AbstractModelAttribute DualStatus(result_index::Int = 1) = new(result_index) end +attribute_value_type(::DualStatus) = ResultStatusCode + # Cost of bridging constrained variable in S struct VariableBridgingCost{S<:AbstractSet} <: AbstractModelAttribute end + +attribute_value_type(::VariableBridgingCost) = Float64 + function get_fallback( model::ModelLike, ::VariableBridgingCost{S}, @@ -1693,6 +1775,9 @@ end # Cost of bridging F-in-S constraints struct ConstraintBridgingCost{F<:AbstractFunction,S<:AbstractSet} <: AbstractModelAttribute end + +attribute_value_type(::ConstraintBridgingCost) = Float64 + function get_fallback( model::ModelLike, ::ConstraintBridgingCost{F,S}, diff --git a/test/attributes.jl b/test/attributes.jl index c1d9983623..a75dfab24c 100644 --- a/test/attributes.jl +++ b/test/attributes.jl @@ -194,6 +194,21 @@ function test_UnsupportedSubmittable() ) end +function test_attribute_value_type() + @test MOI.attribute_value_type(MOI.CallbackNodeStatus(1)) == + MOI.CallbackNodeStatusCode + @test MOI.attribute_value_type(MOI.LazyConstraintCallback()) == Function + @test MOI.attribute_value_type(MOI.RelativeGap()) == Float64 + @test MOI.attribute_value_type(MOI.SimplexIterations()) == Int64 + @test MOI.attribute_value_type(MOI.BarrierIterations()) == Int64 + @test MOI.attribute_value_type(MOI.NodeCount()) == Int64 + @test MOI.attribute_value_type( + MOI.ConstraintBridgingCost{MOI.SingleVariable,MOI.ZeroOne}(), + ) == Float64 + @test MOI.attribute_value_type(MOI.VariableBridgingCost{MOI.ZeroOne}()) == + Float64 +end + function runtests() for name in names(@__MODULE__; all = true) if startswith("$name", "test_")