Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 51 additions & 23 deletions src/Utilities/functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -848,25 +848,30 @@ const ScalarAffineLike{T} = Union{T, MOI.SingleVariable, MOI.ScalarAffineFunctio
# Functions convertible to a ScalarQuadraticFunction
const ScalarQuadraticLike{T} = Union{ScalarAffineLike{T}, MOI.ScalarQuadraticFunction{T}}

# Used for overloading Base operator functions so `T` is not in the union to
# avoid overloading e.g. `+(::Float64, ::Float64)`
const ScalarLike{T} = Union{MOI.SingleVariable, MOI.ScalarAffineFunction{T},
MOI.ScalarQuadraticFunction{T}}
# `ScalarLike` for which `T` is defined to avoid defining, e.g.,
# `+(::SingleVariable, ::Any)` which should rather be
# `+(::SingleVariable, ::Number)`.
const TypedScalarLike{T} = Union{MOI.ScalarAffineFunction{T},
MOI.ScalarQuadraticFunction{T}}
# Used for overloading Base operator functions so `T` is not in the union to
# avoid overloading e.g. `+(::Float64, ::Float64)`
const ScalarLike{T} = Union{MOI.SingleVariable, TypedScalarLike{T}}

# Functions convertible to a VectorAffineFunction
const VectorAffineLike{T} = Union{Vector{T}, MOI.VectorOfVariables, MOI.VectorAffineFunction{T}}
# Functions convertible to a VectorQuadraticFunction
const VectorQuadraticLike{T} = Union{VectorAffineLike{T}, MOI.VectorQuadraticFunction{T}}

# `VectorLike` for which `T` is defined to avoid defining, e.g.,
# `+(::VectorOfVariables, ::Any)` which should rather be
# `+(::VectorOfVariables, ::Number)`.
const TypedVectorLike{T} = Union{MOI.VectorAffineFunction{T},
MOI.VectorQuadraticFunction{T}}
# Used for overloading Base operator functions so `T` is not in the union to
# avoid overloading e.g. `+(::Float64, ::Float64)`
const VectorLike{T} = Union{MOI.VectorOfVariables, MOI.VectorAffineFunction{T},
MOI.VectorQuadraticFunction{T}}
const VectorLike{T} = Union{MOI.VectorOfVariables, TypedVectorLike{T}}

const TypedLike{T} = Union{TypedScalarLike{T}, TypedVectorLike{T}}

###################################### +/- #####################################
## promote_operation
Expand Down Expand Up @@ -1354,7 +1359,14 @@ end
function operate(::typeof(*), ::Type{T}, α::T, f::MOI.SingleVariable) where T
return MOI.ScalarAffineFunction{T}([MOI.ScalarAffineTerm(α, f.variable)], zero(T))
end
function operate(::typeof(*), ::Type{T}, f::MOI.SingleVariable, α::T) where T
function operate(::typeof(*), ::Type{T}, α::T, f::MOI.VectorOfVariables) where T
return MOI.VectorAffineFunction{T}(
[MOI.VectorAffineTerm(i, MOI.ScalarAffineTerm(α, f.variables[i]))
for i in eachindex(f.variables)], zeros(T, MOI.output_dimension(f)))
end
function operate(::typeof(*), ::Type{T},
f::Union{MOI.SingleVariable, MOI.VectorOfVariables},
α::T) where T
return operate(*, T, α, f)
end

Expand All @@ -1365,12 +1377,14 @@ function operate!(::typeof(*), ::Type{T},
f.constant *= α
return f
end
function operate(::typeof(*), ::Type{T}, α::T, f::MOI.ScalarAffineFunction) where T
return operate!(*, T, copy(f), α)
function operate!(::typeof(*), ::Type{T},
f::Union{MOI.VectorAffineFunction{T},
MOI.VectorQuadraticFunction{T}}, α::T) where T
map_terms!(term -> operate_term(*, α, term), f)
rmul!(f.constants, α)
return f
end

function operate(::typeof(*), ::Type{T}, α::T,
f::MOI.ScalarQuadraticFunction) where T
function operate(::typeof(*), ::Type{T}, α::T, f::TypedLike{T}) where T
return operate!(*, T, copy(f), α)
end

Expand Down Expand Up @@ -1439,16 +1453,16 @@ end
function Base.:*(arg::ScalarLike{T}, args::ScalarLike{T}...) where T
return operate(*, T, arg, args...)
end
function Base.:*(f::T, g::TypedScalarLike{T}) where T
function Base.:*(f::T, g::TypedLike{T}) where T
return operate(*, T, f, g)
end
function Base.:*(f::Number, g::MOI.SingleVariable)
function Base.:*(f::Number, g::Union{MOI.SingleVariable, MOI.VectorOfVariables})
return operate(*, typeof(f), f, g)
end
function Base.:*(f::TypedScalarLike{T}, g::T) where T
function Base.:*(f::TypedLike{T}, g::T) where T
return operate(*, T, g, f)
end
function Base.:*(f::MOI.SingleVariable, g::Number)
function Base.:*(f::Union{MOI.SingleVariable, MOI.VectorOfVariables}, g::Number)
return operate(*, typeof(g), f, g)
end

Expand Down Expand Up @@ -1477,13 +1491,24 @@ function operate(::typeof(/), ::Type{T}, f::MOI.SingleVariable,
zero(T))
end

function operate!(::typeof(/), ::Type{T}, f::MOI.ScalarAffineFunction{T},
function operate!(::typeof(/), ::Type{T},
f::Union{MOI.ScalarAffineFunction{T},
MOI.ScalarQuadraticFunction{T}},
α::T) where T
f.terms .= operate_term.(/, f.terms, α)
map_terms!(term -> operate_term(/, term, α), f)
f.constant /= α
return f
end

function operate!(::typeof(/), ::Type{T},
f::Union{MOI.VectorAffineFunction{T},
MOI.VectorQuadraticFunction{T}},
α::T) where T
map_terms!(term -> operate_term(/, term, α), f)
rmul!(f.constants, inv(α))
return f
end

function operate!(::typeof(/), ::Type{T}, f::MOI.ScalarQuadraticFunction{T},
α::T) where T
f.affine_terms .= operate_term.(/, f.affine_terms, α)
Expand All @@ -1492,16 +1517,19 @@ function operate!(::typeof(/), ::Type{T}, f::MOI.ScalarQuadraticFunction{T},
return f
end

function operate(::typeof(/), ::Type{T},
f::Union{MOI.ScalarAffineFunction{T},
MOI.ScalarQuadraticFunction{T}}, α::T) where T
function operate(::typeof(/), ::Type{T}, f::TypedLike{T}, α::T) where T
return operate!(/, T, copy(f), α)
end
function operate(::typeof(/), ::Type{T},
f::Union{MOI.SingleVariable, MOI.VectorOfVariables},
α::T) where T
return operate(*, T, inv(α), f)
end

function Base.:/(f::TypedScalarLike{T}, g::T) where T
function Base.:/(f::TypedLike{T}, g::T) where T
return operate(/, T, f, g)
end
function Base.:/(f::MOI.SingleVariable, g::Number)
function Base.:/(f::Union{MOI.SingleVariable, MOI.VectorOfVariables}, g::Number)
return operate(/, typeof(g), f, g)
end

Expand Down
127 changes: 79 additions & 48 deletions test/Utilities/functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -680,59 +680,90 @@ end
@test MOIU.promote_operation(-, T, t) == MOI.VectorQuadraticFunction{T}
end

α = [1, 2, 3]
v = MOI.VectorOfVariables([y, w, y])
g = MOI.VectorAffineFunction(
MOI.VectorAffineTerm.([3, 1],
MOI.ScalarAffineTerm.([5, 2], [y, x])),
[3, 1, 4])
f = MOI.VectorQuadraticFunction(
@testset "Vector + and - Vector" begin
α = [1, 2, 3]
v = MOI.VectorOfVariables([y, w, y])
g = MOI.VectorAffineFunction(
MOI.VectorAffineTerm.([3, 1],
MOI.ScalarAffineTerm.([5, 2], [y, x])),
[3, 1, 4])
f = MOI.VectorQuadraticFunction(
MOI.VectorAffineTerm.([1, 2, 2],
MOI.ScalarAffineTerm.([3, 1, 2], [x, x, y])),
MOI.VectorQuadraticTerm.([1, 1, 2],
MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y])),
[7, 3, 4])
v_plus_g = MOI.VectorAffineFunction(
MOI.VectorAffineTerm.([3, 1, 1, 2, 3],
MOI.ScalarAffineTerm.([5, 2, 1, 1, 1], [y, x, y, w, y])),
[3, 1, 4])
g_plus_α = MOI.VectorAffineFunction(
MOI.VectorAffineTerm.([3, 1],
MOI.ScalarAffineTerm.([5, 2], [y, x])),
[4, 3, 7])
α_minus_v = MOI.VectorAffineFunction(
MOI.VectorAffineTerm.([1, 2, 3],
MOI.ScalarAffineTerm.([-1, -1, -1], [y, w, y])),
[1, 2, 3])
v_minus_v_plus_v = MOI.VectorAffineFunction(
MOI.VectorAffineTerm.([1, 2, 3, 1, 2, 3, 1, 2, 3],
MOI.ScalarAffineTerm.([1, 1, 1, -1, -1, -1, 1, 1, 1],
[y, w, y, y, w, y, y, w, y])),
[0, 0, 0])
f_plus_α = MOI.VectorQuadraticFunction(
MOI.VectorAffineTerm.([1, 2, 2],
MOI.ScalarAffineTerm.([3, 1, 2], [x, x, y])),
MOI.VectorQuadraticTerm.([1, 1, 2],
MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y])),
[8, 5, 7])
f_minus_g = MOI.VectorQuadraticFunction(
MOI.VectorAffineTerm.([1, 2, 2, 3, 1],
MOI.ScalarAffineTerm.([3, 1, 2, -5, -2], [x, x, y, y, x])),
v_plus_g = MOI.VectorAffineFunction(
MOI.VectorAffineTerm.([3, 1, 1, 2, 3],
MOI.ScalarAffineTerm.([5, 2, 1, 1, 1], [y, x, y, w, y])),
[3, 1, 4])
g_plus_α = MOI.VectorAffineFunction(
MOI.VectorAffineTerm.([3, 1],
MOI.ScalarAffineTerm.([5, 2], [y, x])),
[4, 3, 7])
α_minus_v = MOI.VectorAffineFunction(
MOI.VectorAffineTerm.([1, 2, 3],
MOI.ScalarAffineTerm.([-1, -1, -1], [y, w, y])),
[1, 2, 3])
v_minus_v_plus_v = MOI.VectorAffineFunction(
MOI.VectorAffineTerm.([1, 2, 3, 1, 2, 3, 1, 2, 3],
MOI.ScalarAffineTerm.([1, 1, 1, -1, -1, -1, 1, 1, 1],
[y, w, y, y, w, y, y, w, y])),
[0, 0, 0])
f_plus_α = MOI.VectorQuadraticFunction(
MOI.VectorAffineTerm.([1, 2, 2],
MOI.ScalarAffineTerm.([3, 1, 2], [x, x, y])),
MOI.VectorQuadraticTerm.([1, 1, 2],
MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y])),
[4, 2, 0])
@test v + g ≈ v_plus_g
@test g + α ≈ g_plus_α
@test α + g ≈ g_plus_α
@test α - v ≈ α_minus_v
@test MOIU.operate(+, Int, MOIU.operate(-, Int, v, v), v) ≈ v_minus_v_plus_v
@test f + α ≈ f_plus_α
@test f - g ≈ f_minus_g
@test f - f + f - g ≈ f_minus_g
@test v + f + α - v ≈ f_plus_α
@test v - f - α - v ≈ - f_plus_α
@test MOIU.operate!(-, Int, v, f) - v ≈ - f
@test (g + v + g + v + f) - (v + g + v + g) ≈ f
@test v - α ≈ - α_minus_v
@test g - f ≈ - f_minus_g
[8, 5, 7])
f_minus_g = MOI.VectorQuadraticFunction(
MOI.VectorAffineTerm.([1, 2, 2, 3, 1],
MOI.ScalarAffineTerm.([3, 1, 2, -5, -2], [x, x, y, y, x])),
MOI.VectorQuadraticTerm.([1, 1, 2],
MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y])),
[4, 2, 0])
@test v + g ≈ v_plus_g
@test g + α ≈ g_plus_α
@test α + g ≈ g_plus_α
@test α - v ≈ α_minus_v
@test MOIU.operate(+, Int, MOIU.operate(-, Int, v, v), v) ≈ v_minus_v_plus_v
@test f + α ≈ f_plus_α
@test f - g ≈ f_minus_g
@test f - f + f - g ≈ f_minus_g
@test v + f + α - v ≈ f_plus_α
@test v - f - α - v ≈ - f_plus_α
@test MOIU.operate!(-, Int, v, f) - v ≈ - f
@test (g + v + g + v + f) - (v + g + v + g) ≈ f
@test v - α ≈ - α_minus_v
@test g - f ≈ - f_minus_g
end
@testset "Vector * and / constant" begin
v = MOI.VectorOfVariables([y, w, y])
v2 = MOIU.operate(
vcat, Float64,
2.0fy,
2.0fw,
2.0fy)
f = MOIU.operate(
vcat, Float64,
2.0fx + 3.0fy + 1.0,
3.0fx + 2.0fy + 3.0)
f2 = MOIU.operate(
vcat, Float64,
4.0fx + 6.0fy + 2.0,
6.0fx + 4.0fy + 6.0)
g = MOIU.operate(
vcat, Float64,
7.0fx * fy + 2.0fx + 3.0fy + 1.0,
6.0fx * fx + 5.0fy * fy + 3.0fx + 2.0fy + 3.0)
g2 = MOIU.operate(
vcat, Float64,
14.0fx * fy + 4.0fx + 6.0fy + 2.0,
12.0fx * fx + 10.0fy * fy + 6.0fx + 4.0fy + 6.0)
@testset "$(typeof(a))" for (a, a2) in [(v, v2), (f, f2), (g, g2)]
@test a * 2.0 ≈ a2
@test 2.0 * a ≈ a2
@test a / 0.5 ≈ a2
end
end
end