Source code for scalarization.MOEADSF

import abc
import numpy as np

from abc import abstractmethod
from typing import Union


[docs]class MOEADSFError(Exception): """Raised when an error related to the MOEADSF classes is encountered. """
[docs]class MOEADSFBase(abc.ABC): """A base class for representing scalarizing functions for the MOEA/D algorithm. Instances of the implementations of this class should work as function. """ @abstractmethod
[docs] def __call__( self, objective_vector: np.ndarray, reference_vector: np.ndarray, ideal_vector: np.ndarray, nadir_vector: np.ndarray, ) -> Union[float, np.ndarray]: """Evaluate the SF. Args: objective_vector (np.ndarray): The objective vector to calculate the values. reference_vector (np.ndarray): The reference vector to calculate the values. ideal_vector (np.ndarray): The ideal objective vector. nadir_vector (np.ndarray): The nadir objective vector. Returns: Union[float, np.ndarray]: Either a single SF value or a vector of values if objective is a 2D array. """ pass
[docs]class Tchebycheff(MOEADSFBase): """Implements the Tchebycheff scalarizing function. """
[docs] def __call__( self, objective_vector: np.ndarray, reference_vector: np.ndarray, ideal_vector: np.ndarray, ) -> Union[float, np.ndarray]: """Evaluate the Tchebycheff scalarizing function for minimization problems. Args: objective_vector (np.ndarray): A vector representing a solution in the objective space. reference_vector (np.ndarray): A reference vector representing the direction ideal_vector (np.ndarray): The ideal objective vector Raises: MOEADSFError: The dimensions of the objective vector and reference_vector don't match. Note: The shaped of objective_vector and reference_vector must match. """ if not objective_vector.shape == reference_vector.shape: msg = ( "The dimensions of the objective vector {} and " "reference_vector {} do not match." ).format(objective_vector.shape, reference_vector.shape) raise MOEADSFError(msg) feval = np.abs(objective_vector - ideal_vector) * reference_vector max_fun = np.max(feval) return max_fun
[docs]class WeightedSum(MOEADSFBase): """Implements the Weighted sum scalarization function """
[docs] def __call__( self, objective_vector: np.ndarray, reference_vector: np.ndarray ) -> Union[float, np.ndarray]: """Evaluate the WeightedSum scalarizing function. Args: objective_vector (np.ndarray): A vector representing a solution in the objective space. reference_vector (np.ndarray): A reference vector representing the direction Raises: MOEADSFError: The dimensions of the objective vector and reference_vector don't match. Note: The shaped of objective_vector and reference_vector must match. A reference point is not needed. """ if not objective_vector.shape == reference_vector.shape: msg = ( "The dimensions of the objective vector {} and " "reference_vector {} do not match." ).format(objective_vector.shape, reference_vector.shape) raise MOEADSFError(msg) feval = np.sum(objective_vector * reference_vector) return feval
[docs]class PBI(MOEADSFBase): """Implements the PBI scalarization function Args: theta(float): A penalty parameter used by the function Attributes: theta (float): A penalty parameter used by the function .. Q. Zhang and H. Li, "MOEA/D: A Multiobjective Evolutionary Algorithm Based on Decomposition," in IEEE Transactions on Evolutionary Computation, vol. 11, no. 6, pp. 712-731, Dec. 2007, doi: 10.1109/TEVC.2007.892759. """ def __init__(self, theta: float = 5): self.theta = theta
[docs] def __call__( self, objective_vector: np.ndarray, reference_vector: np.ndarray, ideal_vector: np.ndarray, ) -> Union[float, np.ndarray]: """Evaluate the PBI scalarizing function for minimization problems. Args: objective_vector (np.ndarray): A vector representing a solution in the objective space. reference_vector (np.ndarray): A reference vector representing the direction ideal_vector (np.ndarray): The ideal objecive vector Raises: MOEADSFError: The dimensions of the objective vector and reference_vector don't match. Note: The shaped of objective_vector and reference_vector must match. The reference point is not needed. """ if not objective_vector.shape == reference_vector.shape: msg = ( "The dimensions of the objective vector {} and " "reference_vector {} do not match." ).format(objective_vector.shape, reference_vector.shape) raise MOEADSFError(msg) norm_weights = np.linalg.norm(reference_vector) weights = np.true_divide(reference_vector, norm_weights) fx_a = objective_vector - ideal_vector d1 = np.fabs(np.inner(fx_a, weights)) fx_b = objective_vector - (ideal_vector + d1 * weights) d2 = np.linalg.norm(fx_b) fvalue = d1 + self.theta * d2 return fvalue