-
-
Notifications
You must be signed in to change notification settings - Fork 411
Description
This issue is for a discussion on introducing multiobjective support to JuMP (and
MOI).
Passing multiple objectives to the solver
There are two possibilities:
- Extending
@objectiveto support vector-valued functions, so the user would
write:@objective(model, Min, C * x)
- Adding an
indexkeyword, so the user would write:@objective(model, Min, C[1, :] * x, index = 1) @objective(model, Min, C[2, :] * x, index = 2)
Option (1) is probably the easiest, since it fits quite well into the MOI
framework, and JuMP already has support for parsing vector-valued functions.
M.O. solvers would just declare:
function MOI.supports(
::Optimizer, ::MOI.ObjectiveFunction{MOI.VectorAffineFunction{Float64}}
)
return true
endThe biggest downside with (1) is that it would only support linear and quadratic
objectives. We wouldn't be able to directly support nonlinear objectives. (You
could, of course, introduce a dummy variable with a nonlinear equality
constraint.)
Querying results from the solver
I think the easiest way for M.O. solvers to return the Pareto frontier is for
them to sligthly abuse the notion of ResultCount.
We should implement
function result_count(model::Model)
return MOI.get(model, MOI.ResultCount())
endAnd then add keyword arguments to value, objective_value, so we have:
function value(x::VariableRef; result=1)
return MOI.get(owner_model(x), MOI.VariablePrimal(result), index(x))
endThe only issue with objective_value (and objective_bound and
dual_objective_bound) is that they expect a Float64 return type. This would
be relaxed to depend on the type of the objective function.
Example
If MultiJuMP implemented a MOI.Optimizer solver, we could write:
using JuMP
using MultiJuMP
model = Model(() -> MultiJuMP.Optimizer(GLPK.Optimizer))
@variable(model, x[1:2] >= 0)
@objective(model, Min, [2x[1] + x[2]; x[1] + 2x[2]])
@constraint(model, sum(x) >= 1)
optimize!(model)
pareto_frontier = []
for i = 1:result_count(model)
@assert primal_status(model; result = i) == MOI.OPTIMAL
push!(pareto_frontier, (
x_val = value.(x; result = i),
obj = objective_value(model; result = i)
))
end