From ff692935451c8c9769b0d51170813e8a19d7abc5 Mon Sep 17 00:00:00 2001 From: Joaquim Dias Garcia Date: Fri, 23 Jun 2023 15:32:38 -0300 Subject: [PATCH 1/4] Protect names on .bib (#3423) --- CITATION.bib | 4 ++-- README.md | 8 ++++---- docs/src/index.md | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CITATION.bib b/CITATION.bib index b27af5c433e..d08f3cb4a01 100644 --- a/CITATION.bib +++ b/CITATION.bib @@ -1,6 +1,6 @@ @article{Lubin2023, - author = {Miles Lubin and Oscar Dowson and Joaquim Dias Garcia and Joey Huchette and Beno{\^i}t Legat and Juan Pablo Vielma}, - title = {JuMP 1.0: Recent improvements to a modeling language for mathematical optimization}, + author = {Miles Lubin and Oscar Dowson and Joaquim {Dias Garcia} and Joey Huchette and Beno{\^i}t Legat and Juan Pablo Vielma}, + title = {{JuMP} 1.0: {R}ecent improvements to a modeling language for mathematical optimization}, journal = {Mathematical Programming Computation}, year = {2023}, doi = {10.1007/s12532-023-00239-3} diff --git a/README.md b/README.md index eb96f4ced3c..a2002eea50a 100644 --- a/README.md +++ b/README.md @@ -54,8 +54,8 @@ following paper ([preprint](https://arxiv.org/abs/2206.03866)): ```bibtex @article{Lubin2023, - author = {Miles Lubin and Oscar Dowson and Joaquim Dias Garcia and Joey Huchette and Beno{\^i}t Legat and Juan Pablo Vielma}, - title = {JuMP 1.0: Recent improvements to a modeling language for mathematical optimization}, + author = {Miles Lubin and Oscar Dowson and Joaquim {Dias Garcia} and Joey Huchette and Beno{\^i}t Legat and Juan Pablo Vielma}, + title = {{JuMP} 1.0: {R}ecent improvements to a modeling language for mathematical optimization}, journal = {Mathematical Programming Computation}, year = {2023}, doi = {10.1007/s12532-023-00239-3} @@ -68,7 +68,7 @@ For earlier works, see: ```bibtex @article{DunningHuchetteLubin2017, author = {Iain Dunning and Joey Huchette and Miles Lubin}, - title = {JuMP: A Modeling Language for Mathematical Optimization}, + title = {{JuMP}: {A} {M}odeling {L}anguage for {M}athematical {O}ptimization}, journal = {SIAM Review}, volume = {59}, number = {2}, @@ -82,7 +82,7 @@ For earlier works, see: ```bibtex @article{LubinDunningIJOC, author = {Miles Lubin and Iain Dunning}, - title = {Computing in Operations Research Using Julia}, + title = {{C}omputing in {O}perations {R}esearch {U}sing {J}ulia}, journal = {INFORMS Journal on Computing}, volume = {27}, number = {2}, diff --git a/docs/src/index.md b/docs/src/index.md index 22d2bff01b7..8eb5e676762 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -87,8 +87,8 @@ following paper ([preprint](https://arxiv.org/abs/2206.03866)): ```bibtex @article{Lubin2023, - author = {Miles Lubin and Oscar Dowson and Joaquim Dias Garcia and Joey Huchette and Beno{\^i}t Legat and Juan Pablo Vielma}, - title = {JuMP 1.0: Recent improvements to a modeling language for mathematical optimization}, + author = {Miles Lubin and Oscar Dowson and Joaquim {Dias Garcia} and Joey Huchette and Beno{\^i}t Legat and Juan Pablo Vielma}, + title = {{JuMP} 1.0: {R}ecent improvements to a modeling language for mathematical optimization}, journal = {Mathematical Programming Computation}, year = {2023}, doi = {10.1007/s12532-023-00239-3} From 0d1d90a91e0757b7183167989cff8cfd3806b4bc Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Tue, 27 Jun 2023 10:18:24 +1200 Subject: [PATCH 2/4] [docs] fix flakey doctest in variables.md (#3425) --- docs/src/manual/variables.md | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/docs/src/manual/variables.md b/docs/src/manual/variables.md index 57d1de46ca2..85abb69ac53 100644 --- a/docs/src/manual/variables.md +++ b/docs/src/manual/variables.md @@ -1222,19 +1222,15 @@ ERROR: MethodError: no method matching set_lower_bound(::AffExpr, ::Float64) [...] ``` -However, you can convert the matrix into one in which the upper triangular -elements are `VariableRef` and the lower triangular elements are `AffExpr` as -follows: +Instead, you can convert an upper-triangular elements to a variable as follows: ```jldoctest skewsymmetric -julia> y = Union{VariableRef,AffExpr}[ - j > i ? first(keys(x[i, j].terms)) : x[i, j] - for i in 1:size(x, 1), j in 1:size(x, 2) - ] -2×2 Matrix{Union{VariableRef, AffExpr}}: - 0 x[1,2] - -x[1,2] 0 +julia> to_variable(x::AffExpr) = first(keys(x.terms)) +to_variable (generic function with 1 method) + +julia> to_variable(x[1, 2]) +x[1,2] -julia> set_lower_bound(y[1, 2], 0.0) +julia> set_lower_bound(to_variable(x[1, 2]), 0.0) ``` ### Example: Hermitian positive semidefinite variables From 0b3ee89520c8f1b3e9397ee5dc612a2cad32aa8a Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Tue, 27 Jun 2023 13:20:06 +1200 Subject: [PATCH 3/4] Set SlackBridgePrimalDualStart in set_start_values (#3422) --- Project.toml | 2 +- docs/Project.toml | 2 +- src/optimizer_interface.jl | 2 ++ test/test_model.jl | 14 ++++++++++++++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index d8f04b0e67e..8d280a7f167 100644 --- a/Project.toml +++ b/Project.toml @@ -13,7 +13,7 @@ SnoopPrecompile = "66db9d55-30c0-4569-8b51-7e840670fc0c" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" [compat] -MathOptInterface = "1.17" +MathOptInterface = "1.18" MutableArithmetics = "1" OrderedCollections = "1" SnoopPrecompile = "1" diff --git a/docs/Project.toml b/docs/Project.toml index 383743c002f..98d810097e0 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -42,7 +42,7 @@ Ipopt = "=1.4.1" JSON = "0.21" JSONSchema = "1" Literate = "2.8" -MathOptInterface = "=1.17.1" +MathOptInterface = "=1.18.0" MultiObjectiveAlgorithms = "=1.0.0" Plots = "1" SCS = "=1.2.0" diff --git a/src/optimizer_interface.jl b/src/optimizer_interface.jl index 9f9578dd3b6..6648f6a23a7 100644 --- a/src/optimizer_interface.jl +++ b/src/optimizer_interface.jl @@ -1151,6 +1151,8 @@ function set_start_values( for (ci, dual_start) in constraint_dual set_dual_start_value(ci, dual_start) end + # Needed for models which bridge `min f(x)` into `min t; t >= f(x)`. + MOI.set(model, MOI.Bridges.Objective.SlackBridgePrimalDualStart(), nothing) return end diff --git a/test/test_model.jl b/test/test_model.jl index 21e12856b5f..de420a8d903 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -1110,6 +1110,20 @@ function test_model_quad_to_soc_start_values() return end +function test_SlackBridgePrimalDualStart() + inner = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()) + mock = MOI.Utilities.MockOptimizer(inner) + model = direct_model(MOI.Bridges.Objective.Slack{Float64}(mock)) + @variable(model, x, start = 1.0) + @objective(model, Min, x^2) + set_start_values(model; variable_primal_start = start_value) + F, S = MOI.ScalarQuadraticFunction{Float64}, MOI.LessThan{Float64} + ci = first(MOI.get(inner, MOI.ListOfConstraintIndices{F,S}())) + @test MOI.get(inner, MOI.ConstraintPrimalStart(), ci) == 0.0 + @test MOI.get(inner, MOI.ConstraintDualStart(), ci) == -1.0 + return +end + function test_keyword_getindex() err = JuMP._get_index_keyword_indexing_error() model = Model() From 0f123b8e41c97ddb135f906593123b5c591ee949 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Tue, 27 Jun 2023 13:20:55 +1200 Subject: [PATCH 4/4] Add fallback for MOI.AbstractSymmetricMatrixSet{Triangle,Square} (#3424) --- src/macros.jl | 7 +-- src/sd.jl | 100 +++++++++++++++++++++++++--------------- test/test_constraint.jl | 9 ---- 3 files changed, 65 insertions(+), 51 deletions(-) diff --git a/src/macros.jl b/src/macros.jl index eff273fca98..621442081b8 100644 --- a/src/macros.jl +++ b/src/macros.jl @@ -781,7 +781,7 @@ end function build_constraint( _error::Function, - x::Matrix, + x::AbstractMatrix, set::MOI.AbstractVectorSet, ) return _error( @@ -793,10 +793,7 @@ end function build_constraint( _error::Function, ::Matrix, - T::Union{ - MOI.PositiveSemidefiniteConeSquare, - MOI.PositiveSemidefiniteConeTriangle, - }, + T::MOI.PositiveSemidefiniteConeTriangle, ) return _error("instead of `$(T)`, use `JuMP.PSDCone()`.") end diff --git a/src/sd.jl b/src/sd.jl index 9c4b4a3bc81..e0be834cbd3 100644 --- a/src/sd.jl +++ b/src/sd.jl @@ -137,25 +137,6 @@ triangular part of the matrix is constrained to belong to the """ struct PSDCone end -function build_constraint( - _error::Function, - f::AbstractMatrix{<:AbstractJuMPScalar}, - ::Nonnegatives, - extra::PSDCone, -) - return build_constraint(_error, f, extra) -end - -function build_constraint( - _error::Function, - f::AbstractMatrix{<:AbstractJuMPScalar}, - ::Nonpositives, - extra::PSDCone, -) - new_f = _MA.operate!!(*, -1, f) - return build_constraint(_error, new_f, extra) -end - """ SymmetricMatrixShape @@ -167,6 +148,7 @@ lower-left triangular part given row by row). struct SymmetricMatrixShape <: AbstractShape side_dimension::Int end + function reshape_vector( vectorized_form::Vector{T}, shape::SymmetricMatrixShape, @@ -181,12 +163,14 @@ function reshape_vector( end return LinearAlgebra.Symmetric(matrix) end + function reshape_set( ::MOI.PositiveSemidefiniteConeTriangle, ::SymmetricMatrixShape, ) return PSDCone() end + function vectorize(matrix, ::SymmetricMatrixShape) n = LinearAlgebra.checksquare(matrix) return [matrix[i, j] for j in 1:n for i in 1:j] @@ -414,12 +398,7 @@ function build_variable( ) n = _square_side(_error, variables) set = MOI.PositiveSemidefiniteConeTriangle(n) - shape = SymmetricMatrixShape(n) - return VariablesConstrainedOnCreation( - _vectorize_variables(_error, variables), - set, - shape, - ) + return build_variable(_error, variables, set) end function value( @@ -476,12 +455,7 @@ function build_constraint( ::PSDCone, ) where {V<:AbstractJuMPScalar,M<:AbstractMatrix{V}} n = LinearAlgebra.checksquare(Q) - shape = SymmetricMatrixShape(n) - return VectorConstraint( - vectorize(Q, shape), - MOI.PositiveSemidefiniteConeTriangle(n), - shape, - ) + return build_constraint(_error, Q, MOI.PositiveSemidefiniteConeTriangle(n)) end """ @@ -511,12 +485,7 @@ function build_constraint( ::PSDCone, ) n = LinearAlgebra.checksquare(Q) - shape = SquareMatrixShape(n) - return VectorConstraint( - vectorize(Q, shape), - MOI.PositiveSemidefiniteConeSquare(n), - shape, - ) + return build_constraint(_error, Q, MOI.PositiveSemidefiniteConeSquare(n)) end """ @@ -742,3 +711,60 @@ function build_constraint(_error::Function, ::AbstractMatrix, ::Zeros) "`LinearAlgebra.Symmetric` or `LinearAlgebra.Hermitian`.", ) end + +function build_constraint( + _error::Function, + Q::LinearAlgebra.Symmetric{V,M}, + set::MOI.AbstractSymmetricMatrixSetTriangle, +) where {V<:AbstractJuMPScalar,M<:AbstractMatrix{V}} + n = LinearAlgebra.checksquare(Q) + shape = SymmetricMatrixShape(n) + return VectorConstraint(vectorize(Q, shape), set, shape) +end + +function build_constraint( + _error::Function, + Q::AbstractMatrix{<:AbstractJuMPScalar}, + set::MOI.AbstractSymmetricMatrixSetSquare, +) + n = LinearAlgebra.checksquare(Q) + shape = SquareMatrixShape(n) + return VectorConstraint(vectorize(Q, shape), set, shape) +end + +function build_constraint( + _error::Function, + f::AbstractMatrix{<:AbstractJuMPScalar}, + ::Nonnegatives, + extra::Union{ + MOI.AbstractSymmetricMatrixSetTriangle, + MOI.AbstractSymmetricMatrixSetSquare, + PSDCone, + }, +) + return build_constraint(_error, f, extra) +end + +function build_constraint( + _error::Function, + f::AbstractMatrix{<:AbstractJuMPScalar}, + ::Nonpositives, + extra::Union{ + MOI.AbstractSymmetricMatrixSetTriangle, + MOI.AbstractSymmetricMatrixSetSquare, + PSDCone, + }, +) + new_f = _MA.operate!!(*, -1, f) + return build_constraint(_error, new_f, extra) +end + +function build_variable( + _error::Function, + variables::Matrix{<:AbstractVariable}, + set::MOI.AbstractSymmetricMatrixSetTriangle, +) + n = _square_side(_error, variables) + x = _vectorize_variables(_error, variables) + return VariablesConstrainedOnCreation(x, set, SymmetricMatrixShape(n)) +end diff --git a/test/test_constraint.jl b/test/test_constraint.jl index a7e114df0ba..ad45ced56b0 100644 --- a/test/test_constraint.jl +++ b/test/test_constraint.jl @@ -652,15 +652,6 @@ function test_extension_PSD_constraint_errors( ) model = ModelType() @variable(model, X[1:2, 1:2]) - err = ErrorException( - "In `@constraint(model, X in MOI.PositiveSemidefiniteConeSquare(2))`:" * - " instead of `MathOptInterface.PositiveSemidefiniteConeSquare(2)`," * - " use `JuMP.PSDCone()`.", - ) - @test_throws_strip( - err, - @constraint(model, X in MOI.PositiveSemidefiniteConeSquare(2)) - ) err = ErrorException( "In `@constraint(model, X in MOI.PositiveSemidefiniteConeTriangle(2))`:" * " instead of `MathOptInterface.PositiveSemidefiniteConeTriangle(2)`," *