Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
odow committed Dec 12, 2024
1 parent ac964c4 commit 4050b4e
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,24 @@
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.

"""
ComplementsToScalarNonlinearFunctionBridge{T,F} <:
ComplementsToScalarNonlinearFunctionBridge{T,F,G} <:
Bridges.Constraint.AbstractBridge
`ComplementsToScalarNonlinearFunctionBridge` implements the following
reformulation:
* ``(F, x) \\in \\textsf{Complements}()`` to
``y - F = 0`` and
```julia
if isfinite(l)
(x - l) * F <= 0.0
(x - l) * y <= 0.0
else
1.0 * F <= 0.0
y <= 0
end
if isfinite(u)
(x - u) * F <= 0.0
(x - u) * y <= 0.0
else
-1.0 * F <= 0.0
y >= 0
end
```
Expand All @@ -35,7 +36,9 @@ reformulation:
`ComplementsToScalarNonlinearFunctionBridge` creates:
* [`MOI.ScalarNonlinearFunction`](@ref) in [`MOI.LessThan{T}`](@ref)
* `G` in [`MOI.EqualTo{T}`](@ref)
* [`MOI.ScalarQuadraticFunction`](@ref) in [`MOI.LessThan{T}`](@ref)
* [`MOI.VariableIndex`](@ref) in [`MOI.Interval{T}`](@ref)
"""
mutable struct ComplementsToScalarNonlinearFunctionBridge{
T,
Expand All @@ -45,24 +48,38 @@ mutable struct ComplementsToScalarNonlinearFunctionBridge{
MOI.VectorQuadraticFunction{T},
MOI.VectorNonlinearFunction,
},
G,
} <: AbstractBridge
f::F
ci::Vector{MOI.ConstraintIndex{MOI.ScalarNonlinearFunction,MOI.LessThan{T}}}
y::Vector{MOI.VariableIndex}
ci_eq::Vector{MOI.ConstraintIndex{G,MOI.EqualTo{T}}}
ci_lt::Vector{
MOI.ConstraintIndex{MOI.ScalarQuadraticFunction{T},MOI.LessThan{T}}
}
bounds::Vector{NTuple{2,T}}
function ComplementsToScalarNonlinearFunctionBridge{T}(
f,

function ComplementsToScalarNonlinearFunctionBridge{T,F,G}(
f::F,
::MOI.Complements,
) where {T}
ci = MOI.ConstraintIndex{MOI.ScalarNonlinearFunction,MOI.LessThan{T}}[]
return new{T,typeof(f)}(f, ci, NTuple{2,T}[])
) where {T,F,G}
return new{T,F,G}(
f,
MOI.VariableIndex[],
MOI.ConstraintIndex{G,MOI.EqualTo{T}}[],
MOI.ConstraintIndex{
MOI.ScalarQuadraticFunction{T},
MOI.LessThan{T},
}[],
NTuple{2,T}[],
)
end
end

const ComplementsToScalarNonlinearFunction{T,OT<:MOI.ModelLike} =
SingleBridgeOptimizer{ComplementsToScalarNonlinearFunctionBridge{T},OT}

function bridge_constraint(
::Type{ComplementsToScalarNonlinearFunctionBridge{T,F}},
::Type{ComplementsToScalarNonlinearFunctionBridge{T,F,G}},
model::MOI.ModelLike,
f::F,
s::MOI.Complements,
Expand All @@ -74,10 +91,11 @@ function bridge_constraint(
MOI.VectorQuadraticFunction{T},
MOI.VectorNonlinearFunction,
},
G,
}
# !!! info
# Postpone creation until final_touch.
return ComplementsToScalarNonlinearFunctionBridge{T}(f, s)
return ComplementsToScalarNonlinearFunctionBridge{T,F,G}(f, s)
end

function MOI.supports_constraint(
Expand All @@ -97,15 +115,18 @@ function MOI.supports_constraint(
end

function MOI.Bridges.added_constrained_variable_types(
::Type{<:ComplementsToScalarNonlinearFunctionBridge},
)
return Tuple{Type}[]
::Type{ComplementsToScalarNonlinearFunctionBridge{T,F,G}},
) where {T,F,G}
return Tuple{Type}[(MOI.Interval{T},)]
end

function MOI.Bridges.added_constraint_types(
::Type{<:ComplementsToScalarNonlinearFunctionBridge{T}},
) where {T}
return Tuple{Type,Type}[(MOI.ScalarNonlinearFunction, MOI.LessThan{T})]
::Type{ComplementsToScalarNonlinearFunctionBridge{T,F,G}},
) where {T,F,G}
return Tuple{Type,Type}[
(G, MOI.EqualTo{T}),
(MOI.ScalarQuadraticFunction{T}, MOI.LessThan{T}),
]
end

function concrete_bridge_type(
Expand All @@ -121,7 +142,13 @@ function concrete_bridge_type(
MOI.VectorNonlinearFunction,
},
}
return ComplementsToScalarNonlinearFunctionBridge{T,F}
G = MOI.Utilities.promote_operation(
-,
T,
MOI.Utilities.scalar_type(F),
MOI.VariableIndex,
)
return ComplementsToScalarNonlinearFunctionBridge{T,F,G}
end

function MOI.get(
Expand All @@ -145,37 +172,72 @@ function MOI.delete(
model::MOI.ModelLike,
bridge::ComplementsToScalarNonlinearFunctionBridge,
)
MOI.delete.(model, bridge.ci)
MOI.delete.(model, bridge.y)
MOI.delete.(model, bridge.ci_eq)
MOI.delete.(model, bridge.ci_lt)
empty!(bridge.bounds)
return
end

function MOI.get(
::ComplementsToScalarNonlinearFunctionBridge,
bridge::ComplementsToScalarNonlinearFunctionBridge,
::MOI.NumberOfVariables,
)::Int64
return 0
return length(bridge.y)
end

function MOI.get(
::ComplementsToScalarNonlinearFunctionBridge,
bridge::ComplementsToScalarNonlinearFunctionBridge,
::MOI.ListOfVariableIndices,
)::Vector{MOI.VariableIndex}
return MOI.VariableIndex[]
return copy(bridge.y)
end

function MOI.get(
bridge::ComplementsToScalarNonlinearFunctionBridge{T,F,G},
::MOI.NumberOfConstraints{G,MOI.EqualTo{T}},
)::Int64 where {T,F,G}
return length(bridge.ci_eq)
end

function MOI.get(
bridge::ComplementsToScalarNonlinearFunctionBridge{T,F,G},
::MOI.ListOfConstraintIndices{G,MOI.EqualTo{T}},
) where {T,F,G}
return copy(bridge.ci_eq)
end

function MOI.get(
bridge::ComplementsToScalarNonlinearFunctionBridge{T},
::MOI.NumberOfConstraints{MOI.ScalarNonlinearFunction,MOI.LessThan{T}},
::MOI.NumberOfConstraints{MOI.ScalarQuadraticFunction{T},MOI.LessThan{T}},
)::Int64 where {T}
return length(bridge.ci)
return length(bridge.ci_lt)
end

function MOI.get(
bridge::ComplementsToScalarNonlinearFunctionBridge{T},
::MOI.ListOfConstraintIndices{MOI.ScalarNonlinearFunction,MOI.LessThan{T}},
::MOI.ListOfConstraintIndices{
MOI.ScalarQuadraticFunction{T},
MOI.LessThan{T},
},
) where {T}
return copy(bridge.ci)
return copy(bridge.ci_lt)
end

function MOI.get(
bridge::ComplementsToScalarNonlinearFunctionBridge{T},
::MOI.NumberOfConstraints{MOI.VariableIndex,MOI.Interval{T}},
)::Int64 where {T}
return length(bridge.y)
end

function MOI.get(
bridge::ComplementsToScalarNonlinearFunctionBridge{T},
::MOI.ListOfConstraintIndices{MOI.VariableIndex,MOI.Interval{T}},
) where {T}
return map(bridge.y) do y
return MOI.ConstraintIndex{MOI.VariableIndex,MOI.Interval{T}}(y.value)
end
end

function MOI.Bridges.needs_final_touch(
Expand Down Expand Up @@ -216,27 +278,23 @@ function MOI.Bridges.final_touch(
end
for i in 1:N
(l, u), F = bridge.bounds[i], f[i]
y_u = isfinite(l) ? typemax(T) : zero(T)
y_l = isfinite(u) ? typemin(T) : zero(T)
y, _ = MOI.add_constrained_variable(model, MOI.Interval{T}(y_l, y_u))
push!(bridge.y, y)
# F(x) - y = 0
g = MOI.Utilities.operate(-, T, F, y)
push!(bridge.ci_eq, MOI.add_constraint(model, g, MOI.EqualTo(zero(T))))
x = convert(MOI.VariableIndex, f[N+i])
g_l = if isfinite(l) && iszero(l)
MOI.ScalarNonlinearFunction(:*, Any[x, F])
elseif isfinite(l)
x_l = MOI.ScalarNonlinearFunction(:-, Any[x, l])
MOI.ScalarNonlinearFunction(:*, Any[x_l, F])
elseif F isa MOI.ScalarNonlinearFunction
F
else
MOI.ScalarNonlinearFunction(:+, Any[F])
end
push!(bridge.ci, MOI.add_constraint(model, g_l, MOI.LessThan(zero(T))))
g_u = if isfinite(u) && iszero(u)
MOI.ScalarNonlinearFunction(:*, Any[x, F])
elseif isfinite(u)
x_u = MOI.ScalarNonlinearFunction(:-, Any[x, u])
MOI.ScalarNonlinearFunction(:*, Any[x_u, F])
else
MOI.ScalarNonlinearFunction(:*, Any[-one(T), F])
# (x - b) * y <= 0
for b in (l, u)
if isfinite(b)
x_less_b = MOI.Utilities.operate(-, T, x, b)
h = MOI.Utilities.operate(*, T, x_less_b, y)
ci = MOI.add_constraint(model, h, MOI.LessThan(zero(T)))
push!(bridge.ci_lt, ci)
end
end
push!(bridge.ci, MOI.add_constraint(model, g_u, MOI.LessThan(zero(T))))
end
return
end
5 changes: 1 addition & 4 deletions src/functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -976,10 +976,7 @@ function Base.convert(
return convert(VariableIndex, convert(ScalarAffineFunction{T}, f))
end

function Base.convert(
::Type{VariableIndex},
f::ScalarNonlinearFunction,
) where {T}
function Base.convert(::Type{VariableIndex}, f::ScalarNonlinearFunction)
if f.head != :+ && length(f.args) != 1
throw(InexactError(:convert, VariableIndex, f))
end
Expand Down
Loading

0 comments on commit 4050b4e

Please sign in to comment.