|
1 | | -function _halfspaces(IPS) |
2 | | - return error("MOA.Sandwiching requires Polyhedra.jl to be loaded") |
3 | | -end |
| 1 | +# Copyright 2019, Oscar Dowson and contributors |
| 2 | +# This Source Code Form is subject to the terms of the Mozilla Public License, |
| 3 | +# v.2.0. If a copy of the MPL was not distributed with this file, You can |
| 4 | +# obtain one at http://mozilla.org/MPL/2.0/. |
4 | 5 |
|
5 | | -mutable struct Sandwiching <: AbstractAlgorithm |
6 | | - precision::Float64 |
7 | | -end |
| 6 | +""" |
| 7 | + Sandwiching(precision::Float64) |
8 | 8 |
|
9 | | -tol = 1e-3 |
| 9 | +An algorithm that implemennts the paper described in XXX. |
10 | 10 |
|
11 | | -function _compute_anchors(model::Optimizer) |
12 | | - anchors = Dict{Vector{Float64},Dict{MOI.VariableIndex,Float64}}() |
13 | | - n = MOI.output_dimension(model.f) |
14 | | - scalars = MOI.Utilities.scalarize(model.f) |
15 | | - variables = MOI.get(model.inner, MOI.ListOfVariableIndices()) |
16 | | - yI, yUB = zeros(n), zeros(n) |
17 | | - for (i, f_i) in enumerate(scalars) |
18 | | - MOI.set(model.inner, MOI.ObjectiveFunction{typeof(f_i)}(), f_i) # ρ * sum(f_j for (j, f_j) in enumerate(model.f) if j != i) |
19 | | - MOI.set(model.inner, MOI.ObjectiveSense(), MOI.MIN_SENSE) |
20 | | - MOI.optimize!(model.inner) |
21 | | - # status check |
22 | | - X, Y = _compute_point(model, variables, model.f) |
23 | | - model.ideal_point[i] = Y[i] |
24 | | - yI[i] = Y[i] |
25 | | - anchors[Y] = X |
26 | | - MOI.set(model.inner, MOI.ObjectiveSense(), MOI.MAX_SENSE) |
27 | | - MOI.optimize!(model.inner) |
28 | | - # status check |
29 | | - _, Y = _compute_point(model, variables, f_i) |
30 | | - yUB[i] = Y |
31 | | - end |
32 | | - MOI.set(model.inner, MOI.ObjectiveSense(), MOI.MIN_SENSE) |
33 | | - return yI, yUB, anchors |
34 | | -end |
35 | | - |
36 | | -@enum DistanceMeasure SUB CUR SOL |
| 11 | +## Compat |
37 | 12 |
|
38 | | -function _distance(w̄, b̄, OPS, model) |
39 | | - n = MOI.output_dimension(model.f) |
40 | | - optimizer = typeof(model.inner.optimizer) |
41 | | - δ_optimizer = optimizer() |
42 | | - MOI.set(δ_optimizer, MOI.Silent(), true) |
43 | | - x = MOI.add_variables(δ_optimizer, n) |
44 | | - for (w, b) in OPS |
45 | | - MOI.add_constraint( |
46 | | - δ_optimizer, |
47 | | - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(w, x), 0.0), |
48 | | - MOI.GreaterThan(b), |
49 | | - ) |
50 | | - end |
51 | | - MOI.set( |
52 | | - δ_optimizer, |
53 | | - MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), |
54 | | - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(w̄, x), 0.0), |
55 | | - ) |
56 | | - MOI.set(δ_optimizer, MOI.ObjectiveSense(), MOI.MIN_SENSE) |
57 | | - MOI.optimize!(δ_optimizer) |
58 | | - δ = b̄ - MOI.get(δ_optimizer, MOI.ObjectiveValue()) |
59 | | - return δ |
60 | | -end |
| 13 | +To use this algorithm you MUST first load the Polyhedra.jl Julia package: |
61 | 14 |
|
62 | | -function _select_next_halfspace(H, OPS, model) |
63 | | - distances = [_distance(w, b, OPS, model) for (w, b) in H] |
64 | | - @info "Distances: $(Dict(zip(H, distances)))" |
65 | | - index = argmax(distances) |
66 | | - w, b = H[index] |
67 | | - return distances[index], w, b |
68 | | -end |
69 | | - |
70 | | -function optimize_multiobjective!(algorithm::Sandwiching, model::Optimizer) |
71 | | - @assert MOI.get(model.inner, MOI.ObjectiveSense()) == MOI.MIN_SENSE |
72 | | - ε = algorithm.precision |
73 | | - start_time = time() |
74 | | - solutions = Dict{Vector{Float64},Dict{MOI.VariableIndex,Float64}}() |
75 | | - variables = MOI.get(model.inner, MOI.ListOfVariableIndices()) |
76 | | - n = MOI.output_dimension(model.f) |
77 | | - scalars = MOI.Utilities.scalarize(model.f) |
78 | | - yI, yUB, anchors = _compute_anchors(model) |
79 | | - merge!(solutions, anchors) |
80 | | - @info "yI: $(yI)" |
81 | | - @info "yUB: $(yUB)" |
82 | | - IPS = [yUB, keys(anchors)...] |
83 | | - OPS = Tuple{Vector{Float64},Float64}[] |
84 | | - for i in 1:n |
85 | | - e_i = Float64.(1:n .== i) |
86 | | - push!(OPS, (e_i, yI[i])) # e_i' * y >= yI_i |
87 | | - push!(OPS, (-e_i, -yUB[i])) # -e_i' * y >= -yUB_i ⟹ e_i' * y <= yUB_i |
88 | | - end |
89 | | - @info "IPS: $(IPS)" |
90 | | - @info "OPS: $(OPS)" |
91 | | - u = MOI.add_variables(model.inner, n) |
92 | | - u_constraints = [ # u_i >= 0 for all i = 1:n |
93 | | - MOI.add_constraint(model.inner, u_i, MOI.GreaterThan{Float64}(0)) |
94 | | - for u_i in u |
95 | | - ] |
96 | | - f_constraints = [ # f_i + u_i <= yUB_i for all i = 1:n |
97 | | - MOI.Utilities.normalize_and_add_constraint( |
98 | | - model.inner, |
99 | | - scalars[i] + u[i], |
100 | | - MOI.LessThan(yUB[i]), |
101 | | - ) for i in 1:n |
102 | | - ] |
103 | | - H = _halfspaces(IPS) |
104 | | - |
105 | | - count = 0 |
106 | | - |
107 | | - while !isempty(H) |
108 | | - count += 1 |
109 | | - @info "-- Iteration #$(count) --" |
110 | | - @info "HalfSpaces: $(H)" |
111 | | - δ, w, b = _select_next_halfspace(H, OPS, model) |
112 | | - @info "Selected halfspace: w: $(w), b: $(b)" |
113 | | - @info "δ: $(δ)" |
114 | | - if δ - tol > ε # added some convergence tolerance |
115 | | - # would not terminate when precision is set to 0 |
116 | | - new_f = sum(w[i] * (scalars[i] + u[i]) for i in 1:n) # w' * (f(x) + u) |
117 | | - MOI.set(model.inner, MOI.ObjectiveFunction{typeof(new_f)}(), new_f) |
118 | | - MOI.optimize!(model.inner) |
119 | | - β̄ = MOI.get(model.inner, MOI.ObjectiveValue()) |
120 | | - @info "β̄: $(β̄)" |
121 | | - X, Y = _compute_point(model, variables, model.f) |
122 | | - @info "Y: $(Y)" |
123 | | - solutions[Y] = X |
124 | | - push!(OPS, (w, β̄)) |
125 | | - @info "Added halfspace w: $(w), b: $(β̄) to OPS" |
126 | | - IPS = push!(IPS, Y) |
127 | | - else |
128 | | - break |
129 | | - end |
130 | | - @info "IPS: $(IPS)" |
131 | | - @info "OPS: $(OPS)" |
132 | | - H = _halfspaces(IPS) |
133 | | - if count == 10 |
134 | | - break |
135 | | - end |
136 | | - end |
137 | | - MOI.delete.(model.inner, f_constraints) |
138 | | - MOI.delete.(model.inner, u_constraints) |
139 | | - MOI.delete.(model.inner, u) |
140 | | - return MOI.OPTIMAL, [SolutionPoint(X, Y) for (Y, X) in solutions] |
| 15 | +```julia |
| 16 | +import MultiObjectiveAlgorithms as MOA |
| 17 | +import Polyhedra |
| 18 | +algorithm = MOA.Sandwiching(0.0) |
| 19 | +``` |
| 20 | +""" |
| 21 | +mutable struct Sandwiching <: AbstractAlgorithm |
| 22 | + precision::Float64 |
141 | 23 | end |
0 commit comments