Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Scaled{S<:AbstractSet} #2237

Merged
merged 3 commits into from
Sep 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/src/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [`hessian_objective_structure`](@ref)
- Added new sets
- [`NormCone`](@ref) (#2119)
- [`ScaledPositiveSemidefiniteConeTriangle`](@ref) (#2154)
- `ScaledPositiveSemidefiniteConeTriangle` (#2154)

### Fixed

Expand Down
2 changes: 1 addition & 1 deletion docs/src/manual/standard_form.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,13 @@ The matrix-valued set types implemented in MathOptInterface.jl are:
| [`RootDetConeSquare(d)`](@ref MathOptInterface.RootDetConeSquare) | ``\{ (t,X) \in \mathbb{R}^{1+d^2} : t \le \det(X)^{1/d}, X \mbox{ is a PSD matrix} \}`` |
| [`PositiveSemidefiniteConeTriangle(d)`](@ref MathOptInterface.PositiveSemidefiniteConeTriangle) | ``\{ X \in \mathbb{R}^{d(d+1)/2} : X \mbox{ is the upper triangle of a PSD matrix} \}`` |
| [`PositiveSemidefiniteConeSquare(d)`](@ref MathOptInterface.PositiveSemidefiniteConeSquare) | ``\{ X \in \mathbb{R}^{d^2} : X \mbox{ is a PSD matrix} \}`` |
| [`ScaledPositiveSemidefiniteConeTriangle(d)`](@ref MathOptInterface.ScaledPositiveSemidefiniteConeTriangle) | ``\{ X \in \mathbb{R}^{d(d+1)/2} : X \mbox{ is a PSD matrix} \}`` |
| [`LogDetConeTriangle(d)`](@ref MathOptInterface.LogDetConeTriangle) | ``\{ (t,u,X) \in \mathbb{R}^{2+d(1+d)/2} : t \le u\log(\det(X/u)), X \mbox{ is the upper triangle of a PSD matrix}, u > 0 \}`` |
| [`LogDetConeSquare(d)`](@ref MathOptInterface.LogDetConeSquare) | ``\{ (t,u,X) \in \mathbb{R}^{2+d^2} : t \le u \log(\det(X/u)), X \mbox{ is a PSD matrix}, u > 0 \}`` |
| [`NormSpectralCone(r, c)`](@ref MathOptInterface.NormSpectralCone) | ``\{ (t, X) \in \mathbb{R}^{1 + r \times c} : t \ge \sigma_1(X), X \mbox{ is a } r\times c\mbox{ matrix} \}``
| [`NormNuclearCone(r, c)`](@ref MathOptInterface.NormNuclearCone) | ``\{ (t, X) \in \mathbb{R}^{1 + r \times c} : t \ge \sum_i \sigma_i(X), X \mbox{ is a } r\times c\mbox{ matrix} \}`` |
| [`HermitianPositiveSemidefiniteConeTriangle(d)`](@ref MathOptInterface.HermitianPositiveSemidefiniteConeTriangle) | The cone of Hermitian positive semidefinite matrices, with
`side_dimension` rows and columns. |
| [`Scaled(S)`](@ref MathOptInterface.Scaled) | The set `S` scaled so that [`Utilities.set_dot`](@ref MathOptInterface.Utilities.set_dot) corresponds to `LinearAlgebra.dot` |

Some of these cones can take two forms: `XXXConeTriangle` and `XXXConeSquare`.

Expand Down
2 changes: 1 addition & 1 deletion docs/src/reference/standard_form.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ SOS2
Indicator
Complements
HyperRectangle
Scaled
```

## Constraint programming sets
Expand Down Expand Up @@ -148,7 +149,6 @@ List of recognized matrix sets.
PositiveSemidefiniteConeTriangle
PositiveSemidefiniteConeSquare
HermitianPositiveSemidefiniteConeTriangle
ScaledPositiveSemidefiniteConeTriangle
LogDetConeTriangle
LogDetConeSquare
RootDetConeTriangle
Expand Down
4 changes: 2 additions & 2 deletions docs/src/submodules/Bridges/list_of_bridges.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ Bridges.Constraint.NormSpectralBridge
Bridges.Constraint.NormNuclearBridge
Bridges.Constraint.SquareBridge
Bridges.Constraint.HermitianToSymmetricPSDBridge
Bridges.Constraint.SymmetricMatrixScalingBridge
Bridges.Constraint.SymmetricMatrixInverseScalingBridge
Bridges.Constraint.SetDotScalingBridge
Bridges.Constraint.SetDotInverseScalingBridge
Bridges.Constraint.RootDetBridge
Bridges.Constraint.LogDetBridge
Bridges.Constraint.IndicatorActiveOnFalseBridge
Expand Down
9 changes: 3 additions & 6 deletions src/Bridges/Constraint/Constraint.jl
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ include("bridges/split_complex_zeros.jl")
include("bridges/split_hyperrectangle.jl")
include("bridges/hermitian.jl")
include("bridges/square.jl")
include("bridges/symmetric_matrix_scaling.jl")
include("bridges/set_dot_scaling.jl")
include("bridges/table.jl")
include("bridges/vectorize.jl")
include("bridges/zero_one.jl")
Expand Down Expand Up @@ -109,11 +109,8 @@ function add_all_bridges(bridged_model, ::Type{T}) where {T}
MOI.Bridges.add_bridge(bridged_model, NormNuclearBridge{T})
MOI.Bridges.add_bridge(bridged_model, HermitianToSymmetricPSDBridge{T})
MOI.Bridges.add_bridge(bridged_model, SquareBridge{T})
MOI.Bridges.add_bridge(bridged_model, SymmetricMatrixScalingBridge{T})
MOI.Bridges.add_bridge(
bridged_model,
SymmetricMatrixInverseScalingBridge{T},
)
MOI.Bridges.add_bridge(bridged_model, SetDotScalingBridge{T})
MOI.Bridges.add_bridge(bridged_model, SetDotInverseScalingBridge{T})
MOI.Bridges.add_bridge(bridged_model, LogDetBridge{T})
MOI.Bridges.add_bridge(bridged_model, RootDetBridge{T})
MOI.Bridges.add_bridge(bridged_model, RSOCtoSOCBridge{T})
Expand Down
212 changes: 212 additions & 0 deletions src/Bridges/Constraint/bridges/set_dot_scaling.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
# 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.

"""
SetDotScalingBridge{T,S,F,G} <: Bridges.Constraint.AbstractBridge

`SetDotScalingBridge` implements the reformulation from constraints
in `S` to constraints in [`MOI.Scaled{S}`](@ref MOI.Scaled).

## Source node

`SetDotScalingBridge` supports:

* `G` in `S`

## Target node

`SetDotScalingBridge` creates:

* `F` in [`MOI.Scaled{S}`](@ref MOI.Scaled)
"""
struct SetDotScalingBridge{T,S,F,G} <: SetMapBridge{T,MOI.Scaled{S},S,F,G}
constraint::MOI.ConstraintIndex{F,MOI.Scaled{S}}
end

const SetDotScaling{T,OT<:MOI.ModelLike} =
SingleBridgeOptimizer{SetDotScalingBridge{T},OT}

function concrete_bridge_type(
::Type{<:SetDotScalingBridge{T}},
G::Type{<:MOI.AbstractVectorFunction},
::Type{S},
) where {T,S<:MOI.AbstractVectorSet}
F = MOI.Utilities.promote_operation(
*,
T,
LinearAlgebra.Diagonal{T,Vector{T}},
G,
)
return SetDotScalingBridge{T,S,F,G}
end

function MOI.Bridges.map_set(
::Type{<:SetDotScalingBridge{T,S}},
set::S,
) where {T,S}
return MOI.Scaled(set)
end

function MOI.Bridges.inverse_map_set(
::Type{<:SetDotScalingBridge{T,S}},
set::MOI.Scaled{S},
) where {T,S}
return set.set
end

_length(f::MOI.AbstractVectorFunction) = MOI.output_dimension(f)
_length(f::AbstractVector) = length(f)

function _scale(::Type{T}, ::Type{S}, func) where {T,S}
set = MOI.Utilities.set_with_dimension(S, _length(func))
scale = MOI.Utilities.SetDotScalingVector{T}(set)
return MOI.Utilities.operate(*, T, LinearAlgebra.Diagonal(scale), func)
end

function _inverse_scale(::Type{T}, ::Type{S}, func) where {T,S}
set = MOI.Utilities.set_with_dimension(S, _length(func))
scale = MOI.Utilities.SetDotScalingVector{T}(set)
inv_scale = MOI.Utilities.lazy_map(T, inv, scale)
return MOI.Utilities.operate(*, T, LinearAlgebra.Diagonal(inv_scale), func)
end

function MOI.Bridges.map_function(
::Type{<:SetDotScalingBridge{T,S}},
func,
) where {T,S}
return _scale(T, S, func)
end

function MOI.Bridges.inverse_map_function(
::Type{<:SetDotScalingBridge{T,S}},
func,
) where {T,S}
return _inverse_scale(T, S, func)
end

# Since the map is a diagonal matrix `D`, it is symmetric so one would initially
# expect `adjoint_map_function` to be the same as `map_function`. However, the
# scalar product for the scaled PSD cone is `<x, y>_2 = x'y` but the scalar
# product for the PSD cone additionally scales the offdiagonal entries by `2`
# hence by `D^2` so `<x, y>_1 = x'D^2y`.
# So `<Dx, y>_2 = <x, D^(-1)y>_1` hence the adjoint of `D` is its inverse!
function MOI.Bridges.adjoint_map_function(
::Type{<:SetDotScalingBridge{T,S}},
func,
) where {T,S}
return _inverse_scale(T, S, func)
end

function MOI.Bridges.inverse_adjoint_map_function(
::Type{<:SetDotScalingBridge{T,S}},
func,
) where {T,S}
return _scale(T, S, func)
end

"""
SetDotInverseScalingBridge{T,S,F,G} <: Bridges.Constraint.AbstractBridge

`SetDotInverseScalingBridge` implements the reformulation from constraints
in the `MOI.Scaled{S}` to constraints in the `S`.

## Source node

`SetDotInverseScalingBridge` supports:

* `G` in [`MOI.Scaled{S}`](@ref MOI.Scaled)

## Target node

`SetDotInverseScalingBridge` creates:

* `F` in `S`
"""
struct SetDotInverseScalingBridge{T,S,F,G} <:
SetMapBridge{T,S,MOI.Scaled{S},F,G}
constraint::MOI.ConstraintIndex{F,S}
end

const SetDotInverseScaling{T,OT<:MOI.ModelLike} =
SingleBridgeOptimizer{SetDotInverseScalingBridge{T},OT}

function concrete_bridge_type(
::Type{<:SetDotInverseScalingBridge{T}},
G::Type{<:MOI.AbstractVectorFunction},
::Type{MOI.Scaled{S}},
) where {T,S<:MOI.AbstractVectorSet}
F = MOI.Utilities.promote_operation(
*,
T,
LinearAlgebra.Diagonal{T,Vector{T}},
G,
)
return SetDotInverseScalingBridge{T,S,F,G}
end

function MOI.Bridges.map_set(
::Type{<:SetDotInverseScalingBridge{T,S}},
set::MOI.Scaled{S},
) where {T,S}
return set.set
end

function MOI.Bridges.inverse_map_set(
::Type{<:SetDotInverseScalingBridge{T,S}},
set::S,
) where {T,S}
return MOI.Scaled(set)
end

function MOI.Bridges.map_function(
::Type{<:SetDotInverseScalingBridge{T,S}},
func,
) where {T,S}
return _inverse_scale(T, S, func)
end

function MOI.Bridges.inverse_map_function(
::Type{<:SetDotInverseScalingBridge{T,S}},
func,
) where {T,S}
return _scale(T, S, func)
end

function MOI.Bridges.adjoint_map_function(
::Type{<:SetDotInverseScalingBridge{T,S}},
func,
) where {T,S}
return _inverse_scale(T, S, func)
end

function MOI.Bridges.inverse_adjoint_map_function(
::Type{<:SetDotInverseScalingBridge{T,S}},
func,
) where {T,S}
return _scale(T, S, func)
end

# Since the set type is not defined, the default `MOI.supports_constraint`
# for `SetMapBridge` does not work
function MOI.supports_constraint(
::Type{<:SetDotScalingBridge},
::Type{<:MOI.AbstractVectorFunction},
S::Type{<:MOI.AbstractVectorSet},
)
return MOI.is_set_dot_scaled(S)
end

function MOI.supports_constraint(
::Type{<:SetDotInverseScalingBridge},
::Type{<:MOI.AbstractVectorFunction},
::Type{MOI.Scaled{S}},
) where {S<:MOI.AbstractVectorSet}
return true
end

# TODO remove in MOI v2
const SymmetricMatrixScalingBridge = SetDotScalingBridge
const SymmetricMatrixInverseScalingBridge = SetDotInverseScalingBridge
Loading
Loading