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
30 changes: 30 additions & 0 deletions .github/workflows/format_check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: format-check
on:
push:
branches:
- main
- release-*
pull_request:
types: [opened, synchronize, reopened]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: julia-actions/setup-julia@latest
with:
version: '1'
- uses: actions/checkout@v4
- name: Format check
shell: julia --color=yes {0}
run: |
using Pkg
Pkg.add(PackageSpec(name="JuliaFormatter", version="2"))
using JuliaFormatter
format(".", verbose=true)
out = String(read(Cmd(`git diff`)))
if isempty(out)
exit(0)
end
@error "Some files have not been formatted !!!"
write(stdout, out)
exit(1)
24 changes: 5 additions & 19 deletions src/MOI_wrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ struct Optimizer{O<:MOI.ModelLike} <: MOI.AbstractOptimizer
optimizer::O
reformulation::AbstractComplementarityRelaxation
function Optimizer(optimizer::MOI.ModelLike)
return new{typeof(optimizer)}(
optimizer,
ScholtesRelaxation(0.0),
)
return new{typeof(optimizer)}(optimizer, ScholtesRelaxation(0.0))
end
end

Expand All @@ -16,30 +13,21 @@ MOI.empty!(model::Optimizer) = MOI.empty!(model.optimizer)

function MOI.supports(
model::Optimizer,
attr::Union{
MOI.AbstractModelAttribute,
MOI.AbstractOptimizerAttribute,
},
attr::Union{MOI.AbstractModelAttribute,MOI.AbstractOptimizerAttribute},
)
return MOI.supports(model.optimizer, attr)
end

function MOI.get(
model::Optimizer,
attr::Union{
MOI.AbstractModelAttribute,
MOI.AbstractOptimizerAttribute,
},
attr::Union{MOI.AbstractModelAttribute,MOI.AbstractOptimizerAttribute},
)
return MOI.get(model.optimizer, attr)
end

function MOI.set(
model::Optimizer,
attr::Union{
MOI.AbstractModelAttribute,
MOI.AbstractOptimizerAttribute,
},
attr::Union{MOI.AbstractModelAttribute,MOI.AbstractOptimizerAttribute},
value,
)
return MOI.set(model.optimizer, attr, value)
Expand All @@ -54,9 +42,7 @@ function MOI.supports_constraint(
end

function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike)
tmp = MOI.Utilities.UniversalFallback(
MOI.Utilities.Model{Float64}()
)
tmp = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}())
tmp_index_map = MOI.copy_to(tmp, src)
reformulate_to_vertical!(tmp)
reformulate_as_nonlinear_program!(tmp, dest.reformulation)
Expand Down
134 changes: 69 additions & 65 deletions src/nonlinear.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,28 @@ the complementarity constraints.
If the complementarity constraints are not in vertical form, an error is thrown.

"""
function reformulate_as_nonlinear_program!(model::MOI.ModelLike, relaxation::AbstractComplementarityRelaxation)
function reformulate_as_nonlinear_program!(
model::MOI.ModelLike,
relaxation::AbstractComplementarityRelaxation,
)
if !is_vertical(model)
error("Complementarity constraints should be reformulated in vertical form before applying nonlinear reformulation")
error(
"Complementarity constraints should be reformulated in vertical form before applying nonlinear reformulation",
)
end

cc_cons = MOI.get(model, MOI.ListOfConstraintIndices{MOI.VectorOfVariables, MOI.Complements}())[1]
cc_cons = MOI.get(
model,
MOI.ListOfConstraintIndices{MOI.VectorOfVariables,MOI.Complements}(),
)[1]
fun = MOI.get(model, MOI.ConstraintFunction(), cc_cons)
set = MOI.get(model, MOI.ConstraintSet(), cc_cons)
n_comp = div(set.dimension, 2)

ind_cc = []
for cc in 1:n_comp
for cc = 1:n_comp
x1 = fun.variables[cc]
x2 = fun.variables[cc + n_comp]
x2 = fun.variables[cc+n_comp]
# Get bounds on x2
lb2, ub2 = MOIU.get_bounds(model, Float64, x2)
# x2 should have at least one bound, otherwise x1 becomes a fixed variable
Expand Down Expand Up @@ -71,7 +79,10 @@ end
function _relax_complementarity_lower_bound!(
model::MOI.ModelLike,
relaxation::ScholtesRelaxation,
x1, x2, lb2, ub2,
x1,
x2,
lb2,
ub2,
)
lb1, ub1 = MOIU.get_bounds(model, Float64, x1)
if isinf(lb1)
Expand All @@ -80,19 +91,18 @@ 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

# x1 ⟂ (x2 <= ub) ≡ x1 <= 0 ; lb <= x2 ; x1 ( x2 - ub) <= 0
function _relax_complementarity_upper_bound!(
model::MOI.ModelLike,
relaxation::ScholtesRelaxation,
x1, x2, lb2, ub2,
x1,
x2,
lb2,
ub2,
)
lb1, ub1 = MOIU.get_bounds(model, Float64, x1)
if isinf(ub1)
Expand All @@ -101,31 +111,22 @@ 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

# x1 ⟂ (lb <= x2 <= ub) ≡ lb <= x2 <= ub ; x1 (x2 - lb) <= 0 ; x1 (x2 - ub) <= 0
function _relax_complementarity_range!(
model::MOI.ModelLike,
relaxation::ScholtesRelaxation,
x1, x2, lb2, ub2,
x1,
x2,
lb2,
ub2,
)
lb1, ub1 = MOIU.get_bounds(model, Float64, x1)
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 All @@ -149,33 +150,30 @@ function _min_eps(a, b, eps)
return MOI.ScalarNonlinearFunction(
:-,
Any[
1.0 * a + 1.0 * b ,
MOI.ScalarNonlinearFunction(
:sqrt,
Any[(1.0 * a)^2 + (1.0 * b)^2 + eps^2],
)
]
1.0*a+1.0*b,
MOI.ScalarNonlinearFunction(:sqrt, Any[(1.0*a)^2+(1.0*b)^2+eps^2]),
],
)
end

function _max_eps(a, b, eps)
return MOI.ScalarNonlinearFunction(
:+,
Any[
1.0 * a + 1.0 * b ,
MOI.ScalarNonlinearFunction(
:sqrt,
Any[(1.0 * a)^2 + (1.0 * b)^2 + eps^2],
)
]
1.0*a+1.0*b,
MOI.ScalarNonlinearFunction(:sqrt, Any[(1.0*a)^2+(1.0*b)^2+eps^2]),
],
)
end

# x1 ⟂ (lb <= x2) ≡ 0 <= x1 ; lb <= x2 ; min(x1, x2 - lb) <= 0
function _relax_complementarity_lower_bound!(
model::MOI.ModelLike,
relaxation::FischerBurmeisterRelaxation,
x1, x2, lb2, ub2,
x1,
x2,
lb2,
ub2,
)
lb1, ub1 = MOIU.get_bounds(model, Float64, x1)
if isinf(lb1)
Expand All @@ -196,7 +194,10 @@ end
function _relax_complementarity_upper_bound!(
model::MOI.ModelLike,
relaxation::FischerBurmeisterRelaxation,
x1, x2, lb2, ub2,
x1,
x2,
lb2,
ub2,
)
lb1, ub1 = MOIU.get_bounds(model, Float64, x1)
if isinf(ub1)
Expand All @@ -217,7 +218,10 @@ end
function _relax_complementarity_range!(
model::MOI.ModelLike,
relaxation::FischerBurmeisterRelaxation,
x1, x2, lb2, ub2,
x1,
x2,
lb2,
ub2,
)
lb1, ub1 = MOIU.get_bounds(model, Float64, x1)
idc1 = MOI.add_constraint(
Expand Down Expand Up @@ -252,13 +256,12 @@ end
function _relax_complementarity_lower_bound!(
model::MOI.ModelLike,
relaxation::LiuFukushimaRelaxation,
x1, x2, lb2, ub2,
x1,
x2,
lb2,
ub2,
)
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 @@ -276,13 +279,12 @@ end
function _relax_complementarity_upper_bound!(
model::MOI.ModelLike,
relaxation::LiuFukushimaRelaxation,
x1, x2, lb2, ub2,
x1,
x2,
lb2,
ub2,
)
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 Down Expand Up @@ -325,20 +327,20 @@ function _kanzow_schwarz_relaxation(a, b, eps)
return MOI.ScalarNonlinearFunction(
:ifelse,
Any[
MOI.ScalarNonlinearFunction(
:>,
Any[1.0 * a + 1.0 * b, 2*eps],
),
(a - eps) * (b - eps),
- 0.5 * ((a - eps)^2 + (b - eps)^2),
]
MOI.ScalarNonlinearFunction(:>, Any[1.0*a+1.0*b, 2*eps]),
(a-eps)*(b-eps),
- 0.5*((a-eps)^2+(b-eps)^2),
],
)
end

function _relax_complementarity_lower_bound!(
model::MOI.ModelLike,
relaxation::KanzowSchwarzRelaxation,
x1, x2, lb2, ub2,
x1,
x2,
lb2,
ub2,
)
lb1, ub1 = MOIU.get_bounds(model, Float64, x1)
if isinf(lb1)
Expand All @@ -359,7 +361,10 @@ end
function _relax_complementarity_upper_bound!(
model::MOI.ModelLike,
relaxation::KanzowSchwarzRelaxation,
x1, x2, lb2, ub2,
x1,
x2,
lb2,
ub2,
)
lb1, ub1 = MOIU.get_bounds(model, Float64, x1)
if isinf(ub1)
Expand All @@ -375,4 +380,3 @@ function _relax_complementarity_upper_bound!(
)
return [idc]
end

Loading
Loading