Source code for ddmtolab.Problems.MTMO.cec21_mtmo

import numpy as np
import pkgutil
import io
from ddmtolab.Methods.mtop import MTOP


class CEC21MTMOFunctions:
    """
    Helper class containing all g-function implementations for CEC21 MTMO benchmark.

    This class provides implementations of various benchmark functions used in the
    CEC 2021 Multi-Task Multi-Objective Optimization competition, including:
    - Basic functions: Rosenbrock (F4), Rastrigin (F8, F9)
    - Complex functions: Modified Schwefel (F11), ExGriewRosen (F15)
    - Hybrid functions: F17, F18, F19, F20, F22
    """

    @staticmethod
    def eval_f1_linear(x):
        """Linear f1 function for MMZDT problems."""
        # MATLAB: A = sum(x, 2); F1Function = A ./ size(x, 2);
        return np.sum(x, axis=1) / x.shape[1]

    @staticmethod
    def eval_F4(x, shift, rotation):
        """Rosenbrock Function F4."""
        x = x.copy()
        x = x - shift
        x = x * (2.048 / 100)
        x = (rotation @ x.T).T

        # Rosenbrock - 使用副本
        x_copy = x.copy()
        x_copy[:, 0] = x_copy[:, 0] + 1
        t = np.zeros(x.shape[0])
        for i in range(x.shape[1] - 1):
            x_copy[:, i + 1] = x_copy[:, i + 1] + 1
            t += 100 * (x_copy[:, i] ** 2 - x_copy[:, i + 1]) ** 2 + (1 - x_copy[:, i]) ** 2

        return t

    @staticmethod
    def eval_F8(x, shift, rotation):
        """
        Rastrigin Function F8 (non-rotated).

        A highly multimodal function with many local optima.

        Parameters
        ----------
        x : np.ndarray
            Input array of shape (n_samples, n_dims).
        shift : np.ndarray
            Shift vector.
        rotation : np.ndarray
            Rotation matrix (not used in this variant).

        Returns
        -------
        np.ndarray
            Function values of shape (n_samples,).
        """
        x = x - shift
        x = x * (5.12 / 100)

        # Rastrigin
        a = 10 * x.shape[1]
        result = np.sum(x ** 2 - 10 * np.cos(2 * np.pi * x), axis=1) + a

        return result

    @staticmethod
    def eval_F9(x, shift, rotation):
        """
        Rastrigin Function F9 (rotated).

        Rotated version of the Rastrigin function.

        Parameters
        ----------
        x : np.ndarray
            Input array of shape (n_samples, n_dims).
        shift : np.ndarray
            Shift vector.
        rotation : np.ndarray
            Rotation matrix.

        Returns
        -------
        np.ndarray
            Function values of shape (n_samples,).
        """
        x = x - shift
        x = x * (5.12 / 100)
        x = (rotation @ x.T).T

        # Rastrigin
        a = 10 * x.shape[1]
        result = np.sum(x ** 2 - 10 * np.cos(2 * np.pi * x), axis=1) + a

        return result

    @staticmethod
    def eval_F11(x, shift, rotation):
        """
        Modified Schwefel Function F11.

        A deceptive function with a second-best minimum far from the global optimum.

        Parameters
        ----------
        x : np.ndarray
            Input array of shape (n_samples, n_dims).
        shift : np.ndarray
            Shift vector.
        rotation : np.ndarray
            Rotation matrix.

        Returns
        -------
        np.ndarray
            Function values of shape (n_samples,).
        """
        x = x - shift
        x = x * (1000.0 / 100)
        x = (rotation @ x.T).T

        # Modified Schwefel
        n = x.shape[1]
        result = CEC21MTMOFunctions._modified_schwefel(x, n)

        return result

    @staticmethod
    def eval_F15(x, shift, rotation):
        """Expanded Griewank plus Rosenbrock Function F15."""
        x = x.copy()
        x = x - shift
        x = x * (5.0 / 100)
        x = (rotation @ x.T).T

        # ExGriewRosen - 使用副本
        x_copy = x.copy()
        x_copy[:, 0] = x_copy[:, 0] + 1
        result = np.zeros(x.shape[0])

        for i in range(x.shape[1] - 1):
            x_copy[:, i + 1] = x_copy[:, i + 1] + 1
            t = 100 * ((x_copy[:, i] ** 2 - x_copy[:, i + 1]) ** 2) + (x_copy[:, i] - 1) ** 2
            result += (t ** 2) / 4000 - np.cos(t) + 1

        # Wrap around: last to first
        index = x.shape[1] - 1
        t = 100 * ((x_copy[:, index] ** 2 - x_copy[:, 0]) ** 2) + (x_copy[:, index] - 1) ** 2
        result += (t ** 2) / 4000 - np.cos(t) + 1

        return result

    @staticmethod
    def eval_F17(x, shift, rotation):
        """
        Hybrid Composition Function F17.
        """
        # 确保shift的广播正确
        x = x - shift.reshape(1, -1)  # 明确reshape
        x = (rotation @ x.T).T

        D = x.shape[1]
        n1 = int(np.ceil(0.3 * D))
        n2 = int(np.ceil(0.3 * D))
        n3 = D - n1 - n2

        x1 = x[:, :n1] * (1000.0 / 100)
        x2 = x[:, n1:n1 + n2] * (5.12 / 100)
        x3 = x[:, n1 + n2:]

        # Modified Schwefel
        result = CEC21MTMOFunctions._modified_schwefel(x1, n1)

        # Rastrigin
        a = 10 * n2
        result += np.sum(x2 ** 2 - 10 * np.cos(2 * np.pi * x2), axis=1) + a

        # Elliptic
        a = 1e6
        for i in range(n3):
            result += (a ** (i / max(n3 - 1, 1))) * (x3[:, i] ** 2)

        return result

    @staticmethod
    def eval_F18(x, shift, rotation):
        """
        Hybrid Composition Function F18.

        Combines Cigar (30%) + HGBat (30%) + Rastrigin (40%).

        Parameters
        ----------
        x : np.ndarray
            Input array of shape (n_samples, n_dims).
        shift : np.ndarray
            Shift vector.
        rotation : np.ndarray
            Rotation matrix.

        Returns
        -------
        np.ndarray
            Function values of shape (n_samples,).
        """
        x = x - shift
        x = (rotation @ x.T).T

        D = x.shape[1]
        n1 = int(np.ceil(0.3 * D))
        n2 = int(np.ceil(0.3 * D))
        n3 = D - n1 - n2

        x1 = x[:, :n1]
        x2 = x[:, n1:n1 + n2] * (5.0 / 100)
        x3 = x[:, n1 + n2:] * (5.12 / 100)

        # Cigar
        a = np.sum(x1[:, 1:] ** 2, axis=1)
        result = x1[:, 0] ** 2 + a * 1e6

        # HGBat
        x2 = x2 - 1
        sum1 = np.sum(x2 ** 2, axis=1)
        sum2 = np.sum(x2, axis=1)
        result += (np.abs(sum1 ** 2 - sum2 ** 2)) ** 0.5 + (0.5 * sum1 + sum2) / n2 + 0.5

        # Rastrigin
        a = 10 * n3
        result += np.sum(x3 ** 2 - 10 * np.cos(2 * np.pi * x3), axis=1) + a

        return result

    @staticmethod
    def eval_F19(x, shift, rotation):
        """
        Hybrid Composition Function F19.

        Combines Griewank (20%) + Weierstrass (20%) + Rosenbrock (30%) + Schaffer F6 (30%).
        """
        x = x.copy()
        x = x - shift
        x = (rotation @ x.T).T

        D = x.shape[1]
        n1 = int(np.ceil(0.2 * D))
        n2 = int(np.ceil(0.2 * D))
        n3 = int(np.ceil(0.3 * D))
        n4 = D - n1 - n2 - n3

        x1 = x[:, :n1] * (600.0 / 100)
        x2 = x[:, n1:n1 + n2] * (0.5 / 100)
        x3 = x[:, n1 + n2:n1 + n2 + n3] * (2.048 / 100)
        x4 = x[:, n1 + n2 + n3:]

        # Griewank
        t = np.arange(1, n1 + 1)
        sum1 = np.sum(x1 ** 2, axis=1)
        prod1 = np.prod(np.cos(x1 / np.sqrt(t)), axis=1)
        result = 1 + sum1 / 4000 - prod1

        # Weierstrass
        a = 0.5
        b = 3
        kmax = 20
        part1 = np.zeros(x.shape[0])
        for i in range(n2):
            for k in range(kmax + 1):
                part1 += a ** k * np.cos(2 * np.pi * (b ** k) * (x2[:, i] + 0.5))

        part2 = 0
        for k in range(kmax + 1):
            part2 += a ** k * np.cos(2 * np.pi * (b ** k) * 0.5)

        result += part1 - n2 * part2

        # Rosenbrock - 修正:使用副本
        t = np.zeros(x.shape[0])
        x3_copy = x3.copy()
        x3_copy[:, 0] = x3_copy[:, 0] + 1
        for i in range(n3 - 1):
            x3_copy[:, i + 1] = x3_copy[:, i + 1] + 1
            t += 100 * (x3_copy[:, i] ** 2 - x3_copy[:, i + 1]) ** 2 + (1 - x3_copy[:, i]) ** 2

        result += t

        # Schaffer F6
        t = np.zeros(x.shape[0])
        for i in range(n4):
            next_idx = (i + 1) % n4
            pSum = x4[:, i] ** 2 + x4[:, next_idx] ** 2
            t += 0.5 + ((np.sin(pSum ** 0.5)) ** 2 - 0.5) / ((1 + 0.001 * pSum) ** 2)

        result += t

        return result

    @staticmethod
    def eval_F20(x, shift, rotation):
        """Hybrid Composition Function F20."""
        x = x.copy()
        x = x - shift
        x = (rotation @ x.T).T

        D = x.shape[1]
        n1 = int(np.ceil(0.2 * D))
        n2 = int(np.ceil(0.2 * D))
        n3 = int(np.ceil(0.3 * D))
        n4 = D - n1 - n2 - n3

        x1 = x[:, :n1] * (5.0 / 100)
        x2 = x[:, n1:n1 + n2]
        x3 = x[:, n1 + n2:n1 + n2 + n3] * (5.0 / 100)
        x4 = x[:, n1 + n2 + n3:] * (5.12 / 100)

        # HGBat - 使用副本
        x1_copy = x1.copy()
        x1_copy = x1_copy - 1
        sum1 = np.sum(x1_copy ** 2, axis=1)
        sum2 = np.sum(x1_copy, axis=1)
        result = (np.abs(sum1 ** 2 - sum2 ** 2)) ** 0.5 + (0.5 * sum1 + sum2) / n1 + 0.5

        # Discus
        result += 1e6 * (x2[:, 0] ** 2) + np.sum(x2[:, 1:] ** 2, axis=1)

        # ExGriewRosen - 使用副本
        x3_copy = x3.copy()
        x3_copy[:, 0] = x3_copy[:, 0] + 1
        for i in range(n3 - 1):
            x3_copy[:, i + 1] = x3_copy[:, i + 1] + 1
            t = 100 * (x3_copy[:, i] ** 2 - x3_copy[:, i + 1]) ** 2 + (x3_copy[:, i] - 1) ** 2
            result += (t ** 2) / 4000 - np.cos(t) + 1

        t = 100 * (x3_copy[:, n3 - 1] ** 2 - x3_copy[:, 0]) ** 2 + (x3_copy[:, n3 - 1] - 1) ** 2
        result += (t ** 2) / 4000 - np.cos(t) + 1

        # Rastrigin
        a = 10 * n4
        result += np.sum(x4 ** 2 - 10 * np.cos(2 * np.pi * x4), axis=1) + a

        return result

    @staticmethod
    def eval_F22(x, shift, rotation):
        """
        Hybrid Composition Function F22.

        Combines Katsuura (10%) + HappyCat (20%) + ExGriewRosen (20%) +
        Modified Schwefel (20%) + Ackley (30%).
        """
        x = x.copy()
        x = x - shift
        x = (rotation @ x.T).T

        D = x.shape[1]
        n1 = int(np.ceil(0.1 * D))
        n2 = int(np.ceil(0.2 * D))
        n3 = int(np.ceil(0.2 * D))
        n4 = int(np.ceil(0.2 * D))
        n5 = D - n1 - n2 - n3 - n4

        x1 = x[:, :n1].copy() * (5.0 / 100)
        x2 = x[:, n1:n1 + n2].copy() * (5.0 / 100)
        x3 = x[:, n1 + n2:n1 + n2 + n3].copy() * (5.0 / 100)
        x4 = x[:, n1 + n2 + n3:n1 + n2 + n3 + n4].copy() * (1000.0 / 100)
        x5 = x[:, n1 + n2 + n3 + n4:].copy()

        # Katsuura - 修正
        index = 32
        prod1 = np.zeros(x.shape[0])  # ✓ 在外层循环外初始化
        result = np.ones(x.shape[0])
        for i in range(n1):
            for j in range(1, index + 1):
                prod1 += np.abs(2 ** j * x1[:, i] - np.round(2 ** j * x1[:, i])) / (2 ** j)
            result *= (1 + i * prod1) ** (10 / (n1 ** 1.2))  # ✓ 使用 i 而不是 (i+1)

        result = (10 / (n1 ** 1.2)) * (result - 1)

        # HappyCat
        x2 = x2 - 1
        sum1 = np.sum(x2 ** 2, axis=1)
        sum2 = np.sum(x2, axis=1)
        result += np.abs(sum1 - n2) ** 0.25 + (0.5 * sum1 + sum2) / n2 + 0.5

        # ExGriewRosen
        x3[:, 0] = x3[:, 0] + 1
        for i in range(n3 - 1):
            x3[:, i + 1] = x3[:, i + 1] + 1
            t = 100 * ((x3[:, i] ** 2 - x3[:, i + 1]) ** 2) + (x3[:, i] - 1) ** 2
            result += (t ** 2) / 4000 - np.cos(t) + 1

        t = 100 * ((x3[:, n3 - 1] ** 2 - x3[:, 0]) ** 2) + (x3[:, n3 - 1] - 1) ** 2
        result += (t ** 2) / 4000 - np.cos(t) + 1

        # Modified Schwefel
        result += CEC21MTMOFunctions._modified_schwefel(x4, n4)

        # Ackley
        sum1 = np.sum(x5 ** 2, axis=1) / n5
        sum2 = np.sum(np.cos(2 * np.pi * x5), axis=1) / n5
        result += (-20) * np.exp(-0.2 * np.sqrt(sum1)) - np.exp(sum2) + 20 + np.e

        return result

    @staticmethod
    def _modified_schwefel(x, n):
        """
        Modified Schwefel function helper.

        Parameters
        ----------
        x : np.ndarray
            Input array of shape (n_samples, n_dims).
        n : int
            Number of dimensions.

        Returns
        -------
        np.ndarray
            Function values of shape (n_samples,).
        """
        prod1 = np.zeros(x.shape[0])
        for i in range(x.shape[1]):
            z = x[:, i] + 4.209687462275036e+002

            gz = np.zeros_like(z)
            mask1 = np.abs(z) <= 500
            mask2 = z > 500
            mask3 = ~(mask1 | mask2)

            # Case 1: |z| <= 500
            gz[mask1] = z[mask1] * np.sin(np.abs(z[mask1]) ** 0.5)

            # Case 2: z > 500
            temp = 500 - np.mod(z[mask2], 500)
            gz[mask2] = temp * np.sin(np.abs(temp) ** 0.5) - ((z[mask2] - 500) ** 2) / (10000 * n)

            # Case 3: z < -500
            temp = np.mod(np.abs(z[mask3]), 500) - 500
            gz[mask3] = temp * np.sin(np.abs(500 - np.mod(np.abs(z[mask3]), 500)) ** 0.5) - ((z[mask3] + 500) ** 2) / (
                        10000 * n)

            prod1 += gz

        return 418.9829 * n - prod1



[docs] class CEC21MTMO: """ Implementation of the CEC 2021 Competition on Evolutionary Multi-Task Multi-Objective Optimization (MTMO) benchmark problems. These problems consist of two multi-objective optimization tasks (MO-tasks) with shared variables, designed to test knowledge transfer in the presence of multiple conflicting objectives. All tasks are minimization problems. Notes ----- Fixed parameters by benchmark definition: - K=2 (number of tasks) - D=50, M=2 for all problems Attributes ---------- data_dir : str The directory path for problem data files. funcs : CEC21MTMOFunctions Instance of the functions helper class. """ problem_information = { 'n_cases': 10, 'n_tasks': '2', 'n_dims': '50', 'n_objs': '2', 'n_cons': '0', 'type': 'synthetic', } def __init__(self): self.data_dir = 'data_cec21mtmo' self.funcs = CEC21MTMOFunctions()
[docs] def P1(self) -> MTOP: """ Generates Problem 1: **T1 (MMDTLZ, F17) vs T2 (MMZDT, F17)**. Both tasks are 2-objective, 50-dimensional. - T1: MMDTLZ-type with hybrid function F17 (Modified Schwefel + Rastrigin + Elliptic). - T2: MMZDT-type with linear f1, hybrid function F17, and concave h. - Relationship: Different task types but same g-function complexity. Returns ------- MTOP A Multi-Task Multi-Objective Optimization Problem instance. """ dim = 50 # Load rotation matrices and shift vectors data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_1/matrix_1') rotation1 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_1/bias_1') shift1 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_1/matrix_2') rotation2 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_1/bias_2') shift2 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) def T1(x): """Task 1: MMDTLZ with F17 g-function""" x = np.atleast_2d(x) # Evaluate g-function (F17) g = self.funcs.eval_F17(x[:, 1:], shift1, rotation1) # MMDTLZ objectives f1 = (1 + g) * np.cos(x[:, 0] * 0.5 * np.pi) f2 = (1 + g) * np.sin(x[:, 0] * 0.5 * np.pi) return np.vstack([f1, f2]).T def T2(x): """Task 2: MMZDT with linear f1, F17 g-function, and concave h""" x = np.atleast_2d(x) # Evaluate f1 (linear) f1 = self.funcs.eval_f1_linear(x[:, 0:1]) # Evaluate g-function (F17) g = self.funcs.eval_F17(x[:, 1:], shift2, rotation2) g = g + 1 # Concave h-function f2 = g * (1 - (f1 / g) ** 2) return np.vstack([f1, f2]).T # Bounds lb = np.concatenate([[0.0], -100.0 * np.ones(49)]) ub = np.concatenate([[1.0], 100.0 * np.ones(49)]) problem = MTOP() problem.add_task(T1, dim=dim, lower_bound=lb, upper_bound=ub) problem.add_task(T2, dim=dim, lower_bound=lb, upper_bound=ub) return problem
[docs] def P2(self) -> MTOP: """ Generates Problem 2: **T1 (MMDTLZ, F19) vs T2 (MMDTLZ, F19)**. """ dim = 50 # 加载rotation matrices and shift vectors data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_2/matrix_1') rotation1 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_2/bias_1') shift1 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_2/matrix_2') rotation2 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_2/bias_2') shift2 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) def T1(x): # 这是任务0,应该用 rotation1, shift1 """Task 0: MMDTLZ with F19 g-function""" x = np.atleast_2d(x) # Evaluate g-function (F19) g = self.funcs.eval_F19(x[:, 1:], shift1, rotation1) # MMDTLZ objectives f1 = (1 + g) * np.cos(x[:, 0] * 0.5 * np.pi) f2 = (1 + g) * np.sin(x[:, 0] * 0.5 * np.pi) return np.vstack([f1, f2]).T def T2(x): # 这是任务1,应该用 rotation2, shift2 """Task 1: MMDTLZ with F19 g-function""" x = np.atleast_2d(x) # Evaluate g-function (F19) g = self.funcs.eval_F19(x[:, 1:], shift2, rotation2) # MMDTLZ objectives f1 = (1 + g) * np.cos(x[:, 0] * 0.5 * np.pi) f2 = (1 + g) * np.sin(x[:, 0] * 0.5 * np.pi) return np.vstack([f1, f2]).T # Bounds lb = np.concatenate([[0.0], -100.0 * np.ones(49)]) ub = np.concatenate([[1.0], 100.0 * np.ones(49)]) problem = MTOP() problem.add_task(T1, dim=dim, lower_bound=lb, upper_bound=ub) problem.add_task(T2, dim=dim, lower_bound=lb, upper_bound=ub) return problem
[docs] def P3(self) -> MTOP: """ Generates Problem 3: **T1 (MMDTLZ, F22) vs T2 (MMZDT, F22)**. Both tasks are 2-objective, 50-dimensional. - T1: MMDTLZ-type with hybrid function F22 (Katsuura + HappyCat + ExGriewRosen + Modified Schwefel + Ackley). - T2: MMZDT-type with linear f1, hybrid function F22, and convex h. - Relationship: Different task types but same g-function complexity. Returns ------- MTOP A Multi-Task Multi-Objective Optimization Problem instance. """ dim = 50 # Load rotation matrices and shift vectors data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_3/matrix_1') rotation1 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_3/bias_1') shift1 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_3/matrix_2') rotation2 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_3/bias_2') shift2 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) def T1(x): """Task 1: MMDTLZ with F22 g-function""" x = np.atleast_2d(x) # Evaluate g-function (F22) g = self.funcs.eval_F22(x[:, 1:], shift1, rotation1) # MMDTLZ objectives f1 = (1 + g) * np.cos(x[:, 0] * 0.5 * np.pi) f2 = (1 + g) * np.sin(x[:, 0] * 0.5 * np.pi) return np.vstack([f1, f2]).T def T2(x): """Task 2: MMZDT with linear f1, F22 g-function, and convex h""" x = np.atleast_2d(x) # Evaluate f1 (linear) f1 = self.funcs.eval_f1_linear(x[:, 0:1]) # Evaluate g-function (F22) g = self.funcs.eval_F22(x[:, 1:], shift2, rotation2) g = g + 1 # Convex h-function f2 = g * (1 - np.sqrt(f1 / g)) return np.vstack([f1, f2]).T # Bounds lb = np.concatenate([[0.0], -100.0 * np.ones(49)]) ub = np.concatenate([[1.0], 100.0 * np.ones(49)]) problem = MTOP() problem.add_task(T1, dim=dim, lower_bound=lb, upper_bound=ub) problem.add_task(T2, dim=dim, lower_bound=lb, upper_bound=ub) return problem
[docs] def P4(self) -> MTOP: """ Generates Problem 4: **T1 (MMZDT, F15) vs T2 (MMZDT, F15)**. Both tasks are 2-objective, 50-dimensional. - T1: MMZDT-type with linear f1, hybrid function F15 (ExGriewRosen), and convex h. - T2: MMZDT-type with linear f1, hybrid function F15 (ExGriewRosen), and convex h. - Relationship: Same task type and g-function, both convex. Returns ------- MTOP A Multi-Task Multi-Objective Optimization Problem instance. """ dim = 50 # Load rotation matrices and shift vectors data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_4/matrix_1') rotation1 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_4/bias_1') shift1 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_4/matrix_2') rotation2 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_4/bias_2') shift2 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) def T1(x): """Task 1: MMZDT with linear f1, F15 g-function, and convex h""" x = np.atleast_2d(x) # Evaluate f1 (linear) f1 = self.funcs.eval_f1_linear(x[:, 0:1]) # Evaluate g-function (F15) g = self.funcs.eval_F15(x[:, 1:], shift1, rotation1) g = g + 1 # Convex h-function f2 = g * (1 - np.sqrt(f1 / g)) return np.vstack([f1, f2]).T def T2(x): """Task 2: MMZDT with linear f1, F15 g-function, and convex h""" x = np.atleast_2d(x) # Evaluate f1 (linear) f1 = self.funcs.eval_f1_linear(x[:, 0:1]) # Evaluate g-function (F15) g = self.funcs.eval_F15(x[:, 1:], shift2, rotation2) g = g + 1 # Convex h-function f2 = g * (1 - np.sqrt(f1 / g)) return np.vstack([f1, f2]).T # Bounds lb = np.concatenate([[0.0], -100.0 * np.ones(49)]) ub = np.concatenate([[1.0], 100.0 * np.ones(49)]) problem = MTOP() problem.add_task(T1, dim=dim, lower_bound=lb, upper_bound=ub) problem.add_task(T2, dim=dim, lower_bound=lb, upper_bound=ub) return problem
[docs] def P5(self) -> MTOP: """ Generates Problem 5: **T1 (MMDTLZ, F4) vs T2 (MMZDT, F4)**. Both tasks are 2-objective, 50-dimensional. - T1: MMDTLZ-type with hybrid function F4 (Rosenbrock). - T2: MMZDT-type with linear f1, hybrid function F4 (Rosenbrock), and concave h. - Relationship: Different task types but same g-function (Rosenbrock). Returns ------- MTOP A Multi-Task Multi-Objective Optimization Problem instance. """ dim = 50 # Load rotation matrices and shift vectors data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_5/matrix_1') rotation1 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_5/bias_1') shift1 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_5/matrix_2') rotation2 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_5/bias_2') shift2 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) def T1(x): """Task 1: MMDTLZ with F4 g-function""" x = np.atleast_2d(x) # Evaluate g-function (F4 - Rosenbrock) g = self.funcs.eval_F4(x[:, 1:], shift1, rotation1) # MMDTLZ objectives f1 = (1 + g) * np.cos(x[:, 0] * 0.5 * np.pi) f2 = (1 + g) * np.sin(x[:, 0] * 0.5 * np.pi) return np.vstack([f1, f2]).T def T2(x): """Task 2: MMZDT with linear f1, F4 g-function, and concave h""" x = np.atleast_2d(x) # Evaluate f1 (linear) f1 = self.funcs.eval_f1_linear(x[:, 0:1]) # Evaluate g-function (F4 - Rosenbrock) g = self.funcs.eval_F4(x[:, 1:], shift2, rotation2) g = g + 1 # Concave h-function f2 = g * (1 - (f1 / g) ** 2) return np.vstack([f1, f2]).T # Bounds lb = np.concatenate([[0.0], -100.0 * np.ones(49)]) ub = np.concatenate([[1.0], 100.0 * np.ones(49)]) problem = MTOP() problem.add_task(T1, dim=dim, lower_bound=lb, upper_bound=ub) problem.add_task(T2, dim=dim, lower_bound=lb, upper_bound=ub) return problem
[docs] def P6(self) -> MTOP: """ Generates Problem 6: **T1 (MMDTLZ, F9) vs T2 (MMDTLZ, F9)**. Both tasks are 2-objective, 50-dimensional. - T1: MMDTLZ-type with hybrid function F9 (Rastrigin, rotated). - T2: MMDTLZ-type with hybrid function F9 (Rastrigin, rotated). - Relationship: Same task type and g-function. Returns ------- MTOP A Multi-Task Multi-Objective Optimization Problem instance. """ dim = 50 # Load rotation matrices and shift vectors data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_6/matrix_1') rotation1 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_6/bias_1') shift1 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_6/matrix_2') rotation2 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_6/bias_2') shift2 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) def T1(x): """Task 1: MMDTLZ with F9 g-function""" x = np.atleast_2d(x) # Evaluate g-function (F9 - Rastrigin rotated) g = self.funcs.eval_F9(x[:, 1:], shift1, rotation1) # MMDTLZ objectives f1 = (1 + g) * np.cos(x[:, 0] * 0.5 * np.pi) f2 = (1 + g) * np.sin(x[:, 0] * 0.5 * np.pi) return np.vstack([f1, f2]).T def T2(x): """Task 2: MMDTLZ with F9 g-function""" x = np.atleast_2d(x) # Evaluate g-function (F9 - Rastrigin rotated) g = self.funcs.eval_F9(x[:, 1:], shift2, rotation2) # MMDTLZ objectives f1 = (1 + g) * np.cos(x[:, 0] * 0.5 * np.pi) f2 = (1 + g) * np.sin(x[:, 0] * 0.5 * np.pi) return np.vstack([f1, f2]).T # Bounds lb = np.concatenate([[0.0], -100.0 * np.ones(49)]) ub = np.concatenate([[1.0], 100.0 * np.ones(49)]) problem = MTOP() problem.add_task(T1, dim=dim, lower_bound=lb, upper_bound=ub) problem.add_task(T2, dim=dim, lower_bound=lb, upper_bound=ub) return problem
[docs] def P7(self) -> MTOP: """ Generates Problem 7: **T1 (MMDTLZ, F8) vs T2 (MMZDT, F8)**. Both tasks are 2-objective, 50-dimensional. - T1: MMDTLZ-type with hybrid function F8 (Rastrigin, non-rotated). - T2: MMZDT-type with linear f1, hybrid function F8 (Rastrigin, non-rotated), and convex h. - Relationship: Different task types but same g-function. Returns ------- MTOP A Multi-Task Multi-Objective Optimization Problem instance. """ dim = 50 # Load rotation matrices and shift vectors data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_7/matrix_1') rotation1 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_7/bias_1') shift1 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_7/matrix_2') rotation2 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_7/bias_2') shift2 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) def T1(x): """Task 1: MMDTLZ with F8 g-function""" x = np.atleast_2d(x) # Evaluate g-function (F8 - Rastrigin non-rotated) g = self.funcs.eval_F8(x[:, 1:], shift1, rotation1) # MMDTLZ objectives f1 = (1 + g) * np.cos(x[:, 0] * 0.5 * np.pi) f2 = (1 + g) * np.sin(x[:, 0] * 0.5 * np.pi) return np.vstack([f1, f2]).T def T2(x): """Task 2: MMZDT with linear f1, F8 g-function, and convex h""" x = np.atleast_2d(x) # Evaluate f1 (linear) f1 = self.funcs.eval_f1_linear(x[:, 0:1]) # Evaluate g-function (F8 - Rastrigin non-rotated) g = self.funcs.eval_F8(x[:, 1:], shift2, rotation2) g = g + 1 # Convex h-function f2 = g * (1 - np.sqrt(f1 / g)) return np.vstack([f1, f2]).T # Bounds lb = np.concatenate([[0.0], -100.0 * np.ones(49)]) ub = np.concatenate([[1.0], 100.0 * np.ones(49)]) problem = MTOP() problem.add_task(T1, dim=dim, lower_bound=lb, upper_bound=ub) problem.add_task(T2, dim=dim, lower_bound=lb, upper_bound=ub) return problem
[docs] def P8(self) -> MTOP: """ Generates Problem 8: **T1 (MMDTLZ, F18) vs T2 (MMZDT, F20)**. Both tasks are 2-objective, 50-dimensional. - T1: MMDTLZ-type with hybrid function F18 (Cigar + HGBat + Rastrigin). - T2: MMZDT-type with linear f1, hybrid function F20 (HGBat + Discus + ExGriewRosen + Rastrigin), and concave h. - Relationship: Different task types and different g-functions. Returns ------- MTOP A Multi-Task Multi-Objective Optimization Problem instance. """ dim = 50 # Load rotation matrices and shift vectors data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_8/matrix_1') rotation1 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_8/bias_1') shift1 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_8/matrix_2') rotation2 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_8/bias_2') shift2 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) def T1(x): """Task 1: MMDTLZ with F18 g-function""" x = np.atleast_2d(x) # Evaluate g-function (F18) g = self.funcs.eval_F18(x[:, 1:], shift1, rotation1) # MMDTLZ objectives f1 = (1 + g) * np.cos(x[:, 0] * 0.5 * np.pi) f2 = (1 + g) * np.sin(x[:, 0] * 0.5 * np.pi) return np.vstack([f1, f2]).T def T2(x): """Task 2: MMZDT with linear f1, F20 g-function, and concave h""" x = np.atleast_2d(x) # Evaluate f1 (linear) f1 = self.funcs.eval_f1_linear(x[:, 0:1]) # Evaluate g-function (F20) g = self.funcs.eval_F20(x[:, 1:], shift2, rotation2) g = g + 1 # Concave h-function f2 = g * (1 - (f1 / g) ** 2) return np.vstack([f1, f2]).T # Bounds lb = np.concatenate([[0.0], -100.0 * np.ones(49)]) ub = np.concatenate([[1.0], 100.0 * np.ones(49)]) problem = MTOP() problem.add_task(T1, dim=dim, lower_bound=lb, upper_bound=ub) problem.add_task(T2, dim=dim, lower_bound=lb, upper_bound=ub) return problem
[docs] def P9(self) -> MTOP: """ Generates Problem 9: **T1 (MMDTLZ, F11) vs T2 (MMZDT, F18)**. Both tasks are 2-objective, 50-dimensional. - T1: MMDTLZ-type with hybrid function F11 (Modified Schwefel). - T2: MMZDT-type with linear f1, hybrid function F18 (Cigar + HGBat + Rastrigin), and concave h. - Relationship: Different task types and different g-functions. Returns ------- MTOP A Multi-Task Multi-Objective Optimization Problem instance. """ dim = 50 # Load rotation matrices and shift vectors data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_9/matrix_1') rotation1 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_9/bias_1') shift1 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_9/matrix_2') rotation2 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_9/bias_2') shift2 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) def T1(x): """Task 1: MMDTLZ with F11 g-function""" x = np.atleast_2d(x) # Evaluate g-function (F11 - Modified Schwefel) g = self.funcs.eval_F11(x[:, 1:], shift1, rotation1) # MMDTLZ objectives f1 = (1 + g) * np.cos(x[:, 0] * 0.5 * np.pi) f2 = (1 + g) * np.sin(x[:, 0] * 0.5 * np.pi) return np.vstack([f1, f2]).T def T2(x): """Task 2: MMZDT with linear f1, F18 g-function, and concave h""" x = np.atleast_2d(x) # Evaluate f1 (linear) f1 = self.funcs.eval_f1_linear(x[:, 0:1]) # Evaluate g-function (F18) g = self.funcs.eval_F18(x[:, 1:], shift2, rotation2) g = g + 1 # Concave h-function f2 = g * (1 - (f1 / g) ** 2) return np.vstack([f1, f2]).T # Bounds lb = np.concatenate([[0.0], -100.0 * np.ones(49)]) ub = np.concatenate([[1.0], 100.0 * np.ones(49)]) problem = MTOP() problem.add_task(T1, dim=dim, lower_bound=lb, upper_bound=ub) problem.add_task(T2, dim=dim, lower_bound=lb, upper_bound=ub) return problem
[docs] def P10(self) -> MTOP: """ Generates Problem 10: **T1 (MMDTLZ, F15) vs T2 (MMZDT, F17)**. Both tasks are 2-objective, 50-dimensional. - T1: MMDTLZ-type with hybrid function F15 (ExGriewRosen). - T2: MMZDT-type with linear f1, hybrid function F17 (Modified Schwefel + Rastrigin + Elliptic), and concave h. - Relationship: Different task types and different g-functions. Returns ------- MTOP A Multi-Task Multi-Objective Optimization Problem instance. """ dim = 50 # Load rotation matrices and shift vectors data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_10/matrix_1') rotation1 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_10/bias_1') shift1 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_10/matrix_2') rotation2 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) data_bytes = pkgutil.get_data('ddmtolab.Problems.MTMO', f'{self.data_dir}/benchmark_10/bias_2') shift2 = np.loadtxt(io.BytesIO(data_bytes), dtype=float) def T1(x): """Task 1: MMDTLZ with F15 g-function""" x = np.atleast_2d(x) # Evaluate g-function (F15 - ExGriewRosen) g = self.funcs.eval_F15(x[:, 1:], shift1, rotation1) # MMDTLZ objectives f1 = (1 + g) * np.cos(x[:, 0] * 0.5 * np.pi) f2 = (1 + g) * np.sin(x[:, 0] * 0.5 * np.pi) return np.vstack([f1, f2]).T def T2(x): """Task 2: MMZDT with linear f1, F17 g-function, and concave h""" x = np.atleast_2d(x) # Evaluate f1 (linear) f1 = self.funcs.eval_f1_linear(x[:, 0:1]) # Evaluate g-function (F17) g = self.funcs.eval_F17(x[:, 1:], shift2, rotation2) g = g + 1 # Concave h-function f2 = g * (1 - (f1 / g) ** 2) return np.vstack([f1, f2]).T # Bounds lb = np.concatenate([[0.0], -100.0 * np.ones(49)]) ub = np.concatenate([[1.0], 100.0 * np.ones(49)]) problem = MTOP() problem.add_task(T1, dim=dim, lower_bound=lb, upper_bound=ub) problem.add_task(T2, dim=dim, lower_bound=lb, upper_bound=ub) return problem
# --- True Pareto Front (PF) Functions --- def _circle_PF(N, M=2) -> np.ndarray: """ Quarter circle arc PF: unit circle in first quadrant. Used for MMDTLZ tasks. """ theta = np.linspace(0, np.pi / 2, N) f1 = np.cos(theta) f2 = np.sin(theta) return np.column_stack([f1, f2]) def _convex_PF(N, M=2) -> np.ndarray: """ Convex PF: f_2 = 1 - sqrt(f_1). Used for MMZDT tasks with convex h-function. """ f1 = np.linspace(0, 1, N) f2 = 1 - np.sqrt(f1) return np.column_stack([f1, f2]) def _concave_PF(N, M=2) -> np.ndarray: """ Concave PF: f_2 = 1 - f_1^2. Used for MMZDT tasks with concave h-function. """ f1 = np.linspace(0, 1, N) f2 = 1 - f1 ** 2 return np.column_stack([f1, f2]) # Problem-specific PF assignments P1_T1_PF = _circle_PF # MMDTLZ, F17 P1_T2_PF = _circle_PF # MMZDT, F17, concave (special case: circle) P2_T1_PF = _circle_PF # MMDTLZ, F19 P2_T2_PF = _circle_PF # MMDTLZ, F19 P3_T1_PF = _circle_PF # MMDTLZ, F22 P3_T2_PF = _convex_PF # MMZDT, F22, convex P4_T1_PF = _convex_PF # MMZDT, F15, convex P4_T2_PF = _convex_PF # MMZDT, F15, convex P5_T1_PF = _circle_PF # MMDTLZ, F4 P5_T2_PF = _concave_PF # MMZDT, F4, concave P6_T1_PF = _circle_PF # MMDTLZ, F9 P6_T2_PF = _circle_PF # MMDTLZ, F9 P7_T1_PF = _circle_PF # MMDTLZ, F8 P7_T2_PF = _convex_PF # MMZDT, F8, convex P8_T1_PF = _circle_PF # MMDTLZ, F18 P8_T2_PF = _concave_PF # MMZDT, F20, concave P9_T1_PF = _circle_PF # MMDTLZ, F11 P9_T2_PF = _concave_PF # MMZDT, F18, concave P10_T1_PF = _circle_PF # MMDTLZ, F15 P10_T2_PF = _concave_PF # MMZDT, F17, concave SETTINGS = { 'metric': 'IGD', 'n_pf': 1000, 'pf_path': './MOReference', 'P1': {'T1': P1_T1_PF, 'T2': P1_T2_PF}, 'P2': {'T1': P2_T1_PF, 'T2': P2_T2_PF}, 'P3': {'T1': P3_T1_PF, 'T2': P3_T2_PF}, 'P4': {'T1': P4_T1_PF, 'T2': P4_T2_PF}, 'P5': {'T1': P5_T1_PF, 'T2': P5_T2_PF}, 'P6': {'T1': P6_T1_PF, 'T2': P6_T2_PF}, 'P7': {'T1': P7_T1_PF, 'T2': P7_T2_PF}, 'P8': {'T1': P8_T1_PF, 'T2': P8_T2_PF}, 'P9': {'T1': P9_T1_PF, 'T2': P9_T2_PF}, 'P10': {'T1': P10_T1_PF, 'T2': P10_T2_PF}, }