Skip to content

Commit

Permalink
Add bridge
Browse files Browse the repository at this point in the history
  • Loading branch information
blegat committed Dec 5, 2024
1 parent 01fa32c commit 114fa43
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 9 deletions.
1 change: 1 addition & 0 deletions src/Bridges/Variable/Variable.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ function add_all_bridges(model, ::Type{T}) where {T}
MOI.Bridges.add_bridge(model, RSOCtoPSDBridge{T})
MOI.Bridges.add_bridge(model, HermitianToSymmetricPSDBridge{T})
MOI.Bridges.add_bridge(model, ParameterToEqualToBridge{T})
MOI.Bridges.add_bridge(model, DotProductsBridge{T})
return
end

Expand Down
62 changes: 62 additions & 0 deletions src/Bridges/Variable/bridges/set_dot.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
struct DotProductsBridge{T,S,V} <: SetMapBridge{T,S,MOI.SetWithDotProducts{S,V}}
variables::Vector{MOI.VariableIndex}
constraint::MOI.ConstraintIndex{MOI.VectorOfVariables, S}
set::MOI.SetWithDotProducts{S,V}
end

function supports_constrained_variable(
::Type{<:DotProductsBridge},
::Type{<:MOI.SetWithDotProducts},
)
return true
end

function concrete_bridge_type(
::Type{<:DotProductsBridge{T}},
::Type{MOI.SetWithDotProducts{S,V}},
) where {T,S,V}
return DotProductsBridge{T,S,V}
end

function bridge_constrained_variable(
BT::Type{DotProductsBridge{T,S,V}},
model::MOI.ModelLike,
set::MOI.SetWithDotProducts{S,V},
) where {T,S,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},
set::S,
) where {T,S}
return MOI.SetWithDotProducts(set, bridge.vectors)
end

function MOI.Bridges.inverse_map_set(
::Type{<:DotProductsBridge},
set::MOI.SetWithDotProducts,
)
return set.set
end

function MOI.Bridges.map_function(
bridge::DotProductsBridge{T},
func,
i::MOI.Bridges.IndexInVector,
) where {T}
scalars = MOI.Utilities.eachscalar(func)
if i.value in eachindex(bridge.set.vectors)
return MOI.Utilities.set_dot(bridge.set.vectors[i.value], scalars, bridge.set.set)
else
return convert(MOI.ScalarAffineFunction{T}, scalars[i.value - length(bridge.vectors)])
end
end

function MOI.Bridges.inverse_map_function(bridge::DotProductsBridge{T}, func) where {T}
m = length(bridge.set.vectors)
return MOI.Utilities.operate(vcat, T, MOI.Utilities.eachscalar(func)[(m+1):end])
end

11 changes: 6 additions & 5 deletions src/Bridges/Variable/set_map.jl
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ function MOI.get(
if any(isnothing, value)
return nothing
end
return MOI.Bridges.map_function(typeof(bridge), value, i)
return MOI.Bridges.map_function(bridge, value, i)
end

function MOI.supports(
Expand Down Expand Up @@ -203,7 +203,7 @@ function MOI.Bridges.bridged_function(
i::MOI.Bridges.IndexInVector,
) where {T}
func = MOI.Bridges.map_function(
typeof(bridge),
bridge,
MOI.VectorOfVariables(bridge.variables),
i,
)
Expand All @@ -212,7 +212,7 @@ end

function unbridged_map(bridge::SetMapBridge{T}, vi::MOI.VariableIndex) where {T}
F = MOI.ScalarAffineFunction{T}
mapped = MOI.Bridges.inverse_map_function(typeof(bridge), vi)
mapped = MOI.Bridges.inverse_map_function(bridge, vi)
return Pair{MOI.VariableIndex,F}[bridge.variable=>mapped]
end

Expand All @@ -222,9 +222,10 @@ function unbridged_map(
) where {T}
F = MOI.ScalarAffineFunction{T}
func = MOI.VectorOfVariables(vis)
funcs = MOI.Bridges.inverse_map_function(typeof(bridge), func)
funcs = MOI.Bridges.inverse_map_function(bridge, func)
scalars = MOI.Utilities.eachscalar(funcs)
# FIXME not correct for SetWithDotProducts, it won't recover the dot product variables
return Pair{MOI.VariableIndex,F}[
bridge.variables[i] => scalars[i] for i in eachindex(vis)
bridge.variables[i] => scalars[i] for i in eachindex(bridge.variables)
]
end
4 changes: 4 additions & 0 deletions src/Bridges/set_map.jl
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ function map_function(::Type{BT}, func, i::IndexInVector) where {BT}
return MOI.Utilities.eachscalar(map_function(BT, func))[i.value]
end

function map_function(bridge::AbstractBridge, func, i::IndexInVector)
return map_function(typeof(bridge), func, i)
end

"""
inverse_map_function(bridge::MOI.Bridges.AbstractBridge, func)
inverse_map_function(::Type{BT}, func) where {BT}
Expand Down
9 changes: 7 additions & 2 deletions src/Utilities/functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -638,18 +638,23 @@ end
A type that allows iterating over the scalar-functions that comprise an
`AbstractVectorFunction`.
"""
struct ScalarFunctionIterator{F<:MOI.AbstractVectorFunction,C}
struct ScalarFunctionIterator{F<:MOI.AbstractVectorFunction,C,S} <: AbstractVector{S}
f::F
# Cache that can be used to store a precomputed datastructure that allows
# an efficient implementation of `getindex`.
cache::C
function ScalarFunctionIterator(f::MOI.AbstractVectorFunction, cache)
return new{typeof(f),typeof(cache),scalar_type(typeof(f))}(f, cache)
end
end

function ScalarFunctionIterator(func::MOI.AbstractVectorFunction)
return ScalarFunctionIterator(func, scalar_iterator_cache(func))
end

scalar_iterator_cache(func::MOI.AbstractVectorFunction) = nothing
Base.size(s::ScalarFunctionIterator) = (MOI.output_dimension(s.f),)

scalar_iterator_cache(::MOI.AbstractVectorFunction) = nothing

function output_index_iterator(terms::AbstractVector, output_dimension)
start = zeros(Int, output_dimension)
Expand Down
22 changes: 20 additions & 2 deletions src/sets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1855,15 +1855,33 @@ end
`factor * Diagonal(diagonal) * factor'`.
"""
struct LowRankMatrix{T}
struct LowRankMatrix{T} <: AbstractMatrix{T}
diagonal::Vector{T}
factor::Matrix{T}
end

struct TriangleVectorization{M}
function Base.size(m::LowRankMatrix)
n = size(m.factor, 1)
return (n, n)
end

function Base.getindex(m::LowRankMatrix, i::Int, j::Int)
return sum(m.factor[i, k] * m.diagonal[k] * m.factor[j, k]' for k in eachindex(m.diagonal))
end

struct TriangleVectorization{T,M<:AbstractMatrix{T}} <: AbstractVector{T}
matrix::M
end

function Base.size(v::TriangleVectorization)
n = size(v.matrix, 1)
return (Utilities.trimap(n, n),)
end

function Base.getindex(v::TriangleVectorization, k::Int)
return getindex(v.matrix, Utilities.inverse_trimap(k)...)
end

"""
SOS1{T<:Real}(weights::Vector{T})
Expand Down

0 comments on commit 114fa43

Please sign in to comment.