Solvers
While DESDEO is a framework for interactive multiobjective optimization, it does not implement any optimizers per se. Instead, DESDEO provides interfaces to many existing solvers. How these interfaces work in general is explained in the section Solver interfaces, while the currently implemented solvers in DESDEO are introduced and a couple of examples on how to use the solvers are given in the section Solver examples.
Solver interfaces
The solver interfaces rely internally heavily on the evaluators discussed
in the section Parsing and evaluating. It is
the evaluators that make sure the Problem
being solved is in a format that
can be evaluated by a solver. The solver interfaces discussed here are
in charge of making sure that when an outside solver evaluates a problem, the information
from the solver is passed to the evaluator in a correct format, and that the
output of the solver is then processed in a way that it can be utilized elsewhere
in DESDEO. The interfaces also pass information from DESDEO to solvers
in a compatible format. To put it simply, the solver interfaces are translators between the
evaluators in DESDEO and the solvers found outside of DESDEO.
Solver examples
How solvers can be utilized in practice is best illustrated with examples. We provide here a few examples on how to utilize different solvers through the solver interfaces available in DESDEO.
Scipy solvers
The Scipy solvers in desdeo, found in the module Scipy solver
interfaces can be used to interface with
the optimization routines found in the Scipy library. There are interfaces to
the solvers
minimize
and differential_evolution
.
Scipy solvers do not support TensorVariables.
First, to illustrate the usage of the minimize
interface, and the interfaces in general, consider the following
example:
from desdeo.tools import ScipyMinimizeSolver
problem: Problem # a problem with the objectives f_1, f_2, and f_3 to be minimized
solver = ScipyMinimizeSolver(problem)
results: SolverResults = solver.solve("f_1")
In the above example, we consider an arbitrary Problem
with three objectives.
We then create a solver by calling ScipyMinimizeSolver
and supplying it the problem we want to solve. This makes all the necessary setups for the solver and then
returns an instance of the ScipyMinimizeSolver class, which we have stored in solver
. To run the solver, we call the solve
function
with the symbol of the function defined in the problem we wish to minimize. Then, the solver returns a pydantic
dataclass of type SolverResults with the results of the optimization. It
is important to know that whichever function we request the solver to optimize, will be minimized. Therefore,
in the example, if f_1
was to be maximized instead, we should have called solve
with the argument f_1_min
.
The results contained in SolverResults will then correspond to the original maximized function f_1
. It is
the jobs of the evaluators to make sure that f_1_min
is available. Likewise, if we have
Scalarized the problem, we can give the solver the symbol of the added
scalarization function.
Likewise for ScipyDeSolver utilizing
differential_evolution
:
from desdeo.tools import ScipyDeSolver
problem: Problem # a problem with the objectives f_1, f_2, and f_3 to be minimized
solver = ScipyDeSolver(problem)
results: SolverResults = solver.solve("f_1")
Note
Whichever function we request a solver to optimize, it will be minimized.
Proximal solver
The proximal solver is useful when a Problem
has been defines such that all of
its objective functions have been defined with a
DiscreteRepresentation. The
proximal solver takes a symbol to optimize, and will return the decision
variable values that correspond to the lowest value found for the symbol in the
data. It works identically to the scipy solvers in the previous example:
from desdeo.tools import ProximalSolver
problem: Problem # a problem with the objectives f_1, f_2, and f_3, and a discrete definition available
solver = ProximalSolver(problem)
results: SolverResults = solver.solve("f_1")
Pyomo solvers
WIP.
Gurobipy solver
The gurobipy solver is suitable for solving mixed-integer
linear and quadratic optimization problems. GurobipySolver also does not support non-differentiable problems, for
example, problems with some max terms, like many (non-differentiable) functions.
Like the other solvers, the gurobipy solver takes the symbol of
the objective function minimized (or maximized, with the above mentioned added _min
) and returns the results of
the optimization:
from desdeo.tools import GurobipySolver
problem: Problem # a problem with the objectives f_1, f_2, and f_3
solver = GurobipySolver(problem)
results: SolverResults = solver.solve("f_1")
Nevergrad solver
TODO.
Summary of Solvers
TODO.