From dfa44d9e0dc76a02555164fdbcce5f85a0176df1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Wed, 11 Dec 2024 09:11:10 +0100 Subject: [PATCH] Add conversions --- .../bridges/LinearCombinationBridge.jl | 70 ---------------- .../Variable/bridges/DotProductsBridge.jl | 82 ------------------- src/sets.jl | 77 +++++++++++++++-- 3 files changed, 69 insertions(+), 160 deletions(-) delete mode 100644 src/Bridges/Constraint/bridges/LinearCombinationBridge.jl delete mode 100644 src/Bridges/Variable/bridges/DotProductsBridge.jl diff --git a/src/Bridges/Constraint/bridges/LinearCombinationBridge.jl b/src/Bridges/Constraint/bridges/LinearCombinationBridge.jl deleted file mode 100644 index 2656cea235..0000000000 --- a/src/Bridges/Constraint/bridges/LinearCombinationBridge.jl +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright (c) 2017: Miles Lubin and contributors -# Copyright (c) 2017: Google Inc. -# -# Use of this source code is governed by an MIT-style license that can be found -# in the LICENSE.md file or at https://opensource.org/licenses/MIT. - -struct LinearCombinationBridge{T,S,A,V,F,G} <: - SetMapBridge{T,S,MOI.LinearCombinationInSet{S,A,V},F,G} - constraint::MOI.ConstraintIndex{F,S} - set::MOI.LinearCombinationInSet{S,A,V} -end - -function MOI.supports_constraint( - ::Type{<:LinearCombinationBridge}, - ::Type{<:MOI.AbstractVectorFunction}, - ::Type{<:MOI.LinearCombinationInSet}, -) - return true -end - -function concrete_bridge_type( - ::Type{<:LinearCombinationBridge{T}}, - G::Type{<:MOI.AbstractVectorFunction}, - ::Type{MOI.LinearCombinationInSet{S,A,V}}, -) where {T,S,A,V} - U = MOI.Utilities.promote_operation(*, T, MOI.Utilities.scalar_type(G), T) - F = MOI.Utilities.promote_operation(vcat, T, U) - return LinearCombinationBridge{T,S,A,V,F,G} -end - -function _map_function(set::MOI.LinearCombinationInSet, func) - scalars = MOI.Utilities.eachscalar(func) - return MOI.Utilities.vectorize([ - sum(scalars[j] * set.vectors[j][i] for j in eachindex(scalars)) for - i in 1:MOI.dimension(set.set) - ]) -end - -function bridge_constraint( - ::Type{LinearCombinationBridge{T,S,A,V,F,G}}, - model::MOI.ModelLike, - func::G, - set::MOI.LinearCombinationInSet{S,A,V}, -) where {T,S,A,F,G,V} - mapped_func = _map_function(set, func) - constraint = MOI.add_constraint(model, mapped_func, set.set) - return LinearCombinationBridge{T,S,A,V,F,G}(constraint, set) -end - -function MOI.Bridges.map_set( - ::Type{<:LinearCombinationBridge}, - set::MOI.LinearCombinationInSet, -) - return set.set -end - -function MOI.Bridges.inverse_map_set( - bridge::LinearCombinationBridge, - ::MOI.AbstractSet, -) - return bridge.set -end - -function MOI.Bridges.adjoint_map_function(bridge::LinearCombinationBridge, func) - scalars = MOI.Utilities.eachscalar(func) - return MOI.Utilities.vectorize([ - MOI.Utilities.set_dot(vector, scalars, bridge.set.set) for - vector in bridge.set.vectors - ]) -end diff --git a/src/Bridges/Variable/bridges/DotProductsBridge.jl b/src/Bridges/Variable/bridges/DotProductsBridge.jl deleted file mode 100644 index a2468f4b9c..0000000000 --- a/src/Bridges/Variable/bridges/DotProductsBridge.jl +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright (c) 2017: Miles Lubin and contributors -# Copyright (c) 2017: Google Inc. -# -# Use of this source code is governed by an MIT-style license that can be found -# in the LICENSE.md file or at https://opensource.org/licenses/MIT. - -struct DotProductsBridge{T,S,A,V} <: SetMapBridge{T,S,MOI.SetDotProducts{S,A,V}} - variables::Vector{MOI.VariableIndex} - constraint::MOI.ConstraintIndex{MOI.VectorOfVariables,S} - set::MOI.SetDotProducts{S,A,V} -end - -function supports_constrained_variable( - ::Type{<:DotProductsBridge}, - ::Type{<:MOI.SetDotProducts}, -) - return true -end - -function concrete_bridge_type( - ::Type{<:DotProductsBridge{T}}, - ::Type{MOI.SetDotProducts{S,A,V}}, -) where {T,S,A,V} - return DotProductsBridge{T,S,A,V} -end - -function bridge_constrained_variable( - BT::Type{DotProductsBridge{T,S,A,V}}, - model::MOI.ModelLike, - set::MOI.SetDotProducts{S,A,V}, -) where {T,S,A,V} - variables, constraint = - _add_constrained_var(model, MOI.Bridges.inverse_map_set(BT, set)) - return BT(variables, constraint, set) -end - -function MOI.Bridges.map_set(bridge::DotProductsBridge{T,S}, ::S) where {T,S} - return bridge.set -end - -function MOI.Bridges.inverse_map_set( - ::Type{<:DotProductsBridge}, - set::MOI.SetDotProducts, -) - return set.set -end - -function MOI.Bridges.map_function( - bridge::DotProductsBridge{T}, - func, - i::MOI.Bridges.IndexInVector, -) where {T} - scalars = MOI.Utilities.eachscalar(func) - return MOI.Utilities.set_dot( - bridge.set.vectors[i.value], - scalars, - bridge.set.set, - ) -end - -function MOI.Bridges.map_function(bridge::DotProductsBridge{T}, func) where {T} - scalars = MOI.Utilities.eachscalar(func) - return MOI.Utilities.vectorize([ - MOI.Utilities.set_dot(vector, scalars, bridge.set.set) for - vector in bridge.set.vectors - ]) -end - -# This returns `true` by default for `SetMapBridge` -# but is is not supported for this bridge because `inverse_map_function` -# is not implemented -function MOI.supports( - ::MOI.ModelLike, - ::MOI.VariablePrimalStart, - ::Type{<:DotProductsBridge}, -) - return false -end - -function unbridged_map(::DotProductsBridge, ::Vector{MOI.VariableIndex}) - return nothing -end diff --git a/src/sets.jl b/src/sets.jl index 1ed64088d7..3e802db1aa 100644 --- a/src/sets.jl +++ b/src/sets.jl @@ -1824,12 +1824,18 @@ end dimension(s::SetDotProducts) = length(s.vectors) -function dual_set(s::SetDotProducts) - return LinearCombinationInSet(s.set, s.vectors) +function MOI.Bridges.Constraint.conversion_cost( + ::Type{SetDotProducts{S,A1,Vector{A1}}}, + ::Type{SetDotProducts{S,A2,Vector{A2}}}, +) where {S,A1,A2} + return MOI.Bridges.Constraint.conversion_cost(A1, A2) end -function dual_set_type(::Type{SetDotProducts{S,A,V}}) where {S,A,V} - return LinearCombinationInSet{S,A,V} +function convert( + ::Type{SetDotProducts{S,A,Vector{A}}}, + set::SetDotProducts, +) + return SetDotProducts(set.set, convert(A, set.vectors)) end """ @@ -1853,6 +1859,28 @@ end dimension(s::LinearCombinationInSet) = length(s.vectors) +function MOI.Bridges.Constraint.conversion_cost( + ::Type{LinearCombinationInSet{S,A1,Vector{A1}}}, + ::Type{LinearCombinationInSet{S,A2,Vector{A2}}}, +) where {S,A1,A2} + return MOI.Bridges.Constraint.conversion_cost(A1, A2) +end + +function convert( + ::Type{LinearCombinationInSet{S,A,Vector{A}}}, + set::LinearCombinationInSet, +) + return LinearCombinationInSet(set.set, convert(A, set.vectors)) +end + +function dual_set(s::SetDotProducts) + return LinearCombinationInSet(s.set, s.vectors) +end + +function dual_set_type(::Type{SetDotProducts{S,A,V}}) where {S,A,V} + return LinearCombinationInSet{S,A,V} +end + function dual_set(s::LinearCombinationInSet) return SetDotProducts(s.side_dimension, s.vectors) end @@ -1915,13 +1943,11 @@ function Base.getindex(m::Factorization, i::Int, j::Int) end """ - struct Factorization{ + struct PositiveSemidefiniteFactorization{ T, F<:Union{AbstractVector{T},AbstractMatrix{T}}, - D<:Union{T,AbstractVector{T}}, - } <: AbstractMatrix{T} + } <: AbstractFactorization{T,F} factor::F - scaling::D end Matrix corresponding to `factor * Diagonal(diagonal) * factor'`. @@ -1941,10 +1967,45 @@ function Base.getindex(m::PositiveSemidefiniteFactorization, i::Int, j::Int) return sum(m.factor[i, k] * m.factor[j, k]' for k in axes(m.factor, 2)) end +function MOI.Bridges.Constraint.conversion_cost( + ::Type{<:AbstractMatrix}, + ::Type{<:AbstractMatrix}, +) + return Inf +end + +function MOI.Bridges.Constraint.conversion_cost( + ::Type{<:Factorization{T,F}}, + ::Type{PositiveSemidefiniteFactorization{T,F}}, +) where {T,F} + return 1.0 +end + +function Base.convert( + ::Type{Factorization{T,F,D}}, + f::PositiveSemidefiniteFactorization{T,F}, +) where {F<:AbstractVector} + return Factorization{T,F,D}(f.factor, one(T)) +end + +function Base.convert( + ::Type{Factorization{T,F,D}}, + f::PositiveSemidefiniteFactorization{T,F}, +) where {F<:AbstractVector} + return Factorization{T,F,D}(f.factor, one(T)) +end + struct TriangleVectorization{T,M<:AbstractMatrix{T}} <: AbstractVector{T} matrix::M end +function MOI.Bridges.Constraint.conversion_cost( + ::Type{TriangleVectorization{T,M1}}, + ::Type{TriangleVectorization{T,M2}}, +) where {T,M1,M2} + return MOI.Bridges.Constraint.conversion_cost(M1, M2) +end + function Base.size(v::TriangleVectorization) n = size(v.matrix, 1) return (Utilities.trimap(n, n),)