Basics of desdeo-emo

[1]:
import plotly.graph_objects as go
import numpy as np
import pandas as pd

from desdeo_problem import variable_builder, ScalarObjective, MOProblem
from desdeo_problem.testproblems.TestProblems import test_problem_builder

from desdeo_emo.EAs.NSGAIII import NSGAIII
from desdeo_emo.EAs.RVEA import RVEA
from desdeo_emo.utilities.plotlyanimate import animate_init_, animate_next_

from pprint import pprint

Coello MOP7

Definition

Definition

Pareto set and front

Front

Define objective functions

[2]:
def f_1(x):
    term1 = ((x[:,0] - 2) ** 2) / 2
    term2 = ((x[:,1] + 1) ** 2) / 13
    return term1 + term2 + 3

def f_2(x):
    term1 = ((x[:, 0] + x[:, 1] - 3) ** 2) / 36
    term2 = ((-x[:, 0] + x[:, 1] + 2) ** 2) / 8
    return term1 + term2 - 17

def f_3(x):
    term1 = ((x[:, 0] + (2 * x[:, 1]) - 1) ** 2) / 175
    term2 = ((-x[:, 0] + 2* x[:, 1]) ** 2) / 17
    return term1 + term2 - 13

Note that the expected input x is two dimensional. It should be a 2-D numpy array.

Create Variable objects

[3]:
help(variable_builder)
Help on function variable_builder in module desdeo_problem.problem.Variable:

variable_builder(names: List[str], initial_values: Union[List[float], numpy.ndarray], lower_bounds: Union[List[float], numpy.ndarray] = None, upper_bounds: Union[List[float], numpy.ndarray] = None) -> List[desdeo_problem.problem.Variable.Variable]
    Automatically build all variable objects.

    Arguments:
        names (List[str]): Names of the variables
        initial_values (np.ndarray): Initial values taken by the variables.
        lower_bounds (Union[List[float], np.ndarray], optional): Lower bounds of the
            variables. If None, it defaults to negative infinity. Defaults to None.
        upper_bounds (Union[List[float], np.ndarray], optional): Upper bounds of the
            variables. If None, it defaults to positive infinity. Defaults to None.

    Raises:
        VariableError: Lengths of the input arrays are different.

    Returns:
        List[Variable]: List of variable objects

[4]:
list_vars = variable_builder(['x', 'y'],
                             initial_values = [0,0],
                             lower_bounds=[-400, -400],
                             upper_bounds=[400, 400])
list_vars
[4]:
[<desdeo_problem.problem.Variable.Variable at 0x18dcf70c340>,
 <desdeo_problem.problem.Variable.Variable at 0x18dcf682ca0>]

Create Objective objects

[5]:
f1 = ScalarObjective(name='f1', evaluator=f_1)
f2 = ScalarObjective(name='f2', evaluator=f_2)
f3 = ScalarObjective(name='f3', evaluator=f_3)
list_objs = [f1, f2, f3]

Create the problem object

[6]:
problem = MOProblem(variables=list_vars, objectives=list_objs)

Using the EAs

Pass the problem object to the EA, pass parameters as arguments if required.

[7]:
help(NSGAIII)
Help on class NSGAIII in module desdeo_emo.EAs.NSGAIII:

class NSGAIII(desdeo_emo.EAs.BaseEA.BaseDecompositionEA)
 |  NSGAIII(problem: desdeo_problem.problem.Problem.MOProblem, population_size: int = None, population_params: Dict = None, n_survive: int = None, initial_population: desdeo_emo.population.Population.Population = None, lattice_resolution: int = None, selection_type: str = None, interact: bool = False, use_surrogates: bool = False, n_iterations: int = 10, n_gen_per_iter: int = 100, total_function_evaluations: int = 0, keep_archive: bool = False)
 |
 |  Python Implementation of NSGA-III. Based on the pymoo package.
 |
 |  Most of the relevant code is contained in the super class. This class just assigns
 |  the NSGAIII selection operator to BaseDecompositionEA.
 |
 |  Parameters
 |  ----------
 |  problem : MOProblem
 |      The problem class object specifying the details of the problem.
 |  population_size : int, optional
 |      The desired population size, by default None, which sets up a default value
 |      of population size depending upon the dimensionaly of the problem.
 |  population_params : Dict, optional
 |      The parameters for the population class, by default None. See
 |      desdeo_emo.population.Population for more details.
 |  initial_population : Population, optional
 |      An initial population class, by default None. Use this if you want to set up
 |      a specific starting population, such as when the output of one EA is to be
 |      used as the input of another.
 |  lattice_resolution : int, optional
 |      The number of divisions along individual axes in the objective space to be
 |      used while creating the reference vector lattice by the simplex lattice
 |      design. By default None
 |  selection_type : str, optional
 |      One of ["mean", "optimistic", "robust"]. To be used in data-driven optimization.
 |      To be used only with surrogate models which return an "uncertainity" factor.
 |      Using "mean" is equivalent to using the mean predicted values from the surrogate
 |      models and is the default case.
 |      Using "optimistic" results in using (mean - uncertainity) values from the
 |      the surrogate models as the predicted value (in case of minimization). It is
 |      (mean + uncertainity for maximization).
 |      Using "robust" is the opposite of using "optimistic".
 |  a_priori : bool, optional
 |      A bool variable defining whether a priori preference is to be used or not.
 |      By default False
 |  interact : bool, optional
 |      A bool variable defining whether interactive preference is to be used or
 |      not. By default False
 |  n_iterations : int, optional
 |      The total number of iterations to be run, by default 10. This is not a hard
 |      limit and is only used for an internal counter.
 |  n_gen_per_iter : int, optional
 |      The total number of generations in an iteration to be run, by default 100.
 |      This is not a hard limit and is only used for an internal counter.
 |  total_function_evaluations :int, optional
 |      Set an upper limit to the total number of function evaluations. When set to
 |      zero, this argument is ignored and other termination criteria are used.
 |
 |  Method resolution order:
 |      NSGAIII
 |      desdeo_emo.EAs.BaseEA.BaseDecompositionEA
 |      desdeo_emo.EAs.BaseEA.BaseEA
 |      builtins.object
 |
 |  Methods defined here:
 |
 |  __init__(self, problem: desdeo_problem.problem.Problem.MOProblem, population_size: int = None, population_params: Dict = None, n_survive: int = None, initial_population: desdeo_emo.population.Population.Population = None, lattice_resolution: int = None, selection_type: str = None, interact: bool = False, use_surrogates: bool = False, n_iterations: int = 10, n_gen_per_iter: int = 100, total_function_evaluations: int = 0, keep_archive: bool = False)
 |      Initialize EA here. Set up parameters, create EA specific objects.
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from desdeo_emo.EAs.BaseEA.BaseDecompositionEA:
 |
 |  end(self)
 |      Conducts non-dominated sorting at the end of the evolution process
 |
 |      Returns:
 |          tuple: The first element is a 2-D array of the decision vectors of the non-dominated solutions.
 |              The second element is a 2-D array of the corresponding objective values.
 |
 |  pre_iteration(self)
 |      Run this code before every iteration.
 |
 |  request_plot(self) -> desdeo_tools.interaction.request.SimplePlotRequest
 |
 |  request_preferences(self) -> Type[desdeo_tools.interaction.request.BaseRequest]
 |
 |  requests(self) -> Tuple
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from desdeo_emo.EAs.BaseEA.BaseEA:
 |
 |  check_FE_count(self) -> bool
 |      Checks whether termination criteria via function evaluation count has been
 |          met or not.
 |
 |      Returns:
 |          bool: True is function evaluation count limit NOT met.
 |
 |  continue_evolution(self) -> bool
 |      Checks whether the current iteration should be continued or not.
 |
 |  continue_iteration(self)
 |      Checks whether the current iteration should be continued or not.
 |
 |  iterate(self, preference=None) -> Tuple
 |      Run one iteration of EA.
 |
 |      One iteration consists of a constant or variable number of
 |      generations. This method leaves EA.params unchanged, except the current
 |      iteration count and gen count.
 |
 |  manage_preferences(self, preference=None)
 |      Forward the preference to the correct preference handling method.
 |
 |      Args:
 |          preference (_type_, optional): _description_. Defaults to None.
 |
 |      Raises:
 |          eaError: Preference handling not implemented.
 |
 |  post_iteration(self)
 |      Run this code after every iteration.
 |
 |  set_interaction_type(self, interaction_type: Optional[str]) -> Optional[str]
 |
 |  start(self)
 |      Mimics the structure of the mcdm methods. Returns the request objects from self.retuests().
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from desdeo_emo.EAs.BaseEA.BaseEA:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)
 |
 |  allowable_interaction_types

[8]:
evolver = NSGAIII(problem,
                  n_iterations=10,
                  n_gen_per_iter=100,
                  population_size=100)
[9]:
while evolver.continue_evolution():
    evolver.iterate()

Extracting optimized decision variables and objective values

[10]:
individuals, solutions, _ = evolver.end()

fig1 = go.Figure(
    data=go.Scatter(
        x=individuals[:,0],
        y=individuals[:,1],
        mode="markers"))
fig1