Writing Extensions for the MOEADr Package

Felipe Campelo

2023-01-06

Introduction

This is a short guide to writing new functions for the MOEADr package. This package provides a component-based framework for developing (and applying) Multiobjective Evolutionary Algorithms based on Decomposition (MOEA/D)1.

The modular implementation provided in this package provides control over the following aspects of the algorithm:

This document describes how to write functions implementing new variants for any of these modules. A general description of the algorithm and the component-based interpretation behind the MOEADr package is available in our paper2

General guidelines

Nomenclature

Important variables defined in the package

Contributing to the modules

Decomposition strategies

To discover the available decomposition strategies, use get_decomposition_methods(). Decomposition functions are called from within generate_weights().

Other guidelines and requirements:

  • The name of the function (and of the file) must have the format decomposition_XYZ, with XYZ being the moniker for the contributed method (which is going to be passed as decomp$name).
  • Please follow the one function, one file, same name policy strictly (otherwise get_decomposition_methods() won’t be able to correctly list the method).

Example file

Check decomposition_sld.R for a good example of decomposition routine (e.g., to use as a template).

Scalar aggregation functions

To discover the available decomposition strategies, use get_scalarization_methods(). Scalarization functions are called from within scalarize_values().

Other guidelines and requirements:

  • The name of the function (and of the file) must have the format scalarization_XYZ, with XYZ being the moniker for the contributed method (which is going to be passed as aggfun$name).
  • Please follow the one function, one file, same name policy strictly (otherwise get_scalarization_methods() won’t be able to correctly list the method.

Example file

Check scalarize_pbi.R for a good example of decomposition routine (e.g., to use as a template).

Neighborhood assignment options

The strategy for defining the neighborhood structure in the MOEADr package is essentially the same (use Euclidean distances and use the neighbors$T nearest subproblems as a neighborhood). The only difference is the space in which the distances are calculated, which has implications in the need for re-calculating the neighborhood structure. The neighborhoods are defined using an efficient C implementation of the k-nearest-neighbors algorithm available in function FNN::get.knn, which is the only reason why package MOEADr lists FNN in its Imports field (see DESCRIPTION).

The neighborhood assignment function is define_neighborhood(), which is called directly from the main function moead().

Other guidelines and requirements:

  • Unlike the previous modules, the neighborhood assignment strategies are defined (in the current version) as options passed to a single function define_neighborhood. Other possibilities (e.g., to deal with adaptive weights, which would require periodic recalculation) can, at least in principle, use the same strategy. However, if an alternative assignment method becomes too different from the one currently implemented, it may be better to break the options and use the one function, one file, same name policy. In this case, the current options should be moved to independent functions starting with a common preffix (as is the case with other modules, e.g., decomposition).

Example file

Check define_neighborhood.R for the current neighborhood assignment alternatives (e.g., to use as a template).

Variation operators

To discover the available variation operators, use get_variation_operators(). Variation methods are called from within perform_variation().

Other guidelines and requirements:

  • The name of the function (and of the file) must have the format variation_XYZ, with XYZ being the moniker for the contributed method.
  • the only exceptions to that naming convention are local search operators, which are called from within variation_localsearch(). Local search methods should follow the naming convention ls_XYZ, and available methods are discovered using get_localsearch_methods(). See ?variation_localsearch and the Variation section of ?moead for details.
  • Please follow the one function, one file, same name policy strictly (otherwise get_variation_operators() and get_localsearch_methods() won’t be able to correctly list the method.

Example files

Check variation_sbx.R for a good example of a non-local search variation operator, and variation_localsearch.R and ls_dvls.R for local search methods (e.g., to use as a template).

Update strategies

To discover the available decomposition strategies, use get_update_methods(). Update functions are called from within update_population().

Other guidelines and requirements:

  • The name of the function (and of the file) must have the format updt_XYZ, with XYZ being the moniker for the contributed method (which is going to be passed as update$name).
  • Please follow the one function, one file, same name policy strictly (otherwise get_update_methods() won’t be able to correctly list the method.

Example file

Check update_standard.R for a good example of update routine (e.g., to use as a template).

Constraint handling methods

To discover the available constraint handling strategies, use get_constraint_methods(). Constraint handling methods are called from within order_neighborhood().

Other guidelines and requirements:

  • The name of the function (and of the file) must have the format constraint_XYZ, with XYZ being the moniker for the contributed method (which is going to be passed as constraint$name).
  • Please follow the one function, one file, same name policy strictly (otherwise get_constraint_methods() won’t be able to correctly list the method.

Example file

Check constraint_penalty.R for a good example of constraint handling routine (e.g., to use as a template).

Objective scaling

The strategies for objective scaling currently available in the MOEADr package are essentially “none” (i.e., no scaling) and “simple” (simple linear scaling to the interval [0,1]).The scaling function is scale_objectives().

Other guidelines and requirements:

  • Unlike the previous modules, the scaling strategies are defined (in the current version) as options passed to a single function scale_objectives(). Other possibilities can, at least in principle, use the same strategy. However, if an alternative assignment method becomes too different from the one currently implemented, it may be better to break the options and use the one function, one file, same name policy. In this case, the current options should be moved to independent functions starting with a common preffix (as is the case with other modules, e.g., decomposition).

Termination Criteria

To discover the available termination criteria, use get_stop_criteria(). Termination methods are called from within check_stop_criteria().

Other guidelines and requirements:

  • The name of the function (and of the file) must have the format stop_XYZ, with XYZ being the moniker for the contributed method.
  • Please follow the one function, one file, same name policy strictly (otherwise get_stop_criteria() won’t be able to correctly list the method.

Example file

Check stop_maxiter.R for a good example of constraint handling routine (e.g., to use as a template).


  1. Q. Zhang and H. Li, “MOEA/D: A Multiobjective Evolutionary Algorithm Based on Decomposition”, IEEE Trans. Evol. Comp. 11(6): 712-731, 2007.↩︎

  2. F. Campelo, L.S. Batista and C. Aranha, “A Component-Wise Perspective on Multiobjective Evolutionary Algorithms based on Decomposition”, in preparation.↩︎