Skip to content

Commit

Permalink
[Bridges] restrict some bridges to acting on real-valued functions (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
odow authored Apr 8, 2024
1 parent b852738 commit ec3d524
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 13 deletions.
2 changes: 1 addition & 1 deletion src/Bridges/Constraint/bridges/functionize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ function MOI.supports_constraint(
::Type{G},
::Type{<:MOI.AbstractSet},
) where {T,F,G<:MOI.AbstractFunction}
return isfinite(conversion_cost(F, G))
return MOI.Utilities.is_maybe_real(G) && isfinite(conversion_cost(F, G))
end

function concrete_bridge_type(
Expand Down
6 changes: 3 additions & 3 deletions src/Bridges/Constraint/bridges/norm_one.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ end

function MOI.supports_constraint(
::Type{NormOneBridge{T}},
::Type{<:MOI.AbstractVectorFunction},
::Type{F},
::Type{MOI.NormOneCone},
) where {T}
return true
) where {T,F<:MOI.AbstractVectorFunction}
return MOI.Utilities.is_maybe_real(F)
end

function MOI.Bridges.added_constrained_variable_types(::Type{<:NormOneBridge})
Expand Down
6 changes: 3 additions & 3 deletions src/Bridges/Constraint/bridges/vectorize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ end

function MOI.supports_constraint(
::Type{VectorizeBridge{T}},
::Type{<:MOI.AbstractScalarFunction},
::Type{F},
::Type{<:MOI.Utilities.ScalarLinearSet{T}},
) where {T}
return true
) where {T,F<:MOI.AbstractScalarFunction}
return MOI.Utilities.is_maybe_real(F)
end

function MOI.Bridges.added_constrained_variable_types(::Type{<:VectorizeBridge})
Expand Down
12 changes: 6 additions & 6 deletions src/Bridges/Constraint/set_map.jl
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,18 @@ end

function MOI.supports_constraint(
::Type{<:MultiSetMapBridge{T,S1}},
::Type{<:MOI.AbstractScalarFunction},
::Type{F},
::Type{S1},
) where {T,S1<:MOI.AbstractScalarSet}
return true
) where {T,S1<:MOI.AbstractScalarSet,F<:MOI.AbstractScalarFunction}
return MOI.Utilities.is_maybe_real(F)
end

function MOI.supports_constraint(
::Type{<:MultiSetMapBridge{T,S1}},
::Type{<:MOI.AbstractVectorFunction},
::Type{F},
::Type{S1},
) where {T,S1<:MOI.AbstractVectorSet}
return true
) where {T,S1<:MOI.AbstractVectorSet,F<:MOI.AbstractVectorFunction}
return MOI.Utilities.is_maybe_real(F)
end

function MOI.Bridges.added_constrained_variable_types(
Expand Down
34 changes: 34 additions & 0 deletions src/Utilities/functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2492,3 +2492,37 @@ function constant_vector(
)
return f.constants
end

"""
is_maybe_real(::Type{<:MOI.AbstractFunction})
Return `true` if the function type may return `<:Real` values. It returns false
for Complex-valued functions.
This function defaults to returning a false positive (`true`). If your new
function explicitly returns complex values, opt-out by defining a new method.
This function is mostly intended for use in the `MOI.Bridges` submodule to
identify when bridges are not applicable (because the function is
complex-valued).
## Example
```jldoctest
julia> import MathOptInterface as MOI
julia> MOI.Utilities.is_maybe_real(MOI.VariableIndex)
true
julia> MOI.Utilities.is_maybe_real(MOI.ScalarAffineFunction{Complex{Int}})
false
julia> MOI.Utilities.is_maybe_real(MOI.ScalarNonlinearFunction)
true
```
"""
is_maybe_real(::Type{<:MOI.AbstractFunction}) = true
is_maybe_real(::Type{<:MOI.ScalarAffineFunction{<:Complex}}) = false
is_maybe_real(::Type{<:MOI.VectorAffineFunction{<:Complex}}) = false
is_maybe_real(::Type{<:MOI.ScalarQuadraticFunction{<:Complex}}) = false
is_maybe_real(::Type{<:MOI.VectorQuadraticFunction{<:Complex}}) = false
106 changes: 106 additions & 0 deletions test/Bridges/lazy_bridge_optimizer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2131,6 +2131,112 @@ function test_delete_index_in_vector(T::Type = Float64)
return
end

function test_bridge_complex_norminfinitycone()
model = MOI.instantiate(
MOI.Utilities.Model{Float64};
with_bridge_type = Float64,
)
x = MOI.add_variable(model)
t = MOI.add_variable(model)
f = (1.0 + 0.0im) * x + 2.0 * im
g = MOI.Utilities.operate(vcat, Complex{Float64}, t, f)
@test_throws(
MOI.UnsupportedConstraint,
MOI.add_constraint(model, g, MOI.NormInfinityCone(2)),
)
return
end

function test_bridge_complex_normonecone()
model = MOI.instantiate(
MOI.Utilities.Model{Float64};
with_bridge_type = Float64,
)
x = MOI.add_variable(model)
t = MOI.add_variable(model)
f = (1.0 + 0.0im) * x + 2.0 * im
g = MOI.Utilities.operate(vcat, Complex{Float64}, t, f)
@test_throws(
MOI.UnsupportedConstraint,
MOI.add_constraint(model, g, MOI.NormOneCone(2)),
)
return
end

function test_bridge_complex_secondorder()
model = MOI.instantiate(
MOI.Utilities.Model{Float64};
with_bridge_type = Float64,
)
x = MOI.add_variable(model)
t = MOI.add_variable(model)
f = (1.0 + 0.0im) * x + 2.0 * im
g = MOI.Utilities.operate(vcat, Complex{Float64}, t, f)
@test_throws(
MOI.UnsupportedConstraint,
MOI.add_constraint(model, g, MOI.SecondOrderCone(2)),
)
return
end

function test_bridge_complex_nonnegtononpos()
model = MOI.instantiate(
MOI.Utilities.Model{Float64};
with_bridge_type = Float64,
)
x = MOI.add_variable(model)
f = (1.0 + 0.0im) * x + 2.0 * im
g = MOI.Utilities.operate(vcat, Complex{Float64}, f)
@test_throws(
MOI.UnsupportedConstraint,
MOI.add_constraint(model, g, MOI.Nonnegatives(1)),
)
return
end

function test_bridge_complex_nonpostononneg()
model = MOI.instantiate(
MOI.Utilities.Model{Float64};
with_bridge_type = Float64,
)
x = MOI.add_variable(model)
f = (1.0 + 0.0im) * x + 2.0 * im
g = MOI.Utilities.operate(vcat, Complex{Float64}, f)
@test_throws(
MOI.UnsupportedConstraint,
MOI.add_constraint(model, g, MOI.Nonpositives(1)),
)
return
end

function test_bridge_complex_greatertoless()
model = MOI.instantiate(
MOI.Utilities.Model{Float64};
with_bridge_type = Float64,
)
x = MOI.add_variable(model)
f = (1.0 + 0.0im) * x + 2.0 * im
@test_throws(
MOI.UnsupportedConstraint,
MOI.add_constraint(model, f, MOI.LessThan(1.0)),
)
return
end

function test_bridge_complex_greatertoless()
model = MOI.instantiate(
MOI.Utilities.Model{Float64};
with_bridge_type = Float64,
)
x = MOI.add_variable(model)
f = (1.0 + 0.0im) * x + 2.0 * im
@test_throws(
MOI.UnsupportedConstraint,
MOI.add_constraint(model, f, MOI.GreaterThan(1.0))
)
return
end

end # module

TestBridgesLazyBridgeOptimizer.runtests()

0 comments on commit ec3d524

Please sign in to comment.