Skip to content
Draft
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
1 change: 1 addition & 0 deletions docs/src/manual/standard_form.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ The one-dimensional set types implemented in MathOptInterface.jl are:
| [`ZeroOne()`](@ref) | ``\{ 0, 1 \}`` |
| [`Semicontinuous(l, u)`](@ref) | ``\{ 0\} \cup [l, u]`` |
| [`Semiinteger(l, u)`](@ref) | ``\{ 0\} \cup \{l,l+1,\ldots,u-1,u\}`` |
| [`LazyScalarSet(set)`](@ref) | ``set`` |

## Vector cones

Expand Down
1 change: 1 addition & 0 deletions docs/src/reference/standard_form.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ ZeroOne
Semicontinuous
Semiinteger
Parameter
LazyScalarSet
```

## Vector sets
Expand Down
1 change: 1 addition & 0 deletions src/Bridges/Constraint/Constraint.jl
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ function add_all_bridges(model, ::Type{T}) where {T}
# It is also really useful only to PATHSolver.jl, which could add this
# to MOI.ListOfRequiredBridges.
MOI.Bridges.add_bridge(model, IntegerToZeroOneBridge{T})
MOI.Bridges.add_bridge(model, LazyScalarSetBridge{T})
MOI.Bridges.add_bridge(model, LessToGreaterBridge{T})
if T <: AbstractFloat # See note in docstring of AbstractToIntervalBridge
MOI.Bridges.add_bridge(model, LessToIntervalBridge{T})
Expand Down
80 changes: 80 additions & 0 deletions src/Bridges/Constraint/bridges/LazyScalarSetBridge.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# 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.

"""
LazyScalarSetBridge{
T,
F<:MOI.AbstractScalarFunction,
S<:MOI.AbstractScalarSet,
}

`LazyScalarSetBridge` implements the following reformulation:

* ``f \\in LazyScalarSet(s)`` into ``f \\in s``.

## Source node

`LazyScalarSetBridge` supports:

* `F` in `LazyScalarSet{S}`

## Target nodes

`LazyScalarSetBridge` creates:

* `F` in `S`
"""
struct LazyScalarSetBridge{
T,
F<:MOI.AbstractScalarFunction,
S<:MOI.AbstractScalarSet,
} <: MOI.Bridges.Constraint.SetMapBridge{T,S,MOI.LazyScalarSet{S},F,F}
constraint::MOI.ConstraintIndex{F,S}

function LazyScalarSetBridge{T,F,S}(
constraint::MOI.ConstraintIndex{F,S},
) where {T,F<:MOI.AbstractScalarFunction,S<:MOI.AbstractScalarSet}
return new{T,F,S}(constraint)
end
end

MOI.Bridges.map_function(::Type{<:LazyScalarSetBridge}, f) = f

MOI.Bridges.inverse_map_function(::Type{<:LazyScalarSetBridge}, f) = f

MOI.Bridges.adjoint_map_function(::Type{<:LazyScalarSetBridge}, f) = f

MOI.Bridges.inverse_adjoint_map_function(::Type{<:LazyScalarSetBridge}, f) = f

function MOI.Bridges.map_set(
::Type{LazyScalarSetBridge{T,F,S}},
set::MOI.LazyScalarSet{S},
) where {T,F,S}
return set.set
end

function MOI.Bridges.inverse_map_set(
::Type{LazyScalarSetBridge{T,F,S}},
set::S,
) where {T,F,S}
return MOI.LazyScalarSet(set)
end

function MOI.supports_constraint(
::Type{<:LazyScalarSetBridge},
::Type{<:MOI.AbstractScalarFunction},
::Type{<:MOI.LazyScalarSet},
)
return true
end

function MOI.Bridges.Constraint.concrete_bridge_type(
::Type{<:LazyScalarSetBridge{T}},
::Type{F},
::Type{MOI.LazyScalarSet{S}},
) where {T,F<:MOI.AbstractScalarFunction,S<:MOI.AbstractScalarSet}
return LazyScalarSetBridge{T,F,S}
end
10 changes: 10 additions & 0 deletions src/Utilities/sets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@ end

supports_shift_constant(::Type{<:MOI.Parameter}) = true

function supports_shift_constant(
::Type{MOI.LazyScalarSet{S}},
) where {S<:MOI.AbstractScalarSet}
return supports_shift_constant(S)
end

function shift_constant(set::MOI.LazyScalarSet, constant)
return MOI.LazyScalarSet(shift_constant(set.set, constant))
end

"""
ScalarLinearSet{T}

Expand Down
27 changes: 27 additions & 0 deletions src/sets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2866,6 +2866,33 @@ function Base.show(io::IO, s::VectorNonlinearOracle{T}) where {T}
return
end

"""
LazyScalarSet(set::AbstractScalarSet) <: AbstractScalarSet

A set that wraps an inner `set` with a hint that the constraint can be treated
lazily by the solver.

## Example

```jldoctest
julia> model = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}());

julia> x = MOI.add_variable(model);

julia> MOI.add_constraint(
model,
1.0 * x,
MOI.LazyScalarSet(MOI.GreaterThan(1.0)),
)
MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.LazyScalarSet{MathOptInterface.GreaterThan{Float64}}}(1)
```
"""
struct LazyScalarSet{S<:AbstractScalarSet} <: AbstractScalarSet
set::S
end

Base.copy(set::LazyScalarSet) = LazyScalarSet(copy(set.set))

# TODO(odow): these are not necessarily isbits. They may not be safe to return
# without copying if the number is BigFloat, for example.
function Base.copy(
Expand Down
41 changes: 41 additions & 0 deletions test/Bridges/Constraint/test_LazyScalarSetBridge.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# 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.

module TestConstraintLazyScalarSetBridge

using Test

import MathOptInterface as MOI

function runtests()
for name in names(@__MODULE__; all = true)
if startswith("$(name)", "test_")
@testset "$(name)" begin
getfield(@__MODULE__, name)()
end
end
end
return
end

function test_runtests_scalar_affine_function()
MOI.Bridges.runtests(
MOI.Bridges.Constraint.LazyScalarSetBridge,
"""
variables: x
1.0 * x in LazyScalarSet(GreaterThan(0.0))
""",
"""
variables: x
1.0 * x in GreaterThan(0.0)
""",
)
return
end

end # module

TestConstraintLazyScalarSetBridge.runtests()
13 changes: 13 additions & 0 deletions test/Utilities/test_sets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,19 @@ function test_set_dot_scaling(n = 10)
return
end

function test_lazy_scalar_set()
set = MOI.LazyScalarSet(MOI.GreaterThan(1.0))
set_2 = copy(set)
@test set_2 == set
@test MOI.Utilities.supports_shift_constant(typeof(set))
set = MOI.Utilities.shift_constant(set, 2.0)
@test set_2 != set
@test set == MOI.LazyScalarSet(MOI.GreaterThan(3.0))
set = MOI.LazyScalarSet(MOI.Integer())
@test !MOI.Utilities.supports_shift_constant(typeof(set))
return
end

end # module

TestUtilitiesSets.runtests()
Loading