Skip to content

Multiobjective support in JuMP #2099

Closed
@odow

Description

@odow

This issue is for a discussion on introducing multiobjective support to JuMP (and
MOI).

Passing multiple objectives to the solver

There are two possibilities:

  1. Extending @objective to support vector-valued functions, so the user would
    write:
    @objective(model, Min, C * x)
  2. 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

cc @anriseth, @matbesancon

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions