Skip to content

Commit

Permalink
Support vector-valued constraints in normalized_coefficient (#3743)
Browse files Browse the repository at this point in the history
  • Loading branch information
odow authored May 9, 2024
1 parent 18c01c4 commit c65e0c9
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 6 deletions.
6 changes: 3 additions & 3 deletions docs/src/manual/constraints.md
Original file line number Diff line number Diff line change
Expand Up @@ -843,7 +843,7 @@ julia> normalized_coefficient(con, x[1], x[2])
### Vector constraints

To modify the coefficients of a vector-valued constraint, use
[`set_normalized_coefficients`](@ref).
[`set_normalized_coefficient`](@ref).
```jldoctest
julia> model = Model();
Expand All @@ -853,12 +853,12 @@ x
julia> @constraint(model, con, [2x + 3x, 4x] in MOI.Nonnegatives(2))
con : [5 x, 4 x] ∈ MathOptInterface.Nonnegatives(2)
julia> set_normalized_coefficients(con, x, [(1, 3.0)])
julia> set_normalized_coefficient(con, x, [(1, 3.0)])
julia> con
con : [3 x, 4 x] ∈ MathOptInterface.Nonnegatives(2)
julia> set_normalized_coefficients(con, x, [(1, 2.0), (2, 5.0)])
julia> set_normalized_coefficient(con, x, [(1, 2.0), (2, 5.0)])
julia> con
con : [2 x, 5 x] ∈ MathOptInterface.Nonnegatives(2)
Expand Down
58 changes: 55 additions & 3 deletions src/variables.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2624,7 +2624,7 @@ function set_normalized_coefficient(
end

"""
set_normalized_coefficients(
set_normalized_coefficient(
con_ref::ConstraintRef,
variable::AbstractVariableRef,
new_coefficients::Vector{Tuple{Int64,T}},
Expand All @@ -2648,13 +2648,13 @@ x
julia> @constraint(model, con, [2x + 3x, 4x] in MOI.Nonnegatives(2))
con : [5 x, 4 x] ∈ MathOptInterface.Nonnegatives(2)
julia> set_normalized_coefficients(con, x, [(1, 2.0), (2, 5.0)])
julia> set_normalized_coefficient(con, x, [(1, 2.0), (2, 5.0)])
julia> con
con : [2 x, 5 x] ∈ MathOptInterface.Nonnegatives(2)
```
"""
function set_normalized_coefficients(
function set_normalized_coefficient(
constraint::ConstraintRef{<:AbstractModel,<:MOI.ConstraintIndex{F}},
variable::AbstractVariableRef,
new_coefficients::Vector{Tuple{Int64,T}},
Expand All @@ -2669,6 +2669,22 @@ function set_normalized_coefficients(
return
end

"""
set_normalized_coefficients(
constraint::ConstraintRef{<:AbstractModel,<:MOI.ConstraintIndex{F}},
variable::AbstractVariableRef,
new_coefficients::Vector{Tuple{Int64,T}},
) where {T,F<:Union{MOI.VectorAffineFunction{T},MOI.VectorQuadraticFunction{T}}}
A deprecated method that now redirects to [`set_normalized_coefficient`](@ref).
"""
function set_normalized_coefficients(
constraint::ConstraintRef{<:AbstractModel,<:MOI.ConstraintIndex{F}},
variable::AbstractVariableRef,
new_coefficients::Vector{Tuple{Int64,T}},
) where {T,F<:Union{MOI.VectorAffineFunction{T},MOI.VectorQuadraticFunction{T}}}
return set_normalized_coefficient(constraint, variable, new_coefficients)
end
"""
set_normalized_coefficient(
constraint::ConstraintRef,
Expand Down Expand Up @@ -2816,6 +2832,14 @@ con : 5 x ≤ 2
julia> normalized_coefficient(con, x)
5.0
julia> @constraint(model, con_vec, [x, 2x + 1, 3] >= 0)
con_vec : [x, 2 x + 1, 3] ∈ MathOptInterface.Nonnegatives(3)
julia> normalized_coefficient(con_vec, x)
2-element Vector{Tuple{Int64, Float64}}:
(1, 1.0)
(2, 2.0)
```
"""
function normalized_coefficient(
Expand All @@ -2825,6 +2849,14 @@ function normalized_coefficient(
return coefficient(constraint_object(constraint).func, variable)
end

function normalized_coefficient(
constraint::ConstraintRef{<:AbstractModel,<:MOI.ConstraintIndex{F}},
variable::AbstractVariableRef,
) where {T,F<:Union{MOI.VectorAffineFunction{T},MOI.VectorQuadraticFunction{T}}}
c = coefficient.(constraint_object(constraint).func, variable)
return filter!(!iszero last, collect(enumerate(c)))
end

"""
normalized_coefficient(
constraint::ConstraintRef,
Expand Down Expand Up @@ -2852,6 +2884,16 @@ julia> normalized_coefficient(con, x[1], x[1])
julia> normalized_coefficient(con, x[1], x[2])
3.0
julia> @constraint(model, con_vec, x.^2 <= [1, 2])
con_vec : [x[1]² - 1, x[2]² - 2] ∈ MathOptInterface.Nonpositives(2)
julia> normalized_coefficient(con_vec, x[1], x[1])
1-element Vector{Tuple{Int64, Float64}}:
(1, 1.0)
julia> normalized_coefficient(con_vec, x[1], x[2])
Tuple{Int64, Float64}[]
```
"""
function normalized_coefficient(
Expand All @@ -2863,6 +2905,16 @@ function normalized_coefficient(
return coefficient(con.func, variable_1, variable_2)
end

function normalized_coefficient(
constraint::ConstraintRef{<:AbstractModel,<:MOI.ConstraintIndex{F}},
variable_1::AbstractVariableRef,
variable_2::AbstractVariableRef,
) where {T,F<:MOI.VectorQuadraticFunction{T}}
f = constraint_object(constraint).func
c = coefficient.(f, variable_1, variable_2)
return filter!(!iszero last, collect(enumerate(c)))
end

###
### Error messages for common incorrect usages
###
Expand Down
12 changes: 12 additions & 0 deletions test/test_constraint.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1009,6 +1009,18 @@ function test_change_coefficient_batch()
end

function test_change_coefficients_vector_function()
model = Model()
@variable(model, x)
@constraint(model, con, [2x + 3x, 4x] in MOI.Nonnegatives(2))
@test isequal_canonical(constraint_object(con).func, [5.0x, 4.0x])
set_normalized_coefficient(con, x, [(Int64(1), 3.0)])
@test isequal_canonical(constraint_object(con).func, [3.0x, 4.0x])
set_normalized_coefficient(con, x, [(Int64(1), 2.0), (Int64(2), 5.0)])
@test isequal_canonical(constraint_object(con).func, [2.0x, 5.0x])
return
end

function test_change_coefficients_vector_function_DEPRECATED()
model = Model()
@variable(model, x)
@constraint(model, con, [2x + 3x, 4x] in MOI.Nonnegatives(2))
Expand Down
25 changes: 25 additions & 0 deletions test/test_variable.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1626,4 +1626,29 @@ function test_variable_one()
return
end

function test_variable_normalized_coefficient_vector()
model = Model()
@variable(model, x[1:3])
A = Float64[4 5 0; 0 6 7; 8 0 0; 9 10 11]
sparse(y) = filter!(!iszero last, collect(enumerate(y)))
@constraint(model, c, A * x >= 0)
for i in 1:3
@test normalized_coefficient(c, x[i]) == sparse(A[:, i])
end
return
end

function test_variable_normalized_coefficient_vector_quadratic()
model = Model()
@variable(model, x[1:3])
A = Float64[4 5 0; 0 6 7; 8 0 0; 9 10 11]
sparse(y) = filter!(!iszero last, collect(enumerate(y)))
@constraint(model, c, A * (x .^ 2) >= 0)
for i in 1:3, j in 1:3
b = ifelse(i == j, A[:, i], zeros(4))
@test normalized_coefficient(c, x[i], x[j]) == sparse(b)
end
return
end

end # module TestVariable

0 comments on commit c65e0c9

Please sign in to comment.