How an XLEMOO method can be used as an interactive multiobjective optimization method

In this example, we can see how an XLEMOO method can be used as an interactive multiobjective optimization method accepting reference points as preferences.

Imports

Below, we define the import needed to define our LEMOO model.

[1]:
import sys
sys.path.append("../../../XLEMOO")

import warnings

warnings.filterwarnings("ignore", category=DeprecationWarning)
warnings.filterwarnings("ignore", category=FutureWarning)

from XLEMOO.LEMOO import EAParams, MLParams, LEMParams, LEMOO, PastGeneration
from XLEMOO.fitness_indicators import asf_wrapper
from XLEMOO.selection import SelectNBest
from XLEMOO.utilities import parse_skoped_rules, complete_missing_rules, print_rules
from desdeo_emo.recombination import SBX_xover, BP_mutation
from desdeo_tools.scalarization.ASF import PointMethodASF
from desdeo_problem.testproblems import vehicle_crashworthiness

import numpy as np
from imodels import SkopeRulesClassifier

Initialize the problem

Next, we initialize a simple test problem with 3 objective functions and 5 variables. We use the vehicle crash worthiness problem.

[2]:
n_objectives = 3
n_variables = 5

problem = vehicle_crashworthiness()

Initialize an XLEMOO method

Now we are ready to define our LEMOO method. We start by defining the parameters of our model. In lem_params general parameters related to the LEMOO method are defined. In ea_params, parameters specific to the evolutionary phase of our LEMOO method are defined, and in ml_params parameters specific to the learning phase of the method are defined. For additional information about these parameters, see the API documentation of the XLEMOO framework.

[3]:
ideal = np.array([1600.0, 6.0, 0.038])
nadir = np.array([1700.0, 12.0, 0.2])
ref_point = np.array([1670.0, 7.61449, 0.085])  # the reference point

# define the achievement scalarizing function as the fitness function
ref_asf = asf_wrapper(PointMethodASF(ideal=ideal, nadir=nadir), {"reference_point": ref_point})
fitness_fun = ref_asf

lem_params = LEMParams(
    use_darwin=True,
    use_ml=True,
    fitness_indicator=fitness_fun,
    ml_probe = 1,
    ml_threshold = None,
    darwin_probe = None,
    darwin_threshold = None,
    total_iterations=10,
)

ea_params = EAParams(
    population_size=50,
    cross_over_op=SBX_xover(),
    mutation_op=BP_mutation(problem.get_variable_lower_bounds(), problem.get_variable_upper_bounds()),
    selection_op=SelectNBest(None, 50),  # keep population size constant
    population_init_design="LHSDesign",
    iterations_per_cycle=19,
)

ml = SkopeRulesClassifier(precision_min=0.1, n_estimators=30, max_features=None, max_depth=None, bootstrap=True, bootstrap_features=True, random_state=1)
ml_params = MLParams(
    H_split=0.20,
    L_split=0.20,
    ml_model=ml,
    instantiation_factor=10,
    generation_lookback=0,
    ancestral_recall=0,
    unique_only=True,
    iterations_per_cycle=1,
)

lemoo = LEMOO(problem, lem_params, ea_params, ml_params)

Run the XLEMOO method

We run our XLEMOO method for a set number of iterations in each mode. The printed output shows how many iterations were spent in each mode.

[4]:
lemoo.run_iterations()
[4]:
{'darwin_mode': 190, 'learning_mode': 10, 'total_iterations': 10}

Extract and print the rules from skope-rules and complete missing rules

Utilizing the trained XLEMOO model and helper functions imported earlier, we can extract the rules in a human readable format.

[5]:
rules_for_vars = parse_skoped_rules(lemoo=lemoo, problem=problem)
rules_for_vars = complete_missing_rules(lemoo=lemoo, rules_for_vars=rules_for_vars)

print(f"Best solution x = {lemoo._generation_history[-1].individuals[0]}")
print(f"Best objective vector z = {lemoo._generation_history[-1].objectives_fitnesses[0]}")
print_rules(lemoo=lemoo, rules_for_vars=rules_for_vars, tex=False)
Best solution x = [1.003578   2.9999997  1.         1.28857973 1.06367798]
Best objective vector z = [1.66887224e+03 7.51755804e+00 8.31730144e-02]
RULES:
Var     Lower(R)                Upper(R)                Lower(P)                Upper(P)
X_0     1.00315 (1.0)           1.0036 (1.0)            1.00358                 1.00358
X_1     2.99921 (1.0)           3.0 (-1)                3.0                     3.0
X_2     1.0     (0.49)          1.7036 (1.0)            1.0                     1.0
X_3     1.1918  (0.984)         1.5508 (1.0)            1.28858                 1.28858
X_4     1.04039 (1.0)           1.06792 (1.0)           1.06368                 1.06368

Modify variables and explore a new solution

We may then modify the variables to explore new solutions.

[6]:
x_new = np.atleast_2d([1.00184, 2.7135, 1.00000, 1.21741, 1.02602])
z_new = problem.evaluate(x_new).objectives
print(z_new)
[[1.66748556e+03 7.54345501e+00 9.49552335e-02]]

Or we may specify a new reference point and run the XLEMOO method again.