Skip to content
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
5 changes: 5 additions & 0 deletions .JuliaFormatter.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,8 @@
# For more information, see: https://domluna.github.io/JuliaFormatter.jl/stable/config/

always_for_in = true
always_use_return = true
margin = 80
remove_extra_newlines = true
separate_kwargs_with_semicolon = true
short_to_long_function_def = true
19 changes: 14 additions & 5 deletions src/Bridges/complements_vectorize_bridge.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ where `T` is the coefficient type.
[`MOI.Zeros`](@ref) depending on the input set type

"""
struct ComplementsVectorizeBridge{T,F,S,SV} <: MOI.Bridges.Constraint.AbstractBridge
struct ComplementsVectorizeBridge{T,F,S,SV} <:
MOI.Bridges.Constraint.AbstractBridge
constraint::MOI.ConstraintIndex{F,ComplementsWithSetType{SV}}
set_constant::T
end
Expand Down Expand Up @@ -93,7 +94,11 @@ end
function MOI.supports_constraint(
::Type{<:ComplementsVectorizeBridge},
::Type{MOI.VectorOfVariables},
::Type{<:ComplementsWithSetType{<:Union{MOI.GreaterThan,MOI.LessThan,MOI.EqualTo}}},
::Type{
<:ComplementsWithSetType{
<:Union{MOI.GreaterThan,MOI.LessThan,MOI.EqualTo},
},
},
)
return true
end
Expand All @@ -109,11 +114,13 @@ function MOI.Bridges.Constraint.concrete_bridge_type(
return ComplementsVectorizeBridge{T,F,S,SV}
end

MOI.supports(
function MOI.supports(
::MOI.ModelLike,
::ComplementarityReformulation,
::Type{<:ComplementsVectorizeBridge},
) = true
)
return true
end

function MOI.set(
model::MOI.ModelLike,
Expand All @@ -127,7 +134,9 @@ end

# Bridge metadata

function MOI.Bridges.added_constrained_variable_types(::Type{<:ComplementsVectorizeBridge})
function MOI.Bridges.added_constrained_variable_types(
::Type{<:ComplementsVectorizeBridge},
)
return Tuple{Type}[]
end

Expand Down
18 changes: 14 additions & 4 deletions src/Bridges/flip_sign_bridge.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ function _flip_set_type(::Type{MOI.LessThan{T}}) where {T}
return MOI.GreaterThan{T}
end

const _FlippableSets = Union{MOI.Nonnegatives,MOI.Nonpositives,MOI.GreaterThan,MOI.LessThan}
const _FlippableSets =
Union{MOI.Nonnegatives,MOI.Nonpositives,MOI.GreaterThan,MOI.LessThan}

function MOI.Bridges.Constraint.bridge_constraint(
::Type{FlipSignBridge{T,F,S1,S2,G}},
Expand Down Expand Up @@ -87,8 +88,13 @@ function MOI.Bridges.Constraint.concrete_bridge_type(
return FlipSignBridge{T,F,S1,S2,G}
end

MOI.supports(::MOI.ModelLike, ::ComplementarityReformulation, ::Type{<:FlipSignBridge}) =
true
function MOI.supports(
::MOI.ModelLike,
::ComplementarityReformulation,
::Type{<:FlipSignBridge},
)
return true
end

function MOI.set(
model::MOI.ModelLike,
Expand Down Expand Up @@ -126,7 +132,11 @@ function MOI.get(
return [bridge.constraint]
end

function MOI.get(::MOI.ModelLike, ::MOI.ConstraintFunction, bridge::FlipSignBridge)
function MOI.get(
::MOI.ModelLike,
::MOI.ConstraintFunction,
bridge::FlipSignBridge,
)
return bridge.original_func
end

Expand Down
135 changes: 107 additions & 28 deletions src/Bridges/nonlinear.jl
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ function MOI.Bridges.Constraint.bridge_constraint(
# Only `MathOptComplements.Optimizer` supports setting custom bridge arguments
# so the default will be used when the bridge is added for instance to
# `MOI.Bridges.LazyBridgeOptimizer`
reformulation::AbstractComplementarityRelaxation = ScholtesRelaxation(zero(T)),
reformulation::AbstractComplementarityRelaxation = ScholtesRelaxation(
zero(T),
),
) where {T,S}
# Delay reformulation until `final_touch` so that per-constraint
# `ComplementarityReformulation` attributes can override it first.
Expand All @@ -70,8 +72,13 @@ function MOI.Bridges.Constraint.concrete_bridge_type(
return NonlinearBridge{T,S}
end

MOI.supports(::MOI.ModelLike, ::ComplementarityReformulation, ::Type{<:NonlinearBridge}) =
true
function MOI.supports(
::MOI.ModelLike,
::ComplementarityReformulation,
::Type{<:NonlinearBridge},
)
return true
end

function MOI.set(
model::MOI.ModelLike,
Expand All @@ -98,11 +105,17 @@ function MOI.Bridges.added_constraint_types(::Type{<:NonlinearBridge})
return Tuple{Type,Type}[]
end

function MOI.get(bridge::NonlinearBridge, ::MOI.NumberOfConstraints{F,S})::Int64 where {F,S}
function MOI.get(
bridge::NonlinearBridge,
::MOI.NumberOfConstraints{F,S},
)::Int64 where {F,S}
return count(ci -> ci isa MOI.ConstraintIndex{F,S}, bridge.constraints)
end

function MOI.get(bridge::NonlinearBridge, ::MOI.ListOfConstraintIndices{F,S}) where {F,S}
function MOI.get(
bridge::NonlinearBridge,
::MOI.ListOfConstraintIndices{F,S},
) where {F,S}
return MOI.ConstraintIndex{F,S}[
ci for ci in bridge.constraints if ci isa MOI.ConstraintIndex{F,S}
]
Expand Down Expand Up @@ -134,19 +147,52 @@ function MOI.Bridges.final_touch(bridge::NonlinearBridge, model::MOI.ModelLike)
end

# Bound helpers: extract the relevant bounds based on the set type S.
_complementarity_bounds(::Type{MOI.Nonnegatives}, model, ::Type{T}, x2) where {T} =
(zero(T), T(Inf))
_complementarity_bounds(::Type{MOI.Nonpositives}, model, ::Type{T}, x2) where {T} =
(T(-Inf), zero(T))
_complementarity_bounds(::Type{MOI.Zeros}, model, ::Type{T}, x2) where {T} =
(zero(T), zero(T))
function _complementarity_bounds(::Type{<:MOI.GreaterThan}, model, ::Type{T}, x2) where {T}
function _complementarity_bounds(
::Type{MOI.Nonnegatives},
model,
::Type{T},
x2,
) where {T}
return (zero(T), T(Inf))
end
function _complementarity_bounds(
::Type{MOI.Nonpositives},
model,
::Type{T},
x2,
) where {T}
return (T(-Inf), zero(T))
end
function _complementarity_bounds(
::Type{MOI.Zeros},
model,
::Type{T},
x2,
) where {T}
return (zero(T), zero(T))
end
function _complementarity_bounds(
::Type{<:MOI.GreaterThan},
model,
::Type{T},
x2,
) where {T}
return (MOIU.get_bounds(model, T, x2)[1], T(Inf))
end
function _complementarity_bounds(::Type{<:MOI.LessThan}, model, ::Type{T}, x2) where {T}
function _complementarity_bounds(
::Type{<:MOI.LessThan},
model,
::Type{T},
x2,
) where {T}
return (T(-Inf), MOIU.get_bounds(model, T, x2)[2])
end
function _complementarity_bounds(::Type{<:MOI.Interval}, model, ::Type{T}, x2) where {T}
function _complementarity_bounds(
::Type{<:MOI.Interval},
model,
::Type{T},
x2,
) where {T}
return MOIU.get_bounds(model, T, x2)
end

Expand All @@ -170,18 +216,38 @@ function reformulate_as_nonlinear_program!(
x2 = fun.variables[cc+n_comp]
lb2, ub2 = _complementarity_bounds(S, model, Float64, x2)
if isinf(ub2)
idc = _relax_complementarity_lower_bound!(model, relaxation, x1, x2, lb2, ub2)
idc = _relax_complementarity_lower_bound!(
model,
relaxation,
x1,
x2,
lb2,
ub2,
)
elseif isinf(lb2)
idc = _relax_complementarity_upper_bound!(model, relaxation, x1, x2, lb2, ub2)
idc = _relax_complementarity_upper_bound!(
model,
relaxation,
x1,
x2,
lb2,
ub2,
)
else
idc = _relax_complementarity_range!(model, relaxation, x1, x2, lb2, ub2)
idc = _relax_complementarity_range!(
model,
relaxation,
x1,
x2,
lb2,
ub2,
)
end
append!(ind_cc, idc)
end
return ind_cc
end


"""
ScholtesRelaxation <: AbstractComplementarityRelaxation

Expand Down Expand Up @@ -216,7 +282,8 @@ function _relax_complementarity_lower_bound!(
@assert lb1 == 0.0 # ensure we follow MOI's convention
# TODO: what should we do if ub1 is finite?
end
idc = MOI.add_constraint(model, x1 * (x2 - lb2), MOI.LessThan(relaxation.tau))
idc =
MOI.add_constraint(model, x1 * (x2 - lb2), MOI.LessThan(relaxation.tau))
return [idc]
end

Expand All @@ -236,7 +303,8 @@ function _relax_complementarity_upper_bound!(
@assert ub1 == 0.0 # ensure we follow MOI's convention
# TODO: what should we do if lb1 is finite?
end
idc = MOI.add_constraint(model, x1 * (x2 - ub2), MOI.LessThan(relaxation.tau))
idc =
MOI.add_constraint(model, x1 * (x2 - ub2), MOI.LessThan(relaxation.tau))
return [idc]
end

Expand All @@ -249,8 +317,10 @@ function _relax_complementarity_range!(
lb2,
ub2,
)
idc1 = MOI.add_constraint(model, x1 * (x2 - lb2), MOI.LessThan(relaxation.tau))
idc2 = MOI.add_constraint(model, x1 * (x2 - ub2), MOI.LessThan(relaxation.tau))
idc1 =
MOI.add_constraint(model, x1 * (x2 - lb2), MOI.LessThan(relaxation.tau))
idc2 =
MOI.add_constraint(model, x1 * (x2 - ub2), MOI.LessThan(relaxation.tau))
return [idc1, idc2]
end

Expand Down Expand Up @@ -361,7 +431,6 @@ function _relax_complementarity_range!(
return [idc1, idc2]
end


"""
LiuFukushimaRelaxation <: AbstractComplementarityRelaxation

Expand Down Expand Up @@ -389,7 +458,11 @@ function _relax_complementarity_lower_bound!(
lb1, _ = MOIU.get_bounds(model, Float64, x1)
@assert isinf(lb1) || iszero(lb1)

idc1 = MOI.add_constraint(model, x1 * (x2 - lb2), MOI.LessThan(relaxation.epsilon^2))
idc1 = MOI.add_constraint(
model,
x1 * (x2 - lb2),
MOI.LessThan(relaxation.epsilon^2),
)
idc2 = MOI.add_constraint(
model,
(x1 + relaxation.epsilon) * (x2 - lb2 + relaxation.epsilon),
Expand All @@ -398,7 +471,9 @@ function _relax_complementarity_lower_bound!(

# Remove bounds
_remove_bounds!(model, x1)
cidx = MOI.ConstraintIndex{MOI.VariableIndex,MOI.GreaterThan{Float64}}(x2.value)
cidx = MOI.ConstraintIndex{MOI.VariableIndex,MOI.GreaterThan{Float64}}(
x2.value,
)
MOI.delete(model, cidx)

return [idc1, idc2]
Expand All @@ -416,7 +491,11 @@ function _relax_complementarity_upper_bound!(
_, ub1 = MOIU.get_bounds(model, Float64, x1)
@assert isinf(ub1) || iszero(ub1)

idc1 = MOI.add_constraint(model, x1 * (x2 - ub2), MOI.LessThan(relaxation.epsilon^2))
idc1 = MOI.add_constraint(
model,
x1 * (x2 - ub2),
MOI.LessThan(relaxation.epsilon^2),
)
idc2 = MOI.add_constraint(
model,
(x1 - relaxation.epsilon) * (x2 - ub2 - relaxation.epsilon),
Expand All @@ -425,13 +504,13 @@ function _relax_complementarity_upper_bound!(

# Remove bounds
_remove_bounds!(model, x1)
cidx = MOI.ConstraintIndex{MOI.VariableIndex,MOI.LessThan{Float64}}(x2.value)
cidx =
MOI.ConstraintIndex{MOI.VariableIndex,MOI.LessThan{Float64}}(x2.value)
MOI.delete(model, cidx)

return [idc1, idc2]
end


"""
KanzowSchwarzRelaxation <: AbstractComplementarityRelaxation

Expand Down
Loading
Loading