diff --git a/src/Bridges/Constraint/bridges/functionize.jl b/src/Bridges/Constraint/bridges/functionize.jl index f6f8540e30..ff98f04511 100644 --- a/src/Bridges/Constraint/bridges/functionize.jl +++ b/src/Bridges/Constraint/bridges/functionize.jl @@ -33,6 +33,15 @@ function MOI.get( return MOI.get(model, attr, bridge.constraint) end +function MOI.get( + model::MOI.ModelLike, + ::MOI.CanonicalConstraintFunction, + bridge::AbstractFunctionConversionBridge, +) + f = MOI.get(model, MOI.ConstraintFunction(), bridge) + return MOI.Utilities.canonical(f) +end + function MOI.supports( model::MOI.ModelLike, attr::MOI.AbstractConstraintAttribute, @@ -175,14 +184,6 @@ function MOI.delete(model::MOI.ModelLike, c::ScalarFunctionizeBridge) return end -function MOI.get( - model::MOI.ModelLike, - attr::MOI.CanonicalConstraintFunction, - b::ScalarFunctionizeBridge, -) - return convert(MOI.VariableIndex, MOI.get(model, attr, b.constraint)) -end - function MOI.get( model::MOI.ModelLike, attr::MOI.ConstraintFunction, @@ -305,15 +306,6 @@ function MOI.set( return end -function MOI.get( - model::MOI.ModelLike, - attr::MOI.CanonicalConstraintFunction, - b::VectorFunctionizeBridge, -) - f = MOI.get(model, attr, b.constraint) - return MOI.Utilities.convert_approx(MOI.VectorOfVariables, f) -end - function MOI.get( model::MOI.ModelLike, attr::MOI.ConstraintFunction, diff --git a/src/Bridges/Constraint/bridges/slack.jl b/src/Bridges/Constraint/bridges/slack.jl index 53df42f25c..8654c4836c 100644 --- a/src/Bridges/Constraint/bridges/slack.jl +++ b/src/Bridges/Constraint/bridges/slack.jl @@ -46,6 +46,32 @@ function MOI.get( return [bridge.slack_in_set] end +function MOI.get( + ::_AbstractSlackBridge{T,VF,S,F,S}, + ::MOI.NumberOfConstraints{VF,S}, +)::Int64 where {T,VF,F,S} + # This method is needed to resolve a possible ambiguity reported by + # Test.detect_ambiguities. It can't happen in practice because it would mean + # that the original set was the same as the slacked set. + return error( + "Internal error: this method should never be called because it " * + "represents and invalid state. Please open an issue to report.", + ) +end + +function MOI.get( + bridge::_AbstractSlackBridge{T,VF,S,F,S}, + ::MOI.ListOfConstraintIndices{F,S}, +) where {T,VF,S,F} + # This method is needed to resolve a possible ambiguity reported by + # Test.detect_ambiguities. It can't happen in practice because it would mean + # that the original set was the same as the slacked set. + return error( + "Internal error: this method should never be called because it " * + "represents and invalid state. Please open an issue to report.", + ) +end + function MOI.delete(model::MOI.ModelLike, bridge::_AbstractSlackBridge) MOI.delete(model, bridge.equality) MOI.delete(model, bridge.slack) diff --git a/src/Utilities/functions.jl b/src/Utilities/functions.jl index e384587147..a561829ca1 100644 --- a/src/Utilities/functions.jl +++ b/src/Utilities/functions.jl @@ -1408,7 +1408,7 @@ function Base.:+( MOI.ScalarQuadraticFunction{T}, }, g::T, -) where {T} +) where {T<:Number} return operate(+, T, f, g) end @@ -1419,7 +1419,7 @@ function Base.:+( MOI.ScalarAffineFunction{T}, MOI.ScalarQuadraticFunction{T}, }, -) where {T} +) where {T<:Number} return operate(+, T, f, g) end @@ -1452,7 +1452,7 @@ function Base.:+( MOI.VectorQuadraticFunction{T}, }, g::AbstractVector{T}, -) where {T} +) where {T<:Number} return operate(+, T, f, g) end @@ -1463,7 +1463,7 @@ function Base.:+( MOI.VectorAffineFunction{T}, MOI.VectorQuadraticFunction{T}, }, -) where {T} +) where {T<:Number} return operate(+, T, f, g) end @@ -1503,7 +1503,7 @@ function Base.:-( MOI.VectorQuadraticFunction{T}, }, g::T, -) where {T} +) where {T<:Number} return operate(-, T, f, g) end @@ -1517,7 +1517,7 @@ function Base.:-( MOI.VectorAffineFunction{T}, MOI.VectorQuadraticFunction{T}, }, -) where {T} +) where {T<:Number} return operate(-, T, f, g) end @@ -1550,7 +1550,7 @@ function Base.:-( MOI.VectorQuadraticFunction{T}, }, g::AbstractVector{T}, -) where {T} +) where {T<:Number} return operate(-, T, f, g) end @@ -1561,7 +1561,7 @@ function Base.:-( MOI.VectorAffineFunction{T}, MOI.VectorQuadraticFunction{T}, }, -) where {T} +) where {T<:Number} return operate(-, T, f, g) end @@ -1616,13 +1616,13 @@ end # https://github.com/JuliaLang/julia/pull/33205 function Base.:*( f::Union{ - MOI.ScalarAffineFunction, - MOI.ScalarQuadraticFunction, - MOI.VectorAffineFunction, - MOI.VectorQuadraticFunction, + MOI.ScalarAffineFunction{T}, + MOI.ScalarQuadraticFunction{T}, + MOI.VectorAffineFunction{T}, + MOI.VectorQuadraticFunction{T}, }, g::Bool, -) +) where {T<:Number} if g return MA.copy_if_mutable(f) else @@ -1659,34 +1659,6 @@ function Base.:*( return g * f end -# !!! warning -# MathOptInterface includes these methods to support coefficient types which -# are not subtypes of `Number`. We shoud consider removing them in MOI v2.0. - -function Base.:*( - f::Union{ - MOI.ScalarAffineFunction{T}, - MOI.ScalarQuadraticFunction{T}, - MOI.VectorAffineFunction{T}, - MOI.VectorQuadraticFunction{T}, - }, - g::T, -) where {T} - return operate_coefficients(Base.Fix2(*, g), f) -end - -function Base.:*( - f::T, - g::Union{ - MOI.ScalarAffineFunction{T}, - MOI.ScalarQuadraticFunction{T}, - MOI.VectorAffineFunction{T}, - MOI.VectorQuadraticFunction{T}, - }, -) where {T} - return g * f -end - ### Base.:/ function Base.:/( @@ -1697,7 +1669,7 @@ function Base.:/( MOI.VectorQuadraticFunction{T}, }, g::T, -) where {T} +) where {T<:Number} return operate(/, T, f, g) end @@ -1732,8 +1704,8 @@ end ### LinearAlgebra LinearAlgebra.dot(f::ScalarLike, g::ScalarLike) = f * g -LinearAlgebra.dot(α::T, func::TypedLike{T}) where {T} = α * func -LinearAlgebra.dot(func::TypedLike{T}, α::T) where {T} = func * α +LinearAlgebra.dot(α::T, func::TypedLike{T}) where {T<:Number} = α * func +LinearAlgebra.dot(func::TypedLike{T}, α::T) where {T<:Number} = func * α LinearAlgebra.adjoint(f::ScalarLike) = f LinearAlgebra.transpose(f::ScalarLike) = f LinearAlgebra.symmetric_type(::Type{F}) where {F<:ScalarLike} = F @@ -2254,9 +2226,16 @@ function Base.promote_rule( end function Base.promote_rule( - F::Type{<:Union{MOI.ScalarAffineFunction,MOI.ScalarQuadraticFunction}}, + F::Type{MOI.ScalarAffineFunction{T}}, ::Type{MOI.VariableIndex}, -) +) where {T} + return F +end + +function Base.promote_rule( + F::Type{MOI.ScalarQuadraticFunction{T}}, + ::Type{MOI.VariableIndex}, +) where {T} return F end diff --git a/src/Utilities/mutable_arithmetics.jl b/src/Utilities/mutable_arithmetics.jl index 0685508613..c8c8019db3 100644 --- a/src/Utilities/mutable_arithmetics.jl +++ b/src/Utilities/mutable_arithmetics.jl @@ -102,7 +102,7 @@ function MA.promote_operation( op::PROMOTE_IMPLEMENTED_OP, F::Type{T}, G::Type{<:TypedLike{T}}, -) where {T} +) where {T<:Number} return promote_operation(op, T, F, G) end @@ -110,7 +110,7 @@ function MA.promote_operation( op::PROMOTE_IMPLEMENTED_OP, F::Type{<:TypedLike{T}}, G::Type{T}, -) where {T} +) where {T<:Number} return promote_operation(op, T, F, G) end @@ -270,7 +270,7 @@ function _add_sub_affine_terms( α::T, f::MOI.VariableIndex, β::T, -) where {T} +) where {T<:Number} push!(terms, MOI.ScalarAffineTerm(op(α * β), f)) return end @@ -280,7 +280,7 @@ function _add_sub_affine_terms( terms::Vector{MOI.ScalarAffineTerm{T}}, f::MOI.VariableIndex, β::T, -) where {T} +) where {T<:Number} push!(terms, MOI.ScalarAffineTerm(op(β), f)) return end diff --git a/src/Utilities/operate.jl b/src/Utilities/operate.jl index 3042375ad4..51905cecc6 100644 --- a/src/Utilities/operate.jl +++ b/src/Utilities/operate.jl @@ -9,7 +9,7 @@ op::Function, ::Type{T}, args::Union{T,MOI.AbstractFunction}..., - )::MOI.AbstractFunction where {T} + )::MOI.AbstractFunction where {T<:Number} Returns an `MOI.AbstractFunction` representing the function resulting from the operation `op(args...)` on functions of coefficient type `T`. @@ -80,7 +80,7 @@ end ### 1a: operate(::typeof(+), ::Type{T}, ::F1) -operate(::typeof(+), ::Type{T}, f::MOI.AbstractFunction) where {T} = f +operate(::typeof(+), ::Type{T}, f::MOI.AbstractFunction) where {T<:Number} = f operate(::typeof(+), ::Type{T}, f::T) where {T<:Number} = f @@ -95,11 +95,16 @@ function operate( MOI.ScalarAffineFunction{T}, MOI.ScalarQuadraticFunction{T}, }, -) where {T} +) where {T<:Number} return operate(+, T, g, f) end -function operate(::typeof(+), ::Type{T}, f::MOI.VariableIndex, g::T) where {T} +function operate( + ::typeof(+), + ::Type{T}, + f::MOI.VariableIndex, + g::T, +) where {T<:Number} return MOI.ScalarAffineFunction{T}([MOI.ScalarAffineTerm(one(T), f)], g) end @@ -108,7 +113,7 @@ function operate( ::Type{T}, f::MOI.VariableIndex, g::MOI.VariableIndex, -) where {T} +) where {T<:Number} return MOI.ScalarAffineFunction{T}( [MOI.ScalarAffineTerm(one(T), f), MOI.ScalarAffineTerm(one(T), g)], zero(T), @@ -120,7 +125,7 @@ function operate( ::Type{T}, f::MOI.VariableIndex, g::Union{MOI.ScalarAffineFunction{T},MOI.ScalarQuadraticFunction{T}}, -) where {T} +) where {T<:Number} return operate(+, T, g, f) end @@ -129,7 +134,7 @@ function operate( ::Type{T}, f::MOI.ScalarAffineFunction{T}, g::Union{T,MOI.VariableIndex,MOI.ScalarAffineFunction{T}}, -) where {T} +) where {T<:Number} return operate!(+, T, copy(f), g) end @@ -138,7 +143,7 @@ function operate( ::Type{T}, f::MOI.ScalarAffineFunction{T}, g::MOI.ScalarQuadraticFunction{T}, -) where {T} +) where {T<:Number} return operate(+, T, g, f) end @@ -152,7 +157,7 @@ function operate( MOI.ScalarAffineFunction{T}, MOI.ScalarQuadraticFunction{T}, }, -) where {T} +) where {T<:Number} return operate!(+, T, copy(f), g) end @@ -167,7 +172,7 @@ function operate( MOI.ScalarQuadraticFunction{T}, MOI.ScalarNonlinearFunction, }, -) where {T} +) where {T<:Number} return MOI.ScalarNonlinearFunction(:+, Any[f, g]) end @@ -182,7 +187,7 @@ function operate( MOI.ScalarNonlinearFunction, }, g::MOI.ScalarNonlinearFunction, -) where {T} +) where {T<:Number} return MOI.ScalarNonlinearFunction(:+, Any[f, g]) end @@ -191,7 +196,7 @@ function operate( ::Type{T}, f::MOI.ScalarNonlinearFunction, g::MOI.ScalarNonlinearFunction, -) where {T} +) where {T<:Number} return MOI.ScalarNonlinearFunction(:+, Any[f, g]) end @@ -204,7 +209,7 @@ function operate( MOI.VectorAffineFunction{T}, MOI.VectorQuadraticFunction{T}, }, -) where {T} +) where {T<:Number} return operate(+, T, g, f) end @@ -213,7 +218,7 @@ function operate( ::Type{T}, f::MOI.VectorOfVariables, g::Vector{T}, -) where {T} +) where {T<:Number} d = MOI.output_dimension(f) @assert length(g) == d scalar_terms = MOI.ScalarAffineTerm.(one(T), f.variables) @@ -226,7 +231,7 @@ function operate( ::Type{T}, f::MOI.VectorOfVariables, g::MOI.VectorOfVariables, -) where {T} +) where {T<:Number} d = MOI.output_dimension(f) @assert MOI.output_dimension(g) == d fs = MOI.VectorAffineTerm.(1:d, MOI.ScalarAffineTerm.(one(T), f.variables)) @@ -239,7 +244,7 @@ function operate( ::Type{T}, f::MOI.VectorOfVariables, g::Union{MOI.VectorAffineFunction{T},MOI.VectorQuadraticFunction{T}}, -) where {T} +) where {T<:Number} return operate(+, T, g, f) end @@ -252,7 +257,7 @@ function operate( MOI.VectorOfVariables, MOI.VectorAffineFunction{T}, }, -) where {T} +) where {T<:Number} return operate!(+, T, copy(f), g) end @@ -261,7 +266,7 @@ function operate( ::Type{T}, f::MOI.VectorAffineFunction{T}, g::MOI.VectorQuadraticFunction{T}, -) where {T} +) where {T<:Number} return operate(+, T, g, f) end @@ -275,26 +280,30 @@ function operate( MOI.VectorAffineFunction{T}, MOI.VectorQuadraticFunction{T}, }, -) where {T} +) where {T<:Number} return operate!(+, T, copy(f), g) end ### 1c: operate(+, T, args...) -function operate(::typeof(+), ::Type{T}, f, g, h, args...) where {T} +function operate(::typeof(+), ::Type{T}, f, g, h, args...) where {T<:Number} return operate!(+, T, operate(+, T, f, g), h, args...) end ### 2a: operate(::typeof(-), ::Type{T}, ::F) -function operate(::typeof(-), ::Type{T}, f::MOI.VariableIndex) where {T} +function operate(::typeof(-), ::Type{T}, f::MOI.VariableIndex) where {T<:Number} return MOI.ScalarAffineFunction{T}( [MOI.ScalarAffineTerm(-one(T), f)], zero(T), ) end -function operate(::typeof(-), ::Type{T}, f::MOI.VectorOfVariables) where {T} +function operate( + ::typeof(-), + ::Type{T}, + f::MOI.VectorOfVariables, +) where {T<:Number} d = MOI.output_dimension(f) return MOI.VectorAffineFunction{T}( MOI.VectorAffineTerm.(1:d, MOI.ScalarAffineTerm.(-one(T), f.variables)), @@ -311,7 +320,7 @@ function operate( MOI.VectorAffineFunction{T}, MOI.VectorQuadraticFunction{T}, }, -) where {T} +) where {T<:Number} return operate_coefficients(-, f) end @@ -319,7 +328,7 @@ function operate( ::typeof(-), ::Type{T}, f::MOI.ScalarNonlinearFunction, -) where {T} +) where {T<:Number} if f.head == :- && length(f.args) == 1 # A simplification for -(-(f)) into f, but only if f is an SNF. if f.args[1] isa MOI.ScalarNonlinearFunction @@ -340,11 +349,16 @@ function operate( MOI.ScalarAffineFunction{T}, MOI.ScalarQuadraticFunction{T}, }, -) where {T} +) where {T<:Number} return operate!(+, T, operate(-, T, g), f) end -function operate(::typeof(-), ::Type{T}, f::MOI.VariableIndex, g::T) where {T} +function operate( + ::typeof(-), + ::Type{T}, + f::MOI.VariableIndex, + g::T, +) where {T<:Number} return MOI.ScalarAffineFunction{T}([MOI.ScalarAffineTerm(one(T), f)], -g) end @@ -353,7 +367,7 @@ function operate( ::Type{T}, f::MOI.VariableIndex, g::MOI.VariableIndex, -) where {T} +) where {T<:Number} return MOI.ScalarAffineFunction{T}( [MOI.ScalarAffineTerm(one(T), f), MOI.ScalarAffineTerm(-one(T), g)], zero(T), @@ -365,7 +379,7 @@ function operate( ::Type{T}, f::MOI.VariableIndex, g::Union{MOI.ScalarAffineFunction{T},MOI.ScalarQuadraticFunction{T}}, -) where {T} +) where {T<:Number} return operate!(+, T, operate(-, T, g), f) end @@ -374,7 +388,7 @@ function operate( ::Type{T}, f::MOI.ScalarAffineFunction{T}, g::Union{T,MOI.VariableIndex,MOI.ScalarAffineFunction{T}}, -) where {T} +) where {T<:Number} return operate!(-, T, copy(f), g) end @@ -383,7 +397,7 @@ function operate( ::Type{T}, f::MOI.ScalarAffineFunction{T}, g::MOI.ScalarQuadraticFunction{T}, -) where {T} +) where {T<:Number} return MOI.ScalarQuadraticFunction( operate_terms(-, g.quadratic_terms), vcat(f.terms, operate_terms(-, g.affine_terms)), @@ -401,7 +415,7 @@ function operate( MOI.ScalarAffineFunction{T}, MOI.ScalarQuadraticFunction{T}, }, -) where {T} +) where {T<:Number} return operate!(-, T, copy(f), g) end @@ -416,7 +430,7 @@ function operate( MOI.ScalarQuadraticFunction{T}, MOI.ScalarNonlinearFunction, }, -) where {T} +) where {T<:Number} return MOI.ScalarNonlinearFunction(:-, Any[f, g]) end @@ -431,7 +445,7 @@ function operate( MOI.ScalarNonlinearFunction, }, g::MOI.ScalarNonlinearFunction, -) where {T} +) where {T<:Number} return MOI.ScalarNonlinearFunction(:-, Any[f, g]) end @@ -440,7 +454,7 @@ function operate( ::Type{T}, f::MOI.ScalarNonlinearFunction, g::MOI.ScalarNonlinearFunction, -) where {T} +) where {T<:Number} return MOI.ScalarNonlinearFunction(:-, Any[f, g]) end @@ -453,7 +467,7 @@ function operate( MOI.VectorAffineFunction{T}, MOI.VectorQuadraticFunction{T}, }, -) where {T} +) where {T<:Number} return operate!(+, T, operate(-, T, g), f) end @@ -462,7 +476,7 @@ function operate( ::Type{T}, f::MOI.VectorOfVariables, g::AbstractVector{T}, -) where {T} +) where {T<:Number} d = MOI.output_dimension(f) @assert length(g) == d scalar_terms = MOI.ScalarAffineTerm.(one(T), f.variables) @@ -475,7 +489,7 @@ function operate( ::Type{T}, f::MOI.VectorOfVariables, g::MOI.VectorOfVariables, -) where {T} +) where {T<:Number} d = MOI.output_dimension(f) @assert MOI.output_dimension(g) == d fs = MOI.VectorAffineTerm.(1:d, MOI.ScalarAffineTerm.(one(T), f.variables)) @@ -488,7 +502,7 @@ function operate( ::Type{T}, f::MOI.VectorOfVariables, g::Union{MOI.VectorAffineFunction{T},MOI.VectorQuadraticFunction{T}}, -) where {T} +) where {T<:Number} return operate!(+, T, operate(-, T, g), f) end @@ -501,7 +515,7 @@ function operate( MOI.VectorOfVariables, MOI.VectorAffineFunction{T}, }, -) where {T} +) where {T<:Number} return operate!(-, T, copy(f), g) end @@ -510,7 +524,7 @@ function operate( ::Type{T}, f::MOI.VectorAffineFunction{T}, g::MOI.VectorQuadraticFunction{T}, -) where {T} +) where {T<:Number} return MOI.VectorQuadraticFunction( operate_terms(-, g.quadratic_terms), [f.terms; operate_terms(-, g.affine_terms)], @@ -528,13 +542,18 @@ function operate( MOI.VectorAffineFunction{T}, MOI.VectorQuadraticFunction{T}, }, -) where {T} +) where {T<:Number} return operate!(op, T, copy(f), g) end ### 3a: operate(::typeof(*), ::Type{T}, ::T, ::F) -function operate(::typeof(*), ::Type{T}, f::T, g::MOI.VariableIndex) where {T} +function operate( + ::typeof(*), + ::Type{T}, + f::T, + g::MOI.VariableIndex, +) where {T<:Number} return MOI.ScalarAffineFunction{T}([MOI.ScalarAffineTerm(f, g)], zero(T)) end @@ -543,7 +562,7 @@ function operate( ::Type{T}, f::T, g::MOI.VectorOfVariables, -) where {T} +) where {T<:Number} d = MOI.output_dimension(g) terms = MOI.VectorAffineTerm.(1:d, MOI.ScalarAffineTerm.(f, g.variables)) return MOI.VectorAffineFunction{T}(terms, zeros(T, d)) @@ -559,7 +578,7 @@ function operate( MOI.VectorAffineFunction{T}, MOI.VectorQuadraticFunction{T}, }, -) where {T} +) where {T<:Number} return operate!(*, T, copy(g), f) end @@ -568,7 +587,7 @@ function operate( ::Type{T}, f::T, g::MOI.ScalarNonlinearFunction, -) where {T} +) where {T<:Number} return MOI.ScalarNonlinearFunction(:*, Any[f, g]) end @@ -586,7 +605,7 @@ function operate( MOI.VectorQuadraticFunction{T}, }, g::T, -) where {T} +) where {T<:Number} return operate(*, T, g, f) end @@ -595,7 +614,7 @@ function operate( ::Type{T}, f::MOI.ScalarNonlinearFunction, g::T, -) where {T} +) where {T<:Number} return MOI.ScalarNonlinearFunction(:*, Any[f, g]) end @@ -606,7 +625,7 @@ function operate( ::Type{T}, f::MOI.VariableIndex, g::MOI.ScalarAffineFunction{T}, -) where {T} +) where {T<:Number} return operate(*, T, g, f) end @@ -615,7 +634,7 @@ function operate( ::Type{T}, f::MOI.ScalarAffineFunction{T}, g::MOI.ScalarAffineFunction{T}, -) where {T} +) where {T<:Number} nfterms = length(f.terms) ngterms = length(g.terms) quad_terms = Vector{MOI.ScalarQuadraticTerm{T}}(undef, nfterms * ngterms) @@ -654,7 +673,7 @@ function operate( ::Type{T}, f::MOI.VariableIndex, g::MOI.VariableIndex, -) where {T} +) where {T<:Number} return MOI.ScalarQuadraticFunction( [MOI.ScalarQuadraticTerm(f == g ? 2one(T) : one(T), f, g)], MOI.ScalarAffineTerm{T}[], @@ -667,7 +686,7 @@ function operate( ::Type{T}, f::MOI.ScalarAffineFunction{T}, g::MOI.VariableIndex, -) where {T} +) where {T<:Number} if iszero(f.constant) aff_terms = MOI.ScalarAffineTerm{T}[] else @@ -691,7 +710,7 @@ function operate( ::Type{T}, D::Diagonal{T}, func::MOI.VectorQuadraticFunction{T}, -) where {T} +) where {T<:Number} return MOI.VectorQuadraticFunction{T}( operate_terms(*, D, func.quadratic_terms), operate_terms(*, D, func.affine_terms), @@ -704,7 +723,7 @@ function operate( ::Type{T}, D::Diagonal{T}, func::MOI.VectorAffineFunction{T}, -) where {T} +) where {T<:Number} return MOI.VectorAffineFunction{T}( operate_terms(*, D, func.terms), operate(*, T, D, func.constants), @@ -716,7 +735,7 @@ function operate( ::Type{T}, D::Diagonal{T}, func::MOI.VectorOfVariables, -) where {T} +) where {T<:Number} return MOI.VectorAffineFunction{T}( MOI.VectorAffineTerm{T}[ MOI.VectorAffineTerm( @@ -733,7 +752,7 @@ function operate( ::Type{T}, D::Diagonal{T}, v::AbstractVector{T}, -) where {T} +) where {T<:Number} return T[D.diag[i] * v[i] for i in eachindex(v)] end @@ -744,7 +763,7 @@ function operate( ::Type{T}, f::Union{MOI.VariableIndex,MOI.VectorOfVariables}, g::T, -) where {T} +) where {T<:Number} return operate(*, T, inv(g), f) end @@ -758,7 +777,7 @@ function operate( MOI.VectorQuadraticFunction{T}, }, g::T, -) where {T} +) where {T<:Number} return operate!(/, T, copy(f), g) end @@ -767,12 +786,14 @@ function operate( ::Type{T}, f::MOI.ScalarNonlinearFunction, g::T, -) where {T} +) where {T<:Number} return MOI.ScalarNonlinearFunction(:/, Any[f, g]) end ### 5a: operate(::typeof(vcat), ::Type{T}, ::F...) +operate(::typeof(vcat), ::Type{T}) where {T<:Number} = T[] + function operate( ::typeof(vcat), ::Type{T}, @@ -785,7 +806,7 @@ function operate( ::typeof(vcat), ::Type{T}, f::Union{MOI.VariableIndex,MOI.VectorOfVariables}..., -) where {T} +) where {T<:Number} x = Vector{MOI.VariableIndex}(undef, sum(f -> output_dim(T, f), f)) fill_vector(x, T, 0, 0, fill_variables, output_dim, f...) return MOI.VectorOfVariables(x) @@ -802,7 +823,7 @@ function operate( MOI.VectorOfVariables, MOI.VectorAffineFunction{T}, }..., -) where {T} +) where {T<:Number} num_aterms = sum(f -> number_of_affine_terms(T, f), f) aterms = Vector{MOI.VectorAffineTerm{T}}(undef, num_aterms) fill_vector(aterms, T, 0, 0, fill_terms, number_of_affine_terms, f...) @@ -824,7 +845,7 @@ function operate( MOI.VectorAffineFunction{T}, MOI.VectorQuadraticFunction{T}, }..., -) where {T} +) where {T<:Number} num_aterms = sum(func -> number_of_affine_terms(T, func), f) aterms = Vector{MOI.VectorAffineTerm{T}}(undef, num_aterms) fill_vector(aterms, T, 0, 0, fill_terms, number_of_affine_terms, f...) @@ -838,11 +859,19 @@ end ### 6a: operate(::typeof(imag), ::Type{T}, ::F) -function operate(::typeof(imag), ::Type{T}, ::MOI.VariableIndex) where {T} +function operate( + ::typeof(imag), + ::Type{T}, + ::MOI.VariableIndex, +) where {T<:Number} return zero(MOI.ScalarAffineFunction{T}) end -function operate(::typeof(imag), ::Type{T}, f::MOI.VectorOfVariables) where {T} +function operate( + ::typeof(imag), + ::Type{T}, + f::MOI.VectorOfVariables, +) where {T<:Number} return zero_with_output_dimension( MOI.VectorAffineFunction{T}, MOI.output_dimension(f), @@ -867,7 +896,7 @@ end op::Function, ::Type{T}, args::Union{T,MOI.AbstractFunction}..., - )::MOI.AbstractFunction where {T} + )::MOI.AbstractFunction where {T<:Number} Returns an `MOI.AbstractFunction` representing the function resulting from the operation `op(args...)` on functions of coefficient type `T`. @@ -876,7 +905,7 @@ The first argument may be modified, in which case the return value is identical to the first argument. For operations which cannot be implemented in-place, this function returns a new object. """ -operate!(op, ::Type{T}, args...) where {T} = operate(op, T, args...) +operate!(op, ::Type{T}, args...) where {T<:Number} = operate(op, T, args...) ### 1a: operate!(::typeof(+), ::Type{T}, ::F1) @@ -887,7 +916,7 @@ function operate!( ::Type{T}, f::MOI.ScalarAffineFunction{T}, g::Union{T,MOI.VariableIndex,MOI.ScalarAffineFunction{T}}, -) where {T} +) where {T<:Number} return MA.operate!(+, f, g) end @@ -901,7 +930,7 @@ function operate!( MOI.ScalarAffineFunction{T}, MOI.ScalarQuadraticFunction{T}, }, -) where {T} +) where {T<:Number} return MA.operate!(+, f, g) end @@ -916,7 +945,7 @@ function operate!( MOI.ScalarQuadraticFunction{T}, MOI.ScalarNonlinearFunction, }, -) where {T} +) where {T<:Number} if f.head == :+ push!(f.args, g) return f @@ -929,7 +958,7 @@ function operate!( ::Type{T}, f::Union{MOI.VectorAffineFunction{T},MOI.VectorQuadraticFunction{T}}, g::AbstractVector{T}, -) where {T} +) where {T<:Number} @assert MOI.output_dimension(f) == length(g) f.constants .+= g return f @@ -940,7 +969,7 @@ function operate!( ::Type{T}, f::MOI.VectorAffineFunction{T}, g::MOI.VectorOfVariables, -) where {T} +) where {T<:Number} d = MOI.output_dimension(g) @assert MOI.output_dimension(f) == d append!( @@ -955,7 +984,7 @@ function operate!( ::Type{T}, f::MOI.VectorAffineFunction{T}, g::MOI.VectorAffineFunction{T}, -) where {T} +) where {T<:Number} append!(f.terms, g.terms) f.constants .+= g.constants return f @@ -966,7 +995,7 @@ function operate!( ::Type{T}, f::MOI.VectorQuadraticFunction{T}, g::MOI.VectorOfVariables, -) where {T} +) where {T<:Number} d = MOI.output_dimension(g) @assert MOI.output_dimension(f) == d append!( @@ -981,7 +1010,7 @@ function operate!( ::Type{T}, f::MOI.VectorQuadraticFunction{T}, g::MOI.VectorAffineFunction{T}, -) where {T} +) where {T<:Number} append!(f.affine_terms, g.terms) f.constants .+= g.constants return f @@ -992,7 +1021,7 @@ function operate!( ::Type{T}, f::MOI.VectorQuadraticFunction{T}, g::MOI.VectorQuadraticFunction{T}, -) where {T} +) where {T<:Number} append!(f.affine_terms, g.affine_terms) append!(f.quadratic_terms, g.quadratic_terms) f.constants .+= g.constants @@ -1001,7 +1030,7 @@ end ### 1c: operate!(+, T, args...) -function operate!(op::typeof(+), ::Type{T}, f, g, h, args...) where {T} +function operate!(op::typeof(+), ::Type{T}, f, g, h, args...) where {T<:Number} return operate!(+, T, operate!(op, T, f, g), h, args...) end @@ -1011,7 +1040,7 @@ function operate!( op::typeof(-), ::Type{T}, f::Union{MOI.ScalarAffineFunction{T},MOI.ScalarQuadraticFunction{T}}, -) where {T} +) where {T<:Number} return MA.operate!(-, f) end @@ -1022,7 +1051,7 @@ function operate!( ::Type{T}, f::MOI.ScalarAffineFunction{T}, g::Union{T,MOI.VariableIndex,MOI.ScalarAffineFunction{T}}, -) where {T} +) where {T<:Number} return MA.operate!(-, f, g) end @@ -1036,7 +1065,7 @@ function operate!( MOI.ScalarAffineFunction{T}, MOI.ScalarQuadraticFunction{T}, }, -) where {T} +) where {T<:Number} return MA.operate!(-, f, g) end @@ -1045,7 +1074,7 @@ function operate!( ::Type{T}, f::Union{MOI.VectorAffineFunction{T},MOI.VectorQuadraticFunction{T}}, g::AbstractVector{T}, -) where {T} +) where {T<:Number} @assert MOI.output_dimension(f) == length(g) f.constants .-= g return f @@ -1056,7 +1085,7 @@ function operate!( ::Type{T}, f::MOI.VectorAffineFunction{T}, g::MOI.VectorOfVariables, -) where {T} +) where {T<:Number} d = MOI.output_dimension(g) @assert MOI.output_dimension(f) == d append!( @@ -1071,7 +1100,7 @@ function operate!( ::Type{T}, f::MOI.VectorAffineFunction{T}, g::MOI.VectorAffineFunction{T}, -) where {T} +) where {T<:Number} append!(f.terms, operate_terms(-, g.terms)) f.constants .-= g.constants return f @@ -1082,7 +1111,7 @@ function operate!( ::Type{T}, f::MOI.VectorQuadraticFunction{T}, g::MOI.VectorOfVariables, -) where {T} +) where {T<:Number} d = MOI.output_dimension(g) @assert MOI.output_dimension(f) == d append!( @@ -1097,7 +1126,7 @@ function operate!( ::Type{T}, f::MOI.VectorQuadraticFunction{T}, g::MOI.VectorAffineFunction{T}, -) where {T} +) where {T<:Number} append!(f.affine_terms, operate_terms(-, g.terms)) f.constants .-= g.constants return f @@ -1108,7 +1137,7 @@ function operate!( ::Type{T}, f::MOI.VectorQuadraticFunction{T}, g::MOI.VectorQuadraticFunction{T}, -) where {T} +) where {T<:Number} append!(f.affine_terms, operate_terms(-, g.affine_terms)) append!(f.quadratic_terms, operate_terms(-, g.quadratic_terms)) f.constants .-= g.constants @@ -1135,7 +1164,7 @@ function operate!( ::Type{T}, f::MOI.ScalarNonlinearFunction, g::T, -) where {T} +) where {T<:Number} if f.head == :* push!(f.args, g) return f @@ -1148,7 +1177,7 @@ function operate!( ::Type{T}, f::Union{MOI.VectorAffineFunction{T},MOI.VectorQuadraticFunction{T}}, g::T, -) where {T} +) where {T<:Number} map_terms!(term -> operate_term(*, term, g), f) f.constants .*= g return f @@ -1165,7 +1194,7 @@ function operate!( ::Type{T}, f::Union{MOI.ScalarAffineFunction{T},MOI.ScalarQuadraticFunction{T}}, g::T, -) where {T} +) where {T<:Number} map_terms!(term -> operate_term(/, term, g), f) f.constant /= g return f @@ -1176,7 +1205,7 @@ function operate!( ::Type{T}, f::Union{MOI.VectorAffineFunction{T},MOI.VectorQuadraticFunction{T}}, g::T, -) where {T} +) where {T<:Number} map_terms!(term -> operate_term(/, term, g), f) f.constants ./= g return f @@ -1231,7 +1260,7 @@ function operate_term( MOI.VectorAffineTerm{T}, MOI.VectorQuadraticTerm{T}, }, -) where {T} +) where {T<:Number} return operate_term(Base.Fix1(*, f), g) end @@ -1246,7 +1275,7 @@ function operate_term( MOI.VectorQuadraticTerm{T}, }, g::T, -) where {T} +) where {T<:Number} return operate_term(*, g, f) end @@ -1283,7 +1312,7 @@ function operate_term( f::T, g::Union{MOI.ScalarAffineTerm{T},MOI.ScalarQuadraticTerm{T}}, h::T, -) where {T} +) where {T<:Number} return operate_term(Base.Fix1(*, f * h), g) end @@ -1322,7 +1351,7 @@ function operate_term( MOI.VectorQuadraticTerm{T}, }, g::T, -) where {T} +) where {T<:Number} return operate_term(Base.Fix2(/, g), f) end @@ -1440,7 +1469,7 @@ end output_index::Integer, f::Union{AbstractVector{T},MOI.AbstractVectorFunction} g::Union{T,MOI.AbstractScalarFunction}... - ) where {T} + ) where {T<:Number} Return an `MOI.AbstractVectorFunction` in which the scalar function in row `output_index` is the result of `op(f[output_index], g)`. @@ -1464,7 +1493,7 @@ function operate_output_index!( output_index::Integer, f::AbstractVector{T}, g::T, -) where {T} +) where {T<:Number} f[output_index] = op(f[output_index], g) return f end @@ -1475,7 +1504,7 @@ function operate_output_index!( output_index::Integer, f::MOI.VectorAffineFunction{T}, g::T, -) where {T} +) where {T<:Number} f.constants[output_index] = op(f.constants[output_index], g) return f end @@ -1486,7 +1515,7 @@ function operate_output_index!( output_index::Integer, f::MOI.VectorAffineFunction{T}, g::MOI.VariableIndex, -) where {T} +) where {T<:Number} push!( f.terms, MOI.VectorAffineTerm(output_index, MOI.ScalarAffineTerm(op(one(T)), g)), @@ -1500,7 +1529,7 @@ function operate_output_index!( output_index::Integer, f::MOI.VectorAffineFunction{T}, g::MOI.ScalarAffineFunction{T}, -) where {T} +) where {T<:Number} append!( f.terms, MOI.VectorAffineTerm.(output_index, operate_terms(op, g.terms)), @@ -1515,7 +1544,7 @@ function operate_output_index!( output_index::Integer, f::MOI.VectorQuadraticFunction{T}, g::T, -) where {T} +) where {T<:Number} f.constants[output_index] = op(f.constants[output_index], g) return f end @@ -1526,7 +1555,7 @@ function operate_output_index!( output_index::Integer, f::MOI.VectorQuadraticFunction{T}, g::MOI.VariableIndex, -) where {T} +) where {T<:Number} push!( f.affine_terms, MOI.VectorAffineTerm(output_index, MOI.ScalarAffineTerm(op(one(T)), g)), @@ -1540,7 +1569,7 @@ function operate_output_index!( output_index::Integer, f::MOI.VectorQuadraticFunction{T}, g::MOI.ScalarAffineFunction{T}, -) where {T} +) where {T<:Number} append!( f.affine_terms, MOI.VectorAffineTerm.(output_index, operate_terms(op, g.terms)), @@ -1555,7 +1584,7 @@ function operate_output_index!( output_index::Integer, f::MOI.VectorQuadraticFunction{T}, g::MOI.ScalarQuadraticFunction{T}, -) where {T} +) where {T<:Number} append!( f.affine_terms, MOI.VectorAffineTerm.(output_index, operate_terms(op, g.affine_terms)), diff --git a/src/Utilities/promote_operation.jl b/src/Utilities/promote_operation.jl index c91e320097..b47832c104 100644 --- a/src/Utilities/promote_operation.jl +++ b/src/Utilities/promote_operation.jl @@ -9,7 +9,7 @@ op::Function, ::Type{T}, ArgsTypes::Type{<:Union{T,AbstractVector{T},MOI.AbstractFunction}}..., - ) where {T} + ) where {T<:Number} Compute the return type of the call `operate(op, T, args...)`, where the types of the arguments `args` are `ArgsTypes`. @@ -62,7 +62,7 @@ function promote_operation( ::Type{T}, ::Type{T}, ::Type{T}, -) where {T} +) where {T<:Number} return T end @@ -159,7 +159,7 @@ function promote_operation( ::typeof(-), ::Type{T}, ::Type{MOI.VariableIndex}, -) where {T} +) where {T<:Number} return MOI.ScalarAffineFunction{T} end @@ -167,7 +167,7 @@ function promote_operation( ::typeof(-), ::Type{T}, ::Type{MOI.VectorOfVariables}, -) where {T} +) where {T<:Number} return MOI.VectorAffineFunction{T} end @@ -179,7 +179,7 @@ function promote_operation( ::Type{T}, ::Type{F}, ) where { - T, + T<:Number, F<:Union{ # T, # Stackoverflow if included MOI.ScalarAffineFunction{T}, @@ -198,7 +198,7 @@ function promote_operation( ::Type{T}, ::Type{T}, ::Type{T}, -) where {T} +) where {T<:Number} return T end @@ -207,7 +207,7 @@ function promote_operation( ::Type{T}, ::Type{T}, ::Type{MOI.VariableIndex}, -) where {T} +) where {T<:Number} return MOI.ScalarAffineFunction{T} end @@ -216,7 +216,7 @@ function promote_operation( ::Type{T}, ::Type{T}, ::Type{MOI.VectorOfVariables}, -) where {T} +) where {T<:Number} return MOI.VectorAffineFunction{T} end @@ -228,7 +228,7 @@ function promote_operation( ::Type{F}, ::Type{T}, ) where { - T, + T<:Number, F<:Union{ # T, # Stackoverflow if included MOI.ScalarAffineFunction{T}, @@ -247,7 +247,7 @@ function promote_operation( ::Type{T}, ::Type{MOI.VariableIndex}, ::Type{T}, -) where {T} +) where {T<:Number} return MOI.ScalarAffineFunction{T} end @@ -256,7 +256,7 @@ function promote_operation( ::Type{T}, ::Type{MOI.VectorOfVariables}, ::Type{T}, -) where {T} +) where {T<:Number} return MOI.VectorAffineFunction{T} end @@ -267,7 +267,7 @@ function promote_operation( ::Type{T}, ::Type{<:Union{MOI.VariableIndex,MOI.ScalarAffineFunction{T}}}, ::Type{<:Union{MOI.VariableIndex,MOI.ScalarAffineFunction{T}}}, -) where {T} +) where {T<:Number} return MOI.ScalarQuadraticFunction{T} end @@ -309,7 +309,7 @@ function promote_operation( ::Type{T}, ::Type{T}, ::Type{T}, -) where {T} +) where {T<:Number} return T end @@ -318,7 +318,7 @@ function promote_operation( ::Type{T}, ::Type{MOI.VariableIndex}, ::Type{T}, -) where {T} +) where {T<:Number} return MOI.ScalarAffineFunction{T} end @@ -327,7 +327,7 @@ function promote_operation( ::Type{T}, ::Type{MOI.VectorOfVariables}, ::Type{T}, -) where {T} +) where {T<:Number} return MOI.VectorAffineFunction{T} end @@ -336,16 +336,18 @@ end function promote_operation( ::typeof(vcat), ::Type{T}, + ::Type{<:Union{T,AbstractVector{T}}}, ::Type{<:Union{T,AbstractVector{T}}}..., -) where {T} +) where {T<:Number} return Vector{T} end function promote_operation( ::typeof(vcat), ::Type{T}, + ::Type{<:Union{MOI.VariableIndex,MOI.VectorOfVariables}}, ::Type{<:Union{MOI.VariableIndex,MOI.VectorOfVariables}}..., -) where {T} +) where {T<:Number} return MOI.VectorOfVariables end @@ -362,7 +364,7 @@ function promote_operation( MOI.VectorAffineFunction{T}, }, }..., -) where {T} +) where {T<:Number} return MOI.VectorAffineFunction{T} end @@ -381,7 +383,7 @@ function promote_operation( MOI.VectorQuadraticFunction{T}, }, }..., -) where {T} +) where {T<:Number} return MOI.VectorQuadraticFunction{T} end @@ -391,7 +393,7 @@ function promote_operation( ::typeof(imag), ::Type{T}, ::Type{MOI.VariableIndex}, -) where {T} +) where {T<:Number} return MOI.ScalarAffineFunction{T} end @@ -399,6 +401,6 @@ function promote_operation( ::typeof(imag), ::Type{T}, ::Type{MOI.VectorOfVariables}, -) where {T} +) where {T<:Number} return MOI.VectorAffineFunction{T} end diff --git a/src/Utilities/universalfallback.jl b/src/Utilities/universalfallback.jl index 1828016403..21842f53a5 100644 --- a/src/Utilities/universalfallback.jl +++ b/src/Utilities/universalfallback.jl @@ -641,7 +641,7 @@ function check_type_and_multiple_names( value::T, ::Nothing, name, -) where {T} +) where {T<:MOI.Index} return value end @@ -653,13 +653,13 @@ function check_type_and_multiple_names( ::Nothing, value::T, name, -) where {T} +) where {T<:MOI.Index} return value end check_type_and_multiple_names(::Type, ::Nothing, ::Any, name) = nothing -function check_type_and_multiple_names(T::Type, ::Any, ::Any, name) +function check_type_and_multiple_names(::Type{T}, ::Any, ::Any, name) where {T} return throw_multiple_name_error(T, name) end diff --git a/test/Bridges/Constraint/functionize.jl b/test/Bridges/Constraint/functionize.jl index 9b9bf70d2a..e99dfe0b84 100644 --- a/test/Bridges/Constraint/functionize.jl +++ b/test/Bridges/Constraint/functionize.jl @@ -308,6 +308,15 @@ function test_scalar_quadratic_to_nonlinear() return end +function test_canonical_constraint_function() + inner = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()) + model = MOI.Bridges.Constraint.ScalarFunctionize{Float64}(inner) + x = MOI.add_variable(model) + ci = MOI.add_constraint(model, x, MOI.GreaterThan(0.0)) + @test MOI.get(model, MOI.CanonicalConstraintFunction(), ci) ≈ x + return +end + end # module TestConstraintFunctionize.runtests() diff --git a/test/Utilities/functions.jl b/test/Utilities/functions.jl index 3374c04b46..30d21655aa 100644 --- a/test/Utilities/functions.jl +++ b/test/Utilities/functions.jl @@ -27,28 +27,6 @@ const x = MOI.VariableIndex(1) const y = MOI.VariableIndex(2) const z = MOI.VariableIndex(3) -# Number-like but not subtype of `Number` -struct NonNumber - value::Int -end -Base.:*(a::NonNumber, b::NonNumber) = NonNumber(a.value * b.value) -Base.:+(a::NonNumber, b::NonNumber) = NonNumber(a.value + b.value) -Base.zero(::Type{NonNumber}) = NonNumber(0) -function Base.isapprox(a::NonNumber, b::NonNumber; kws...) - return isapprox(a.value, b.value; kws...) -end - -function test_NonNumber() - two = NonNumber(2) - three = NonNumber(3) - six = NonNumber(6) - three_x = MOI.Utilities.operate(*, NonNumber, three, x) - six_x = MOI.Utilities.operate(*, NonNumber, six, x) - @test six_x ≈ two * three_x - @test six_x ≈ three_x * two - return -end - function test_Vectorization_vectorize() g = MOI.VectorAffineFunction( MOI.VectorAffineTerm.([3, 1], MOI.ScalarAffineTerm.([5, 2], [y, x])), diff --git a/test/runtests.jl b/test/runtests.jl index 5aade447bb..d7fb97a0e1 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -9,6 +9,9 @@ using Test # This file gets called first. If it doesn't crash, all is well. include("issue980.jl") +import MathOptInterface as MOI +@test isempty(Test.detect_ambiguities(MOI; recursive = true)) + for file in readdir(@__DIR__) if file in ["issue980.jl", "dummy.jl", "hygiene.jl", "runtests.jl"] continue