-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathChalmet.jl
More file actions
139 lines (129 loc) · 4.49 KB
/
Chalmet.jl
File metadata and controls
139 lines (129 loc) · 4.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# Copyright 2019, Oscar Dowson and contributors
# This Source Code Form is subject to the terms of the Mozilla Public License,
# v.2.0. If a copy of the MPL was not distributed with this file, You can
# obtain one at http://mozilla.org/MPL/2.0/.
"""
Chalmet()
`Chalmet` implements the algorithm of:
Chalmet, L.G., and Lemonidis, L., and Elzinga, D.J. (1986). An algorithm for the
bi-criterion integer programming problem. European Journal of Operational
Research. 25(2), 292-300
## Supported problem classes
This algorithm is restricted to problems with:
* exactly two objectives
## Supported optimizer attributes
* `MOI.TimeLimitSec()`: terminate if the time limit is exceeded and return the
list of current solutions.
"""
struct Chalmet <: AbstractAlgorithm end
function _solve_constrained_model(
::Chalmet,
model::Optimizer,
inner::MOI.ModelLike,
f::MOI.AbstractVectorFunction,
rhs::Vector{Float64},
)
f_scalars = MOI.Utilities.scalarize(model.f)
g = MOI.Utilities.operate(+, Float64, f_scalars...)
MOI.set(inner, MOI.ObjectiveFunction{typeof(g)}(), g)
sets = MOI.LessThan.(rhs .- 1)
c = MOI.Utilities.normalize_and_add_constraint.(inner, f_scalars, sets)
optimize_inner!(model)
status = MOI.get(inner, MOI.TerminationStatus())
if !_is_scalar_status_optimal(status)
_log_subproblem_solve(model, "subproblem not optimal")
MOI.delete.(model, c)
return status, nothing
end
variables = MOI.get(inner, MOI.ListOfVariableIndices())
X, Y = _compute_point(model, variables, f)
_log_subproblem_solve(model, Y)
MOI.delete.(model, c)
return status, SolutionPoint(X, Y)
end
function minimize_multiobjective!(
algorithm::Chalmet,
model::Optimizer,
inner::MOI.ModelLike,
f::MOI.AbstractVectorFunction,
)
@assert MOI.get(inner, MOI.ObjectiveSense()) == MOI.MIN_SENSE
if MOI.output_dimension(f) != 2
error("Chalmet requires exactly two objectives")
end
solutions = SolutionPoint[]
E = Tuple{Int,Int}[]
Q = Tuple{Int,Int}[]
variables = MOI.get(inner, MOI.ListOfVariableIndices())
f1, f2 = MOI.Utilities.scalarize(f)
y1, y2 = zeros(2), zeros(2)
MOI.set(inner, MOI.ObjectiveFunction{typeof(f2)}(), f2)
optimize_inner!(model)
status = MOI.get(inner, MOI.TerminationStatus())
if !_is_scalar_status_optimal(status)
return status, solutions
end
_, y1[2] = _compute_point(model, variables, f2)
_log_subproblem_solve(model, variables)
MOI.set(inner, MOI.ObjectiveFunction{typeof(f1)}(), f1)
y1_constraint = MOI.Utilities.normalize_and_add_constraint(
inner,
f2,
MOI.LessThan(y1[2]),
)
optimize_inner!(model)
status = MOI.get(inner, MOI.TerminationStatus())
if !_is_scalar_status_optimal(status)
return status, solutions
end
x1, y1[1] = _compute_point(model, variables, f1)
_log_subproblem_solve(model, y1)
MOI.delete(inner, y1_constraint)
push!(solutions, SolutionPoint(x1, y1))
MOI.set(inner, MOI.ObjectiveFunction{typeof(f1)}(), f1)
optimize_inner!(model)
status = MOI.get(inner, MOI.TerminationStatus())
if !_is_scalar_status_optimal(status)
return status, solutions
end
_, y2[1] = _compute_point(model, variables, f1)
_log_subproblem_solve(model, variables)
if y2[1] ≈ solutions[1].y[1]
return MOI.OPTIMAL, solutions
end
MOI.set(inner, MOI.ObjectiveFunction{typeof(f2)}(), f2)
y2_constraint = MOI.Utilities.normalize_and_add_constraint(
inner,
f1,
MOI.LessThan(y2[1]),
)
optimize_inner!(model)
status = MOI.get(inner, MOI.TerminationStatus())
if !_is_scalar_status_optimal(status)
return status, solutions
end
x2, y2[2] = _compute_point(model, variables, f2)
_log_subproblem_solve(model, y2)
MOI.delete(inner, y2_constraint)
push!(solutions, SolutionPoint(x2, y2))
push!(Q, (1, 2))
t = 3
while !isempty(Q)
if (ret = _check_premature_termination(model)) !== nothing
return ret, solutions
end
r, s = pop!(Q)
yr, ys = solutions[r].y, solutions[s].y
rhs = [max(yr[1], ys[1]), max(yr[2], ys[2])]
status, solution =
_solve_constrained_model(algorithm, model, inner, f, rhs)
if !_is_scalar_status_optimal(status)
push!(E, (r, s))
continue
end
push!(solutions, solution)
append!(Q, [(r, t), (t, s)])
t += 1
end
return MOI.OPTIMAL, solutions
end