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
@objective
to support vector-valued functions, so the user would
write:@objective(model, Min, C * x)
- Adding an
index
keyword, 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
end
The 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())
end
And 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))
end
The 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