diff --git a/src/Utilities/functions.jl b/src/Utilities/functions.jl index 5a9d7dfb2f..6fc16b4eb0 100644 --- a/src/Utilities/functions.jl +++ b/src/Utilities/functions.jl @@ -1283,7 +1283,8 @@ function map_terms!( op, func::Union{MOI.ScalarAffineFunction,MOI.VectorAffineFunction}, ) - return map!(op, func.terms, func.terms) + map!(op, func.terms, func.terms) + return end function map_terms!( @@ -1291,7 +1292,8 @@ function map_terms!( func::Union{MOI.ScalarQuadraticFunction,MOI.VectorQuadraticFunction}, ) map!(op, func.affine_terms, func.affine_terms) - return map!(op, func.quadratic_terms, func.quadratic_terms) + map!(op, func.quadratic_terms, func.quadratic_terms) + return end ###################################### +/- ##################################### diff --git a/src/Utilities/mutable_arithmetics.jl b/src/Utilities/mutable_arithmetics.jl index d11cb6626d..0685508613 100644 --- a/src/Utilities/mutable_arithmetics.jl +++ b/src/Utilities/mutable_arithmetics.jl @@ -149,15 +149,11 @@ function MA.operate!( return f end -function MA.operate!(::typeof(-), f::MOI.ScalarQuadraticFunction) - operate_terms!(-, f.quadratic_terms) - operate_terms!(-, f.affine_terms) - f.constant = -f.constant - return f -end - -function MA.operate!(::typeof(-), f::MOI.ScalarAffineFunction) - operate_terms!(-, f.terms) +function MA.operate!( + ::typeof(-), + f::Union{MOI.ScalarAffineFunction,MOI.ScalarQuadraticFunction}, +) + map_terms!(Base.Fix1(operate_term, -), f) f.constant = -f.constant return f end diff --git a/src/Utilities/operate.jl b/src/Utilities/operate.jl index 5ee634dd0e..20ddfaacb9 100644 --- a/src/Utilities/operate.jl +++ b/src/Utilities/operate.jl @@ -255,26 +255,6 @@ function operate(::typeof(-), ::Type{T}, f::MOI.VariableIndex) where {T} ) end -function operate( - ::typeof(-), - ::Type{T}, - f::MOI.ScalarAffineFunction{T}, -) where {T} - return MOI.ScalarAffineFunction(operate_terms(-, f.terms), -f.constant) -end - -function operate( - ::typeof(-), - ::Type{T}, - f::MOI.ScalarQuadraticFunction{T}, -) where {T} - return MOI.ScalarQuadraticFunction( - operate_terms(-, f.quadratic_terms), - operate_terms(-, f.affine_terms), - -f.constant, - ) -end - function operate(::typeof(-), ::Type{T}, f::MOI.VectorOfVariables) where {T} d = MOI.output_dimension(f) return MOI.VectorAffineFunction{T}( @@ -286,21 +266,14 @@ end function operate( ::typeof(-), ::Type{T}, - f::MOI.VectorAffineFunction{T}, -) where {T} - return MOI.VectorAffineFunction(operate_terms(-, f.terms), -f.constants) -end - -function operate( - ::typeof(-), - ::Type{T}, - f::MOI.VectorQuadraticFunction{T}, + f::Union{ + MOI.ScalarAffineFunction{T}, + MOI.ScalarQuadraticFunction{T}, + MOI.VectorAffineFunction{T}, + MOI.VectorQuadraticFunction{T}, + }, ) where {T} - return MOI.VectorQuadraticFunction( - operate_terms(-, f.quadratic_terms), - operate_terms(-, f.affine_terms), - -f.constants, - ) + return operate_coefficients(-, f) end ### 2b: operate(::typeof(-), ::Type{T}, ::F1, ::F2) @@ -816,7 +789,7 @@ end function operate!( ::typeof(+), ::Type{T}, - f::MOI.VectorAffineFunction{T}, + f::Union{MOI.VectorAffineFunction{T},MOI.VectorQuadraticFunction{T}}, g::AbstractVector{T}, ) where {T} @assert MOI.output_dimension(f) == length(g) @@ -850,17 +823,6 @@ function operate!( return f end -function operate!( - ::typeof(+), - ::Type{T}, - f::MOI.VectorQuadraticFunction{T}, - g::AbstractVector{T}, -) where {T} - @assert MOI.output_dimension(f) == length(g) - f.constants .+= g - return f -end - function operate!( ::typeof(+), ::Type{T}, @@ -943,7 +905,7 @@ end function operate!( ::typeof(-), ::Type{T}, - f::MOI.VectorAffineFunction{T}, + f::Union{MOI.VectorAffineFunction{T},MOI.VectorQuadraticFunction{T}}, g::AbstractVector{T}, ) where {T} @assert MOI.output_dimension(f) == length(g) @@ -977,17 +939,6 @@ function operate!( return f end -function operate!( - ::typeof(-), - ::Type{T}, - f::MOI.VectorQuadraticFunction{T}, - g::AbstractVector{T}, -) where {T} - @assert MOI.output_dimension(f) == length(g) - f.constants .-= g - return f -end - function operate!( ::typeof(-), ::Type{T}, @@ -1048,7 +999,7 @@ function operate!( g::T, ) where {T} map_terms!(term -> operate_term(*, term, g), f) - LinearAlgebra.rmul!(f.constants, g) + f.constants .*= g return f end @@ -1076,19 +1027,7 @@ function operate!( g::T, ) where {T} map_terms!(term -> operate_term(/, term, g), f) - LinearAlgebra.rmul!(f.constants, inv(g)) - return f -end - -function operate!( - ::typeof(/), - ::Type{T}, - f::MOI.ScalarQuadraticFunction{T}, - g::T, -) where {T} - f.affine_terms .= operate_term.(/, f.affine_terms, g) - f.quadratic_terms .= operate_term.(/, f.quadratic_terms, g) - f.constant /= g + f.constants ./= g return f end @@ -1117,82 +1056,32 @@ Compute `op(args...)`, where at least one element of `args` is one of e. `operate_term(::typeof(*), ::Diagonal, ::VectorTerm)` 4. `/` a. `operate_term(::typeof(/), ::Term, ::T)` + 5. User-defined function + a. `operate_term(::Function, ::Term)` """ function operate_term end ### 1a: operate_term(::typeof(+), ::Term) -function operate_term( - ::typeof(+), - term::Union{ - MOI.ScalarAffineTerm, - MOI.ScalarQuadraticTerm, - MOI.VectorAffineTerm, - MOI.VectorQuadraticTerm, - }, -) - return term -end +# Works automatically via 5a fallback. ### 2a: operate_term(::typeof(-), ::Term) -function operate_term(::typeof(-), term::MOI.ScalarAffineTerm) - return MOI.ScalarAffineTerm(-term.coefficient, term.variable) -end - -function operate_term(::typeof(-), term::MOI.ScalarQuadraticTerm) - return MOI.ScalarQuadraticTerm( - -term.coefficient, - term.variable_1, - term.variable_2, - ) -end - -function operate_term(::typeof(-), term::MOI.VectorAffineTerm) - return MOI.VectorAffineTerm( - term.output_index, - operate_term(-, term.scalar_term), - ) -end - -function operate_term(::typeof(-), term::MOI.VectorQuadraticTerm) - return MOI.VectorQuadraticTerm( - term.output_index, - operate_term(-, term.scalar_term), - ) -end +# Works automatically via 5a fallback. ### 3a: operate_term(::typeof(*), ::T, ::Term) -function operate_term(::typeof(*), f::T, g::MOI.ScalarAffineTerm{T}) where {T} - return MOI.ScalarAffineTerm(f * g.coefficient, g.variable) -end - -function operate_term( - ::typeof(*), - f::T, - g::MOI.ScalarQuadraticTerm{T}, -) where {T} - coef = f * g.coefficient - return MOI.ScalarQuadraticTerm(coef, g.variable_1, g.variable_2) -end - -function operate_term(::typeof(*), f::T, g::MOI.VectorAffineTerm{T}) where {T} - return MOI.VectorAffineTerm( - g.output_index, - operate_term(*, f, g.scalar_term), - ) -end - function operate_term( ::typeof(*), f::T, - g::MOI.VectorQuadraticTerm{T}, + g::Union{ + MOI.ScalarAffineTerm{T}, + MOI.ScalarQuadraticTerm{T}, + MOI.VectorAffineTerm{T}, + MOI.VectorQuadraticTerm{T}, + }, ) where {T} - return MOI.VectorQuadraticTerm( - g.output_index, - operate_term(*, f, g.scalar_term), - ) + return operate_term(Base.Fix1(*, f), g) end ### 3b: operate_term(::typeof(*), ::Term, ::T) @@ -1240,24 +1129,11 @@ end function operate_term( ::typeof(*), - α::T, - t::MOI.ScalarAffineTerm{T}, - β::T, + f::T, + g::Union{MOI.ScalarAffineTerm{T},MOI.ScalarQuadraticTerm{T}}, + h::T, ) where {T} - return MOI.ScalarAffineTerm(α * t.coefficient * β, t.variable) -end - -function operate_term( - ::typeof(*), - α::T, - t::MOI.ScalarQuadraticTerm{T}, - β::T, -) where {T} - return MOI.ScalarQuadraticTerm( - α * t.coefficient * β, - t.variable_1, - t.variable_2, - ) + return operate_term(Base.Fix1(*, f * h), g) end ### 3e: operate_term(::typeof(*), ::Diagonal, ::Vector) @@ -1296,7 +1172,29 @@ function operate_term( }, g::T, ) where {T} - return operate_term(*, f, inv(g)) + return operate_term(Base.Fix2(/, g), f) +end + +### 5a: operate_term(::Function, ::Term) + +function operate_term(op::F, f::MOI.ScalarAffineTerm) where {F<:Function} + return MOI.ScalarAffineTerm(op(f.coefficient), f.variable) +end + +function operate_term(op::F, f::MOI.ScalarQuadraticTerm) where {F<:Function} + coef = op(f.coefficient) + return MOI.ScalarQuadraticTerm(coef, f.variable_1, f.variable_2) +end + +function operate_term(op::F, f::MOI.VectorAffineTerm) where {F<:Function} + return MOI.VectorAffineTerm(f.output_index, operate_term(op, f.scalar_term)) +end + +function operate_term(op::F, f::MOI.VectorQuadraticTerm) where {F<:Function} + return MOI.VectorQuadraticTerm( + f.output_index, + operate_term(op, f.scalar_term), + ) end """ @@ -1314,9 +1212,13 @@ Compute `op(args...)`, where at least one element of `args` is a vector of a. `operate_term(::typeof(-), ::Vector{<:Term})` 3. `*` a. `operate_term(::typeof(*), ::Diagonal, ::Vector{<:VectorTerm})` + 4. User-defined function + a. `operate_term(::Function, ::Vector{<:Term})` """ function operate_terms end +### 1a: operate_term(::typeof(+), ::Vector{<:Term}) + function operate_terms( ::typeof(+), terms::Vector{ @@ -1331,9 +1233,21 @@ function operate_terms( return terms end +### 2a: operate_term(::typeof(-), ::Vector{<:Term}) + +# Works automatically by 4a fallback. + +### 3a: operate_term(::typeof(*), ::Diagonal, ::Vector{<:VectorTerm}) + +function operate_terms(::typeof(*), D::Diagonal, terms) + return map(term -> operate_term(*, D, term), terms) +end + +### 4a: operate_term(::Function, ::Vector{<:Term}) + function operate_terms( - ::typeof(-), - terms::Vector{ + op::F, + f::Vector{ <:Union{ MOI.ScalarAffineTerm, MOI.ScalarQuadraticTerm, @@ -1341,12 +1255,8 @@ function operate_terms( MOI.VectorQuadraticTerm, }, }, -) - return map(term -> operate_term(-, term), terms) -end - -function operate_terms(::typeof(*), D::Diagonal, terms) - return map(term -> operate_term(*, D, term), terms) +) where {F} + return map(Base.Fix1(operate_term, op), f) end """ @@ -1356,18 +1266,20 @@ Compute `op(args...)`, where at least one element of `args` is a vector of [`MOI.ScalarAffineTerm`](@ref), [`MOI.ScalarQuadraticTerm`](@ref), [`MOI.VectorAffineTerm`](@ref), or [`MOI.VectorQuadraticTerm`](@ref). +!!! warning + This method is deprecated and may be removed in MathOptInterface v2.0. + ## Methods 1. `-` a. `operate_term(::typeof(-), ::Vector{<:ScalarTerm})` """ -function operate_terms! end - function operate_terms!( ::typeof(-), terms::Vector{<:Union{MOI.ScalarAffineTerm,MOI.ScalarQuadraticTerm}}, ) - return map!(term -> operate_term(-, term), terms, terms) + map!(Base.Fix1(operate_term, -), terms, terms) + return terms end """ @@ -1521,30 +1433,12 @@ end Return a new term, which is the result of calling `op(coefficient)` for on the coefficient of the term `f`. -""" - -function operate_coefficient(op::F, f::MOI.ScalarAffineTerm) where {F} - return MOI.ScalarAffineTerm(op(f.coefficient), f.variable) -end -function operate_coefficient(op::F, f::MOI.ScalarQuadraticTerm) where {F} - coef = op(f.coefficient) - return MOI.ScalarQuadraticTerm(coef, f.variable_1, f.variable_2) -end - -function operate_coefficient(op::F, f::MOI.VectorAffineTerm) where {F} - return MOI.VectorAffineTerm( - f.output_index, - operate_coefficient(op, f.scalar_term), - ) -end - -function operate_coefficient(op::F, f::MOI.VectorQuadraticTerm) where {F} - return MOI.VectorQuadraticTerm( - f.output_index, - operate_coefficient(op, f.scalar_term), - ) -end +!!! warning + This method is deprecated and may be removed in MathOptInterface v2.0. Use + `operate_term(op, f)` instead. +""" +operate_coefficient(op::F, f) where {F} = operate_term(op, f) """ operate_coefficients( @@ -1559,46 +1453,31 @@ end """ function operate_coefficients end -function operate_coefficients( - op::F, - f::Vector{ - <:Union{ - MOI.ScalarAffineTerm, - MOI.ScalarQuadraticTerm, - MOI.VectorAffineTerm, - MOI.VectorQuadraticTerm, - }, - }, -) where {F} - return map(Base.Fix1(operate_coefficient, op), f) -end +operate_coefficients(op::F, f) where {F} = operate_terms(op, f) function operate_coefficients(op::F, f::MOI.ScalarAffineFunction) where {F} - return MOI.ScalarAffineFunction( - operate_coefficients(op, f.terms), - op(f.constant), - ) + return MOI.ScalarAffineFunction(operate_terms(op, f.terms), op(f.constant)) end function operate_coefficients(op::F, f::MOI.ScalarQuadraticFunction) where {F} return MOI.ScalarQuadraticFunction( - operate_coefficients(op, f.quadratic_terms), - operate_coefficients(op, f.affine_terms), + operate_terms(op, f.quadratic_terms), + operate_terms(op, f.affine_terms), op(f.constant), ) end function operate_coefficients(op::F, f::MOI.VectorAffineFunction) where {F} return MOI.VectorAffineFunction( - operate_coefficients(op, f.terms), - map(op, f.constants), + operate_terms(op, f.terms), + op.(f.constants), ) end function operate_coefficients(op::F, f::MOI.VectorQuadraticFunction) where {F} return MOI.VectorQuadraticFunction( - operate_coefficients(op, f.quadratic_terms), - operate_coefficients(op, f.affine_terms), + operate_terms(op, f.quadratic_terms), + operate_terms(op, f.affine_terms), map(op, f.constants), ) end diff --git a/test/Utilities/test_operate!.jl b/test/Utilities/test_operate!.jl index 4110f7d8c1..c2f7607f59 100644 --- a/test/Utilities/test_operate!.jl +++ b/test/Utilities/test_operate!.jl @@ -409,6 +409,20 @@ function test_operate_term_4a() return end +function test_operate_term_5a() + x = MOI.VariableIndex(1) + for f in ( + MOI.ScalarAffineTerm(1.0, x), + MOI.ScalarQuadraticTerm(1.0, x, x), + MOI.VectorAffineTerm(3, MOI.ScalarAffineTerm(1.0, x)), + MOI.VectorQuadraticTerm(3, MOI.ScalarQuadraticTerm(1.0, x, x)), + ) + @test MOI.Utilities.operate_term(t -> -(t), f) == + MOI.Utilities.operate_term(-, f) + end + return +end + function test_operate_terms_1a() x = MOI.VariableIndex(1) for term in (