diff --git a/docs/src/manual/constraints.md b/docs/src/manual/constraints.md index 2462ed0ce5e..f03d0805023 100644 --- a/docs/src/manual/constraints.md +++ b/docs/src/manual/constraints.md @@ -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(); @@ -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) diff --git a/src/variables.jl b/src/variables.jl index 79be0447fc1..ddd73f9a6b1 100644 --- a/src/variables.jl +++ b/src/variables.jl @@ -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}}, @@ -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}}, @@ -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, @@ -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( @@ -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, @@ -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( @@ -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 ### diff --git a/test/test_constraint.jl b/test/test_constraint.jl index 08c89342fbc..c466f632bdc 100644 --- a/test/test_constraint.jl +++ b/test/test_constraint.jl @@ -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)) diff --git a/test/test_variable.jl b/test/test_variable.jl index 651e9db71ee..e744ae85723 100644 --- a/test/test_variable.jl +++ b/test/test_variable.jl @@ -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