Automatic design and configuration of multi-objective metaheuristics

Author:

Antonio J. Nebro <ajnebro@uma.es>

Date:

2026-09-30

Important

jMetal 7.6 is the last version in which the jmetal-auto sub-project is updated. From now on it is frozen: no new features or algorithms will be added, as its functionality is covered by the Evolver project, which is under active development. The classes, examples and irace resources described in this section remain available in the 7.6 release.

Before reading this section, readers are referred to the papers [NLB+19] and [DNL+22]. Please, take into account that this is a research line that is currently guiding the evolution of jMetal, so changes are expected in the incoming releases.

Motivation

A current trend in multi-objective optimization is to use automatic design and automatic parameter configuration tools to find accurate settings of metaheuristics to effectively solve a number of problems. The idea is to avoid the traditional approach of carrying out a number of pilot tests, which are typically conducted without following a systematic strategy. In this context, an algorithm configuration is a complete assignment of values to all required parameters of the algorithm.

Our approach is to combine jMetal with an auto-configuration tool. Concretely, we have selected irace (https://mlopez-ibanez.github.io/irace/), an R package that implements an elitist iterated racing algorithm, where algorithm configurations are sampled from a sampling distribution, uniformly at random at the beginning, but biased towards the best configurations found in later iterations. At each iteration, the generated configurations and the “elite” ones from previous iterations are raced by evaluating them on training problem instances. A statistical test is used to decide which configurations should be eliminated from the race. When the race terminates, the surviving configurations become elites for the next iteration.

Using the already existing algorithms in jMetal is not feasible as their design does not fulfill the requirements of the integration with irace (see again [NLB+19]). Our strategy has been to develop two jMetal sub-projects: jmetal-component and jmetal-auto.

Available algorithms

The following auto-configurable algorithms are currently available. All of them are located in the org.uma.jmetal.auto.autoconfigurablealgorithm package of the jmetal-auto sub-project:

Class

Algorithm

Encoding

irace parameter file generator

AutoNSGAII

NSGA-II

Real

AutoNSGAIIIraceParameterFileGenerator

AutoNSGAIIPermutation

NSGA-II

Permutation

AutoNSGAIIPermutationIraceParameterFileGenerator

AutoMOPSO

MOPSO (SMPSO and OMOPSO components)

Real

AutoMOPSOIraceFileGenerator

AutoMOEAD

MOEA/D and MOEA/D-DE

Real

AutoMOEADIraceParameterFileGenerator

AutoMOEADPermutation

MOEA/D

Permutation

AutoMOEADPermutationIraceParameterFileGenerator

AutoSMSEMOA

SMS-EMOA

Real

AutoSMSEMOAIIIraceParameterFileGenerator

AutoSMSEMOAPermutation

SMS-EMOA

Permutation

AutoSMSEMOAIIIracePermutationParameterFileGenerator

AutoAGEMOEA

AGE-MOEA and AGE-MOEA-II

Real

AutoAGEMOEAIraceParameterFileGenerator

AutoRVEA

RVEA, RVEA* and iRVEA

Real

AutoRVEAIraceParameterFileGenerator

The generators are located in the org.uma.jmetal.auto.irace.parameterfilegeneration package. We describe next AutoNSGAII and AutoMOPSO, which were the first ones to be developed and which we use to explain the whole process, and then the rest of the algorithms.

Structure of an auto-configurable algorithm

All the classes implement the AutoConfigurableAlgorithm interface, and they share the same structure:

  • A list of fixed parameters (fixedParameterList()): the problem to solve, its reference Pareto front, the maximum number of evaluations and the seed of the random generator (and, in some algorithms, the population size). They are not tuned; they describe the problem instance.

  • A list of configurable parameters (configurableParameterList()): the components and parameters that a configurator such as irace can modify. A parameter can have global sub-parameters, which are required whatever its value is, and specific sub-parameters, which are only required for some of its values (e.g., the distribution index of the SBX crossover). AutoConfigurableAlgorithm.parameterFlattening() returns all of them in a single list.

  • A parse() method that receives an array of strings with pairs “–parameterName parameterValue” and checks their values.

  • A create() method that builds an instance of the algorithm (an EvolutionaryAlgorithm or a ParticleSwarmOptimizationAlgorithm) from the catalogue of components of jmetal-component.

The parameter file required by irace can be obtained from the configurable parameters of any of these classes, by running its generator. For example, for AutoRVEA:

java -cp jmetal-auto/target/jmetal-auto-7.8-jar-with-dependencies.jar \
  org.uma.jmetal.auto.irace.parameterfilegeneration.AutoRVEAIraceParameterFileGenerator > parameters-RVEA.txt

AutoNSGA-II

The standard NSGA-II is a generational evolutionary algorithm featured by using a ranking method based on Pareto ranking and the crowding distance density estimator, both in the selection and replacement steps. When it is used to solve continuous problems, NSGA-II adopts the simulated binary crossover (SBX) and the polynomial mutation. No external archive is included in NSGA-II.

However, as we intend to configure NSGA-II in an automatic way, we have extended the aforementioned features in order to have enough flexibility to modify the search capabilities of the algorithm. This way, we are going to consider that any multi-objective evolutionary algorithm with the typical parameters (selection, crossover, and mutation) and using ranking and crowding in the replacement step can be considered as a variant of NSGA-II.

The components and parameters of NSGA-II (i.e., the parameter space) that can be tuned are included in this table:

Parameter name

Allowed values

populationSize

100

algorithmResult

externalArchive, population

populationSizeWithArchive

[10, 200]

externalArchive

crowdingDistanceArchive, unboundedArchive

createInitialSolutions

random, latinHypercubeSampling, scatterSearch

variation

crossoverAndMutationVariation

offspringPopulationSize

1, 2, 5, 10, 20, 50, 100, 150, 200, 300, 400

crossover

SBX, BLX_ALPHA, wholeArithmetic

crossoverProbability

[0.0, 1.0]

crossoverRepairStrategy

random, round, bounds

sbxDistributionIndex

[5.0, 400.0]

blxAlphaCrossoverAlphaValue

[0.0, 1.0]

mutation

uniform, polynomial, linkedPolynomial, nonUniform

mutationProbabilityFactor

[0.0, 2.0]

mutationRepairStrategy

random, round, bounds

polynomialMutationDistributionIndex

[5.0, 400.0]

linkedPolynomialMutationDistributionIndex

[5.0, 400.0]

uniformMutationPerturbation

[0.0, 1.0]

nonUniformMutationPerturbation

[0.0, 1.0]

selection

random, tournament

selectionTournamentSize

[2, 10]

Our autoNSGAII can adopt an external archive to store the non-dominated solutions found during the search process. There are two choices for this archive:

  • A bounded archive that uses the crowding distance estimator to remove solutions with the archive is full. The size of this archive is given by the populationSize.

  • An unbounded archive, but when the algorithm finishes a subset of solutions (of size populationSize) are selected from the archive and returned as a result.

In case of using no archive, the result of the algorithm is the population, which is configured with the populationSize parameter; otherwise, the output is the external archive but then the population size can be tuned by taking values in the range [10, 200]).

The initial population is typically filled with randomly created solutions, but we also allows to use a latin hypercube sampling scheme and a strategy similar to the one used in the scatter search algorithm.

In the classical NSGA-II, the offspring population size is equal to the population size, but we can select a value from the set {1, 2, 5, 10, 20, 50, 100, 150, 200, 300, 400}; the value 1 leads to a steady-state selection scheme.

The autoNSGAII has a variation component than can take a single value named crossoverAndMutationVariation. It is intended to represent the typical crossover and mutation operators of a genetic algorithm (additional values, e.g., DifferentialiEvolutionVariation are expected to be added in the future). The crossover operators included are SBX (simulated binary crossover), BLX_ALPHA and wholeArithmetic, which are featured by a given probability and a crossoverRepairStrategy, which defines what to do when the crossover produces a variable value out of the allowed bounds (please, refer to Section 3.2 and Figure 3 in the paper). The SBX and BLX_ALPHA require, if selected, a distribution index (a value within the range [5.0, 400]) and an alpha value (range [0.0, 1.0]), respectively.

Similarly, there are several mutation operators to choose from, including polynomial, linkedPolynomial, uniform, and nonUniform, requiring all of them a mutation probability and a repairing strategy; the polynomial and linked polynomial mutations have, as the SBX crossover, a distribution index parameter (in the range [5.0, 400]) and the uniform and nonUniform mutation operators need a perturbation value in the range [0.0, 1.0]. The mutation probability is defined by using a mutation probability factor (a value in the range [0.0, 2.0]), so that the effective mutation probability is the multiplication of that factor with 1.0/N, where N is the number of variables of the problem being optimized.

Finally, the selection operator be random or tournament; this last one can take a value between 2 (i.e., binary tournament) and 10.

As we want to use irace as auto-tuning package, it requires a text file containing information about the parameters, the values they can take, an their relationships. We have created then a file called parameters-NSGAII.txt containing the parameter space:

algorithmResult                          "--algorithmResult "                     c       (externalArchive, population)
populationSizeWithArchive                "--populationSizeWithArchive "           i       (10, 200)                      | algorithmResult %in% c("externalArchive")
externalArchive                          "--externalArchive "                     c       (crowdingDistanceArchive, unboundedArchive) | algorithmResult %in% c("externalArchive")
#
createInitialSolutions                   "--createInitialSolutions "              c       (random, latinHypercubeSampling, scatterSearch)
#
variation                                "--variation "                           c       (crossoverAndMutationVariation)
offspringPopulationSize                  "--offspringPopulationSize "             c       (100)                          | variation %in% c("crossoverAndMutationVariation")
crossover                                "--crossover "                           c       (SBX, BLX_ALPHA, wholeArithmetic) | variation %in% c("crossoverAndMutationVariation")
crossoverProbability                     "--crossoverProbability "                r       (0.0, 1.0)                     | crossover %in% c("SBX","BLX_ALPHA","wholeArithmetic")
crossoverRepairStrategy                  "--crossoverRepairStrategy "             c       (random, round, bounds)        | crossover %in% c("SBX","BLX_ALPHA","wholeArithmetic")
sbxDistributionIndex                     "--sbxDistributionIndex "                r       (5.0, 400.0)                   | crossover %in% c("SBX")
blxAlphaCrossoverAlphaValue              "--blxAlphaCrossoverAlphaValue "         r       (0.0, 1.0)                     | crossover %in% c("BLX_ALPHA")
mutation                                 "--mutation "                            c       (uniform, polynomial, linkedPolynomial, nonUniform) | variation %in% c("crossoverAndMutationVariation")
mutationProbabilityFactor                "--mutationProbabilityFactor "           r       (0.0, 2.0)                     | mutation %in% c("uniform","polynomial","linkedPolynomial","nonUniform")
mutationRepairStrategy                   "--mutationRepairStrategy "              c       (random, round, bounds)        | mutation %in% c("uniform","polynomial","linkedPolynomial","nonUniform")
polynomialMutationDistributionIndex      "--polynomialMutationDistributionIndex " r       (5.0, 400.0)                   | mutation %in% c("polynomial")
linkedPolynomialMutationDistributionIndex "--linkedPolynomialMutationDistributionIndex " r       (5.0, 400.0)                   | mutation %in% c("linkedPolynomial")
uniformMutationPerturbation              "--uniformMutationPerturbation "         r       (0.0, 1.0)                     | mutation %in% c("uniform")
nonUniformMutationPerturbation           "--nonUniformMutationPerturbation "      r       (0.0, 1.0)                     | mutation %in% c("nonUniform")
#
selection                                "--selection "                           c       (tournament, random)
selectionTournamentSize                  "--selectionTournamentSize "             i       (2, 10)                        | selection %in% c("tournament")
#

To know about the syntax of irace configuration files, please refer to the irace documentation.

Note

The file parameters-NSGAII.txt included in the project fixes offspringPopulationSize to 100, as in the study presented in [NLB+19]. The AutoNSGAII class accepts all the values listed in the table above, and the complete parameter space can be generated with AutoNSGAIIIraceParameterFileGenerator.

The AutoNSGAII class

Without entering into implementation details, the auto-configuration of NSGA-II is based on the AutoNSGAII class located in the org.uma.jmetal.auto.autoconfigurablealgorithm package. This class can parse a string defining a particular NSGA-II configuration and create an instance of the algorithm. Each parameter in the string is defined as a pair “–parameterName parameterValue “. An example can be found in the NSGAIIConfiguredFromAParameterString class (located in the examples sub-directory):

public class NSGAIIConfiguredFromAParameterString {

  public static void main(String[] args) {
    String referenceFrontFileName = "resources/referenceFrontsCSV/ZDT1.csv";

    String[] parameters =
        ("--problemName org.uma.jmetal.problem.multiobjective.zdt.ZDT1 "
            + "--randomGeneratorSeed 12 "
            + "--referenceFrontFileName " + referenceFrontFileName + " "
            + "--maximumNumberOfEvaluations 10000 "
            + "--populationSize 100 "
            + "--algorithmResult population "
            + "--createInitialSolutions random "
            + "--offspringPopulationSize 100 "
            + "--variation crossoverAndMutationVariation "
            + "--crossover SBX "
            + "--crossoverProbability 0.9 "
            + "--crossoverRepairStrategy bounds "
            + "--sbxDistributionIndex 20.0 "
            + "--mutation polynomial "
            + "--mutationProbabilityFactor 1.0 "
            + "--polynomialMutationDistributionIndex 20.0 "
            + "--mutationRepairStrategy bounds "
            + "--selection tournament "
            + "--selectionTournamentSize 2 ")
            .split("\\s+");

    AutoNSGAII autoNSGAII = new AutoNSGAII();
    autoNSGAII.parse(parameters);

    EvolutionaryAlgorithm<DoubleSolution> nsgaII = autoNSGAII.create();

    nsgaII.run();

    new SolutionListOutput(nsgaII.result())
        .setVarFileOutputContext(new DefaultFileOutputContext("VAR.csv", ","))
        .setFunFileOutputContext(new DefaultFileOutputContext("FUN.csv", ","))
        .print();
  }
}

Auto-configuration of AutoNSGA-II

To replicate the study presented in [NLB+19] you must follow the steps indicated in this section.

The software requirements are the following:

  • Java JDK (21+)

  • R

The first step is to create a directory for the experiment. Let us called is, for example, iraceJMetal. This directory must contain:

  • File jmetal-auto-7.8-jar-with-dependencies.jar. To generate this file, just type the following command at the root of the jMetal project:

    mvn clean package -DskipTests=true
    

    If everything goes fine, the file will be generated in the jmetal-auto/target folder.

  • The following contents available in folder jmetal-auto/src/main/resources/irace:

    1. irace_3.5.1.tar.gz: file containing irace

    2. autoNSGAIIZDT: directory containing the scenario-NSGAII.txt configuration file, which is prepared to execute the autoconfiguration of NSGA-II using the ZDT problems as training set and the hypervolume as quality indicator for irace. This directory will contain both the temporal as well as the final files generated during the run of irace.

    3. parameters-NSGAII.txt: file describing the parameters that can be tuned, including their allowed values and their dependencies. You are free to modify some parameter values if you know their meaning.

    4. instances-list-ZDT.txt: the problems to be solved (we are assuming the ZDT suite), their reference Pareto fronts, the maximum number of evaluations to be computed are included here:

    org.uma.jmetal.problem.multiobjective.zdt.ZDT1 --referenceFrontFileName ZDT1.csv  --maximumNumberOfEvaluations 10000 --populationSize 100
    org.uma.jmetal.problem.multiobjective.zdt.ZDT2 --referenceFrontFileName ZDT2.csv  --maximumNumberOfEvaluations 10000 --populationSize 100
    org.uma.jmetal.problem.multiobjective.zdt.ZDT3 --referenceFrontFileName ZDT3.csv  --maximumNumberOfEvaluations 10000 --populationSize 100
    org.uma.jmetal.problem.multiobjective.zdt.ZDT4 --referenceFrontFileName ZDT4.csv  --maximumNumberOfEvaluations 10000 --populationSize 100
    org.uma.jmetal.problem.multiobjective.zdt.ZDT6 --referenceFrontFileName ZDT6.csv  --maximumNumberOfEvaluations 10000 --populationSize 100
    
    1. run.sh. Bash script to run irace. IMPORTANT: the number of cores to be used by irace are indicated in the IRACE_PARAMS variable.

  • A copy of the resources folder of the jMetal project. This is needed to allow the algorithm to find the reference fronts.

Running irace

Once we have all the needed resources in the iraceJmetal directory, we are ready to execute the script that will carry out the auto-configuraton by using irace. Take into account that irace will generate thousands of configurations (the default value is 100,000), so using a multi-core machine is advisable. We have tested the software in Linux and macOS.

To run irace simply run the following command:

./run.sh autoNSGAIIZDT/scenario-NSGAII.txt 1

The last parameter is used as a run identifier.

Results

irace will use the directory called autoNSGAIIZDT/execdir-1 (the 1 is the run identifier) to write a number of output files. Two of those files are of particular interest: irace.stderr.out and irace.sdtout.out. The first file should be empty, i.e., we should get an empty line when executing this command:

cat autoNSGAIIZDT/execdir-1/irace.stderr.out

The second file contains a lot of information about the run of irace, including the configurations being tested. We are particularly interested in the best found configurations, which are written at the end of the file (just below the line starting by “# Best configuration as command lines”). For example, a result is the following:

# Best configurations as command lines (first number is the configuration ID; same order as above):
4646  --algorithmResult externalArchive --populationSize 100 --populationSizeWithArchive 20 --maximumNumberOfEvaluations 25000 --createInitialSolutions random --variation crossoverAndMutationVariation --offspringPopulationSize 1 --crossover BLX_ALPHA --crossoverProbability 0.876 --crossoverRepairStrategy random --blxAlphaCrossoverAlphaValue 0.5729 --mutation uniform --mutationProbability 0.0439 --mutationRepairStrategy bounds --uniformMutationPerturbation 0.9957 --selection tournament --selectionTournamentSize 8

This configuration can be used in the NSGAIIConfiguredFromAParameterString program, replacing the existing one, to run NSGA-II with those settings.

AutoMOPSO

After NSGA-II, the second algorithm we have considered for auto-design and configuration is a multi-objective particle swarm optimizer (MOPSO). By taking the basic components of two MOPSO algorithms included in jMetal, namely SMPSO and OMOPSO, we have implemented an AutoMOPSO class following the same strategy adopted with AutoNSGAII. This approach has led to the paper Automatic Design of Multi-Objective Particle Swarm Optimizers, which as been accepted in the ANTs 2022 conference.

The components and parameters space of AutoMOPSO are included in the next table:

Parameter name | Allowed values

swarmSize | [10, 200]

externalArchive

crowdingDistanceArchive, hypervolumeArchive, spatialSpreadDeviationArchive

swarmInitialization

random, latinHypercubeSampling, scatterSearch

mutation

uniform, polynomial, nonUniform

mutationProbabilityFactor

[0.0,2.0]

mutationRepairStrategy

random, round, bounds

uniformMutationPerturbation

[0.0,1.0] if mutation=uniform

polynomialMutationDistributionIndex

[5.0,400.0] if mutation=polynomial

nonUniformMutationPerturbation

[0.0,1.0] if mutation=nonUniform

frequencyOfApplicationOfMutationOperator

[1,10]

inertiaWeightComputingStrategy

constant, random, linearIncreasing, linearDecreasing

weight

[0.1,1.0]

weightMin

[0.1,2.0]

weightMax

[0.5,1.0]

velocityUpdate

defaultVelocityUpdate, constrainedVelocityUpdate

c1Min

[1.0,2.0]

c1Max

[2.0,3.0]

c2Min

[1.0,2.0]

c2Max

[2.0,3.0]

globalBestSelection

binaryTournament, random

velocityChangeWhenLowerLimitIsReached

[-1.0,1.0]

velocityChangeWhenUpperLimitIsReached

[-1.0,1.0]

With AutoMOPSO, we assume that all the MOPSO algorithms have an external archive to store the non-dominated solutions found during the search process. This archive is bounded, and three density estimators can be used to remove solutions when it is full: * The crowding distance of NSGA-II * The contribution to the Hypervolume * The spatial spread deviation adoted by FAME

As the resulting solutions are those included in the archive, the swarm size can be tuned by taking values in the range [10, 200]).

As in AutoNSGAII, the initial swarm can be filled according to three strategies: random, latin hypercube sampling and scatter search.

The MOPSOs generated with AutoMOPSO are endowed with perturbation step, consisting in applying a mutation operator to individuals of the swarm, which are selected according to a frequencyOfApplicationOfMutationOperatorFrequency parameter ranging between 1 and 10. Thus, the particles to be mutated are those in positions divisible by that parameter. The mutation operator are the same used in AutoNSGAII. The speeds of the particles are initialized by default to 0.0.

weightMax and weightMin represent the inertia weight. There are four strategies for computing the inertia weight: constant (a value between 0.1 and 1.0), random, linear increasing and linear decreasing, the three last with minimum and maximum weight values in the ranges [0.1, 0.5] and [0.5, 1.0], respectively.

The two alternatives for velocity updating are the default one, corresponding to the classical scheme that is used in OMOPSO, and the constraint speed mechanism applied in SMPSO. The C1 and C2 (min and max) coefficients take values from the ranges [1.0, 2.0] and [2.0, 3.0], respectively.

The default policies for initializing and updating the local best are that each particle is its local best at the beginning and the local best is updated if the particle dominates it. The selection of the global best consists in taking solutions from the external archive by applying a random or a binary tournament scheme.

Finally, the default position update also applies the classical strategy, but if the resulting position of a particle is lower than the lower bound of the allowed position values, the position of the particle is set to the lower bound value and the velocity is changed by multiplying if by value in the range [-1, 1]. The same applies in the case of the upper bound.

As with AutoNSGAII, we have created then a file called parameters-MOPSO.txt containing the required information:

swarmSize                                "--swarmSize "                           i       (10, 200)
#
archiveSize                              "--archiveSize "                         o       (100)
#
externalArchive                          "--externalArchive "                     c       (crowdingDistanceArchive)
#
swarmInitialization                      "--swarmInitialization "                 c       (random, latinHypercubeSampling, scatterSearch)
#
velocityInitialization                   "--velocityInitialization "              c       (defaultVelocityInitialization)
#
perturbation                             "--perturbation "                        c       (frequencySelectionMutationBasedPerturbation)
mutation                                 "--mutation "                            c       (uniform, polynomial, nonUniform) | perturbation %in% c("frequencySelectionMutationBasedPerturbation")
mutationProbability                      "--mutationProbability "                 r       (0.0, 1.0)                     | mutation %in% c("uniform","polynomial","nonUniform")
mutationRepairStrategy                   "--mutationRepairStrategy "              c       (random, round, bounds)        | mutation %in% c("uniform","polynomial","nonUniform")
polynomialMutationDistributionIndex      "--polynomialMutationDistributionIndex " r       (5.0, 400.0)                   | mutation %in% c("polynomial")
uniformMutationPerturbation              "--uniformMutationPerturbation "         r       (0.0, 1.0)                     | mutation %in% c("uniform")
nonUniformMutationPerturbation           "--nonUniformMutationPerturbation "      r       (0.0, 1.0)                     | mutation %in% c("nonUniform")
frequencyOfApplicationOfMutationOperator "--frequencyOfApplicationOfMutationOperator " i       (1, 10)                        | perturbation %in% c("frequencySelectionMutationBasedPerturbation")
#
inertiaWeightComputingStrategy           "--inertiaWeightComputingStrategy "      c       (constantValue, randomSelectedValue, linearIncreasingValue, linearDecreasingValue)
weight                                   "--weight "                              r       (0.1, 1.0)                     | inertiaWeightComputingStrategy %in% c("constantValue")
weightMin                                "--weightMin "                           r       (0.1, 0.5)                     | inertiaWeightComputingStrategy %in% c("randomSelectedValue", "linearIncreasingValue", "linearDecreasingValue")
weightMax                                "--weightMax "                           r       (0.5, 1.0)                     | inertiaWeightComputingStrategy %in% c("randomSelectedValue", "linearIncreasingValue", "linearDecreasingValue")
#
velocityUpdate                           "--velocityUpdate "                      c       (defaultVelocityUpdate, constrainedVelocityUpdate)
c1Min                                    "--c1Min "                               r       (1.0, 2.0)                     | velocityUpdate %in% c("defaultVelocityUpdate","constrainedVelocityUpdate")
c1Max                                    "--c1Max "                               r       (2.0, 3.0)                     | velocityUpdate %in% c("defaultVelocityUpdate","constrainedVelocityUpdate")
c2Min                                    "--c2Min "                               r       (1.0, 2.0)                     | velocityUpdate %in% c("defaultVelocityUpdate","constrainedVelocityUpdate")
c2Max                                    "--c2Max "                               r       (2.0, 3.0)                     | velocityUpdate %in% c("defaultVelocityUpdate","constrainedVelocityUpdate")
#
localBestInitialization                  "--localBestInitialization "             c       (defaultLocalBestInitialization)
#
globalBestInitialization                 "--globalBestInitialization "            c       (defaultGlobalBestInitialization)
#
globalBestSelection                      "--globalBestSelection "                 c       (binaryTournament, random)
#
globalBestUpdate                         "--globalBestUpdate "                    c       (defaultGlobalBestUpdate)
#
localBestUpdate                          "--localBestUpdate "                     c       (defaultLocalBestUpdate)
#
positionUpdate                           "--positionUpdate "                      c       (defaultPositionUpdate)
velocityChangeWhenLowerLimitIsReached    "--velocityChangeWhenLowerLimitIsReached " r       (-1.0, 1.0)                    | positionUpdate %in% c("defaultPositionUpdate")
velocityChangeWhenUpperLimitIsReached    "--velocityChangeWhenUpperLimitIsReached " r       (-1.0, 1.0)                    | positionUpdate %in% c("defaultPositionUpdate")

The AutoMOPSO class

The org.uma.jmetal.auto.autoconfigurablealgorithm contains the AutoMOPSO class, including an example of how the SMPSO algorithm can be configured using it:

public class SMPSOConfiguredFromAParameterString {

  public static void main(String[] args) {
    String referenceFrontFileName = "ZDT4.csv";

    String[] parameters =
        ("--problemName org.uma.jmetal.problem.multiobjective.zdt.ZDT4 "
            + "--referenceFrontFileName "
            + referenceFrontFileName
            + " "
            + "--maximumNumberOfEvaluations 25000 "
            + "--swarmSize 100 "
            + "--archiveSize 100 "
            + "--swarmInitialization random "
            + "--velocityInitialization defaultVelocityInitialization "
            + "--leaderArchive crowdingDistanceArchive "
            + "--localBestInitialization defaultLocalBestInitialization "
            + "--globalBestInitialization defaultGlobalBestInitialization "
            + "--globalBestSelection binaryTournament "
            + "--perturbation frequencySelectionMutationBasedPerturbation "
            + "--frequencyOfApplicationOfMutationOperator 7 "
            + "--mutation polynomial "
            + "--mutationProbabilityFactor 1.0 "
            + "--mutationRepairStrategy bounds "
            + "--polynomialMutationDistributionIndex 20.0 "
            + "--positionUpdate defaultPositionUpdate "
            + "--velocityChangeWhenLowerLimitIsReached -1.0 "
            + "--velocityChangeWhenUpperLimitIsReached -1.0 "
            + "--globalBestUpdate defaultGlobalBestUpdate "
            + "--localBestUpdate defaultLocalBestUpdate "
            + "--velocityUpdate constrainedVelocityUpdate "
            + "--inertiaWeightComputingStrategy randomSelectedValue "
            + "--c1Min 1.5 "
            + "--c1Max 2.5 "
            + "--c2Min 1.5 "
            + "--c2Max 2.5 "
            + "--weightMin 0.1 "
            + "--weightMax 0.5 ")
            .split("\\s+");

    AutoMOPSO autoMOPSO = new AutoMOPSO();
    autoMOPSO.parseAndCheckParameters(parameters);

    AutoMOPSO.print(autoMOPSO.fixedParameterList);
    AutoMOPSO.print(autoMOPSO.autoConfigurableParameterList);

    ParticleSwarmOptimizationAlgorithm smpso = autoMOPSO.create();

    RunTimeChartObserver<DoubleSolution> runTimeChartObserver =
        new RunTimeChartObserver<>(
            "SMPSO", 80, 500, "resources/referenceFrontsCSV/" + referenceFrontFileName);

    smpso.getObservable().register(runTimeChartObserver);

    smpso.run();

    JMetalLogger.logger.info("Total computing time: " + smpso.getTotalComputingTime()); ;

    new SolutionListOutput(smpso.getResult())
        .setVarFileOutputContext(new DefaultFileOutputContext("VAR.csv", ","))
        .setFunFileOutputContext(new DefaultFileOutputContext("FUN.csv", ","))
        .print();

    System.exit(0);
  }
}

Auto-configuration of AutoSMPSO

To replicate the study presented in [DNL+22] we have just to repeat the same steps followed for AutoNSGA-II, but taking account the following:

  1. The parameter file is parameters-MOPSO.txt.

  2. The scenario is defined in the file autoMOPSOZDT/scenario-MOPSO.txt.

  3. To run irace, the command is:

./run.sh autoMOPSOZDT/scenario-MOPSO.txt 1

When irace finishes, the best found configuration can be found by typing:

cat autoMOPSOZDT/execdir-1/irace.stdout.out

At the end of the output file, we can find something similar to this piece of text:

# Best configurations as commandlines (first number is the configuration ID; same order as above):
2464  --swarmSize 11 --archiveSize 100 --externalArchive hypervolumeArchive --swarmInitialization scatterSearch --velocityInitialization defaultVelocityInitialization --perturbation frequencySelectionMutationBasedPerturbation --mutation uniform --mutationProbabilityFactor 0.1791 --mutationRepairStrategy random --uniformMutationPerturbation 0.7245 --frequencyOfApplicationOfMutationOperator 8 --inertiaWeightComputingStrategy constantValue --weight 0.1081 --velocityUpdate constrainedVelocityUpdate --c1Min 1.7965 --c1Max 2.4579 --c2Min 1.0514 --c2Max 2.5417 --localBestInitialization defaultLocalBestInitialization --globalBestInitialization defaultGlobalBestInitialization --globalBestSelection binaryTournament --globalBestUpdate defaultGlobalBestUpdate --localBestUpdate defaultLocalBestUpdate --positionUpdate defaultPositionUpdate --velocityChangeWhenLowerLimitIsReached 0.1399 --velocityChangeWhenUpperLimitIsReached -0.7488

This configuration can be used in the SMPSOConfiguredFromAParameterString program, replacing the existing one, to run AutoMOPSO with those settings.

AutoMOEAD

AutoMOEAD covers MOEA/D and MOEA/D-DE. The aggregation function, the neighborhood, the number of solutions that an offspring can replace, and the way of generating the sub-problem indices are configurable. The variation component can be a genetic one (crossover and mutation) or a differential evolution one; the pbiTheta and ipbiTheta parameters are only required with the penaltyBoundaryIntersection and invertedPenaltyBoundaryIntersection aggregation functions, and epsilonParameterForNormalizing when the objectives are normalized.

Parameter name

Allowed values

neighborhoodSize

[5, 50]

maximumNumberOfReplacedSolutions

[1, 5]

aggregationFunction

tschebyscheff, weightedSum, penaltyBoundaryIntersection, modifiedTschebyscheff, augmentedTschebyscheff, invertedPenaltyBoundaryIntersection

normalizeObjectives

TRUE, FALSE

epsilonParameterForNormalizing

[1.0E-7, 25.0]

pbiTheta

[1.0, 200.0]

ipbiTheta

[0.001, 1.0]

sequenceGenerator

permutation, integerSequence

algorithmResult

externalArchive, population

externalArchive

crowdingDistanceArchive, unboundedArchive

createInitialSolutions

random, latinHypercubeSampling, scatterSearch

variation

crossoverAndMutationVariation, differentialEvolutionVariation

offspringPopulationSize

1

crossover

SBX, BLX_ALPHA, wholeArithmetic

mutation

uniform, polynomial, linkedPolynomial, nonUniform

differentialEvolutionCrossover

RAND_1_BIN, RAND_1_EXP, RAND_2_BIN

CR, F

[0.0, 1.0]

selection

populationAndNeighborhoodMatingPoolSelection

neighborhoodSelectionProbability

[0.0, 1.0]

The population size is a fixed parameter. For problems with more than two objectives the weight vectors are read from the resources/weightVectorFiles/moead folder (the AutoMOEAD(String weightVectorsDirectory) constructor allows to indicate another folder), so the population size must match one of the available files (e.g., 100 for the file W3D_100.dat). Examples of use can be found in the MOEADConfiguredFromAParameterString and MOEADDEConfiguredFromAParameterString classes.

AutoSMSEMOA

AutoSMSEMOA configures SMS-EMOA, a steady-state algorithm (one offspring per iteration) whose replacement is based on the hypervolume contribution. It shares with AutoNSGAII the initial solutions, the variation and the selection components, and it can also use an external archive to return the result (in which case the population size is taken from populationSizeWithArchive):

Parameter name

Allowed values

algorithmResult

externalArchive, population

populationSizeWithArchive

[10, 200]

externalArchive

crowdingDistanceArchive, unboundedArchive

createInitialSolutions

random, latinHypercubeSampling, scatterSearch

offspringPopulationSize

1

variation

crossoverAndMutationVariation

crossover

SBX, BLX_ALPHA, wholeArithmetic

mutation

uniform, polynomial, linkedPolynomial, nonUniform

selection

random, tournament

selectionTournamentSize

[2, 10]

The crossover and mutation sub-parameters are the same as in AutoNSGAII. An example can be found in the SMSEMOAConfiguredFromAParameterString class.

AutoAGEMOEA

AutoAGEMOEA configures AGE-MOEA and AGE-MOEA-II. As the algorithm variant and the environmental selection are independent parameters, the configurator can also explore combinations of both. The rest of the components are the same as in AutoNSGAII, without an external archive:

Parameter name

Allowed values

algorithmVariant

agemoea, agemoeaii

environmentalSelection

agemoea, agemoeaii

replacement

agemoeaReplacement

createInitialSolutions

random, latinHypercubeSampling, scatterSearch

offspringPopulationSize

1, 2, 5, 10, 20, 50, 100, 150, 200, 300, 400

variation

crossoverAndMutationVariation

crossover

SBX, BLX_ALPHA, wholeArithmetic

mutation

uniform, polynomial, linkedPolynomial, nonUniform

selection

random, tournament

selectionTournamentSize

[2, 10]

The files parameters-AGEMOEA.txt and autoAGEMOEAZDT/scenario-AGEMOEA.txt, located in the jmetal-auto/src/main/resources/irace folder, can be used to configure it with irace.

AutoRVEA

AutoRVEA configures the RVEA family: RVEA, RVEA* (with reference vector regeneration for problems with irregular Pareto fronts) and iRVEA (see RVEA, RVEA*, and iRVEA). Following the component-based scheme, the variant is the replacement component of the algorithm: the three of them share the initial population creation, the selection and the variation components, and only the environmental selection changes. The alpha and fr parameters (the penalty rate of the angle-penalized distance, and the frequency of adaptation of the reference vectors) are required by the three variants, while numberOfSubregions, lateStageFraction and epsilonKappa are specific of iRVEA:

Parameter name

Allowed values

replacement

rvea, rveaStar, iRVEA

alpha

[0.5, 10.0]

fr

[0.01, 1.0]

numberOfSubregions

[10, 100]

lateStageFraction

[0.5, 1.0]

epsilonKappa

[0.01, 0.2]

algorithmResult

population, externalArchive

externalArchive

crowdingDistanceArchive, unboundedArchive

createInitialSolutions

random, latinHypercubeSampling, scatterSearch

offspringPopulationSize

10, 20, 50, 100, 150, 200

variation

crossoverAndMutationVariation

crossover

SBX, BLX_ALPHA, wholeArithmetic

mutation

uniform, polynomial, linkedPolynomial, nonUniform

selection

random, tournament

selectionTournamentSize

[2, 10]

The crossover and mutation sub-parameters are the same as in AutoNSGAII.

Some remarks on the differences with the other auto-configurable algorithms:

  • The population size is not a parameter. In RVEA the population size is the number of reference vectors. By default, they are generated from the number of objectives of the problem: 100, 105, 120 and 126 vectors for 2, 3, 4 and 5 objectives (simplex lattices with 99, 13, 7 and 5 divisions), and two layers of vectors (3 and 2 divisions) for six or more objectives (e.g., 77 vectors for six objectives and 156 for eight). Any other population size can be used by giving a file of uniformly distributed weight vectors, with one vector per line, through the optional parameter --referenceVectorsFile (e.g., resources/weightVectorFiles/moead/W3D_100.dat). The number of components of the vectors must be the number of objectives. There is no populationSizeWithArchive parameter: when an external archive is used, its size is the number of reference vectors.

  • The number of generations is computed from the budget: (maximumNumberOfEvaluations - N) / offspringPopulationSize, where N is the number of reference vectors. It determines the penalty schedule and the moments when the vectors are adapted, so the budget must be at least N.

  • The offspring population size is limited to the range [10, 200]. Contrarily to what happens in NSGA-II, smaller values hardly improve the quality of the results (a new solution only enters the population if it beats the current one of its region) and they multiply the running time, since the cost of the environmental selection of each generation depends mainly on N; larger values degrade the results on some problems.

  • Tournament selection: as the population of RVEA can shrink when some regions are empty, a tournament selection falls back to random selection when the population is smaller than the tournament size.

  • Only unconstrained problems are supported.

The AutoRVEA class is used as the others; the RVEAConfiguredFromAParameterString example solves DTLZ2 with the default reference vectors and with the ones of a file:

String[] parameters =
    ("--problemName org.uma.jmetal.problem.multiobjective.dtlz.DTLZ2 "
        + "--randomGeneratorSeed 12 "
        + "--referenceFrontFileName resources/referenceFrontsCSV/DTLZ2.3D.csv "
        + "--maximumNumberOfEvaluations 40000 "
        + "--algorithmResult population "
        + "--createInitialSolutions random "
        + "--variation crossoverAndMutationVariation "
        + "--offspringPopulationSize 100 "
        + "--crossover SBX "
        + "--crossoverProbability 1.0 "
        + "--crossoverRepairStrategy bounds "
        + "--sbxDistributionIndex 30.0 "
        + "--mutation polynomial "
        + "--mutationProbabilityFactor 1.0 "
        + "--polynomialMutationDistributionIndex 20.0 "
        + "--mutationRepairStrategy bounds "
        + "--selection random "
        + "--replacement rvea "
        + "--alpha 2.0 "
        + "--fr 0.1 "
        + "--referenceVectorsFile resources/weightVectorFiles/moead/W3D_100.dat")
        .split("\\s+");

AutoRVEA autoRVEA = new AutoRVEA();
autoRVEA.parse(parameters);

EvolutionaryAlgorithm<DoubleSolution> rvea = autoRVEA.create();
rvea.run();

The project does not include an irace scenario for AutoRVEA yet: the parameter file can be obtained with the AutoRVEAIraceParameterFileGenerator class (see the previous section), and the scenario of AutoNSGAII can be used as a template.

Algorithms for permutation problems

The classes AutoNSGAIIPermutation, AutoMOEADPermutation and AutoSMSEMOAPermutation are the versions of NSGA-II, MOEA/D and SMS-EMOA for problems whose solutions are permutations, such as the multi-objective traveling salesman problem. The variation operators are replaced by permutation operators. For example, in AutoNSGAIIPermutation the crossover can be PMX, CX, OXD, positionBased or edgeRecombination, with a probability in [0.6, 0.9], and the mutation can be swap, displacement, insert, scramble, inversion or simpleInversion, with a probability in [0.05, 0.1]. The rest of the components follow those of the corresponding real-coded algorithm, with some restrictions: for example, the initial solutions are always created randomly, and AutoMOEADPermutation offers four aggregation functions (tschebyscheff, weightedSum, penaltyBoundaryIntersection and modifiedTschebyscheff) and no differential evolution variation. Examples of use are the NSGAIIConfiguredToSolveABiObjectiveTSP and MOEADConfiguredFromToSolveATriObjectiveTSP classes.

References

[NLB+19]: Nebro, A.J., López-Ibáñez, M., Barba-González, C., García-Nieto, J.: Automatic configuration of NSGA-II with jMetal and irace. GECCO ‘19: Proceedings of the Genetic and Evolutionary Computation Conference CompanionJuly 2019. DOI: https://doi.org/10.1145/3319619.3326832

[DNL+22]: Doblas, D., Nebro, A.J., López-Ibáñez, M., García-Nieto, J, Coello Coello, C.A.: Automatic Design of Multi-objective Particle Swarm Optimizers. International Conference on Swarm Intelligence (ANTS 2022). DOI: https://doi.org/10.1007/978-3-031-20176-9_3