import numpy as np
from ddmtolab.Methods.mtop import MTOP
class LZ09:
"""
LZ09 test function framework for multi-objective optimization.
Parameters
----------
dim : int
Dimension of decision variables.
num_of_objective : int
Number of objectives.
ltype : int
Link function type (21, 22, 23, 24, 25, 26, 32).
dtype : int
Distance function type (1, 2, 3, 4).
ptype : int
Position function type (21, 22, 23, 24 for 2-obj; 31, 32, 33, 34 for 3-obj).
"""
def __init__(self, dim, num_of_objective, ltype, dtype, ptype):
self.dim = dim
self.num_of_objective = num_of_objective
self.ltype = ltype
self.dtype = dtype
self.ptype = ptype
def psfunc(self, x, x1, css):
"""
Position-related link function for 2-objective problems.
Parameters
----------
x : np.ndarray
Subset of decision variables (odd or even indexed).
x1 : np.ndarray
First decision variable.
css : int
Class of index (1 or 2).
Returns
-------
beta : np.ndarray
Transformed variables.
"""
if self.ltype == 21:
if x.shape[1] % 2 == 0:
qq = np.arange(3, self.dim + 1, 2)
else:
qq = np.arange(2, self.dim + 1, 2)
x = 2.0 * (x - 0.5)
beta = x - x1[:, np.newaxis] ** (0.5 * (self.dim + 3.0 * qq - 8) / (self.dim - 2))
elif self.ltype == 22:
if x.shape[1] % 2 == 0:
qq = np.arange(3, self.dim + 1, 2)
else:
qq = np.arange(2, self.dim + 1, 2)
x = 2.0 * (x - 0.5)
theta = np.sin(6 * np.pi * x1[:, np.newaxis] + (np.pi * qq) / self.dim)
beta = x - theta
elif self.ltype == 23:
if x.shape[1] % 2 == 0:
qq = np.arange(3, self.dim + 1, 2)
else:
qq = np.arange(2, self.dim + 1, 2)
theta = 6 * np.pi * x1[:, np.newaxis] + (np.pi * qq) / self.dim
ra = 0.8 * x1[:, np.newaxis]
x = 2.0 * (x - 0.5)
if css == 1:
beta = x - ra * np.cos(theta)
else:
beta = x - ra * np.sin(theta)
elif self.ltype == 24:
if x.shape[1] % 2 == 0:
qq = np.arange(3, self.dim + 1, 2)
else:
qq = np.arange(2, self.dim + 1, 2)
theta = 6 * np.pi * x1[:, np.newaxis] + (np.pi * qq) / self.dim
ra = 0.8 * x1[:, np.newaxis]
x = 2.0 * (x - 0.5)
if css == 1:
beta = x - ra * np.cos(theta / 3)
else:
beta = x - ra * np.sin(theta)
elif self.ltype == 25:
rho = 0.8
phi = np.pi * x1
if x.shape[1] % 2 == 0:
qq = np.arange(3, self.dim + 1, 2)
else:
qq = np.arange(2, self.dim + 1, 2)
theta = 6 * np.pi * x1[:, np.newaxis] + (np.pi * qq) / self.dim
x = 2.0 * (x - 0.5)
if css == 1:
beta = x - rho * np.sin(phi)[:, np.newaxis] * np.sin(theta)
elif css == 2:
beta = x - rho * np.sin(phi)[:, np.newaxis] * np.cos(theta)
else:
beta = x - rho * np.cos(phi)[:, np.newaxis]
elif self.ltype == 26:
if x.shape[1] % 2 == 0:
qq = np.arange(3, self.dim + 1, 2)
else:
qq = np.arange(2, self.dim + 1, 2)
theta = 6 * np.pi * x1[:, np.newaxis] + (np.pi * qq) / self.dim
ra = 0.3 * x1[:, np.newaxis] * (x1[:, np.newaxis] * np.cos(4 * theta) + 2)
x = 2.0 * (x - 0.5)
if css == 1:
beta = x - ra * np.cos(theta)
else:
beta = x - ra * np.sin(theta)
return beta
def psfunc3(self, x, x1, x2, order):
"""
Position-related link function for 3-objective problems.
Parameters
----------
x : np.ndarray
Subset of decision variables (J1, J2, or J3).
x1 : np.ndarray
First decision variable.
x2 : np.ndarray
Second decision variable.
order : np.ndarray
Indices of x in original decision variables.
Returns
-------
beta : np.ndarray
Transformed variables.
"""
if self.ltype == 32:
theta = 2 * np.pi * x1[:, np.newaxis] + np.pi * order / self.dim
x = 4.0 * (x - 0.5)
beta = x - 2 * x2[:, np.newaxis] * np.sin(theta)
return beta
def alpha_function(self, x):
"""
Shape function (PF shape).
Parameters
----------
x : np.ndarray
Decision variables.
Returns
-------
alpha : np.ndarray
Shape function values for each objective.
"""
alpha = np.zeros((x.shape[0], self.num_of_objective))
if self.num_of_objective == 2:
if self.ptype == 21:
alpha[:, 0] = x[:, 0]
alpha[:, 1] = 1 - np.sqrt(x[:, 0])
elif self.ptype == 22:
alpha[:, 0] = x[:, 0]
alpha[:, 1] = 1 - x[:, 0] ** 2
elif self.ptype == 23:
alpha[:, 0] = x[:, 0]
alpha[:, 1] = 1 - np.sqrt(x[:, 0]) - x[:, 0] * np.sin(10 * x[:, 0] ** 2 * np.pi)
elif self.ptype == 24:
alpha[:, 0] = x[:, 0]
alpha[:, 1] = 1 - x[:, 0] - 0.05 * np.sin(4 * np.pi * x[:, 0])
else: # 3 objectives
if self.ptype == 31:
alpha[:, 0] = np.cos(x[:, 0] * np.pi / 2) * np.cos(x[:, 1] * np.pi / 2)
alpha[:, 1] = np.cos(x[:, 0] * np.pi / 2) * np.sin(x[:, 1] * np.pi / 2)
alpha[:, 2] = np.sin(x[:, 0] * np.pi / 2)
elif self.ptype == 32:
alpha[:, 0] = 1 - np.cos(x[:, 0] * np.pi / 2) * np.cos(x[:, 1] * np.pi / 2)
alpha[:, 1] = 1 - np.cos(x[:, 0] * np.pi / 2) * np.sin(x[:, 1] * np.pi / 2)
alpha[:, 2] = 1 - np.sin(x[:, 0] * np.pi / 2)
elif self.ptype == 33:
alpha[:, 0] = x[:, 0]
alpha[:, 1] = x[:, 1]
alpha[:, 2] = 3 - (np.sin(3 * np.pi * x[:, 0]) + np.sin(3 * np.pi * x[:, 1])) - 2 * (x[:, 0] + x[:, 1])
elif self.ptype == 34:
alpha[:, 0] = x[:, 0] * x[:, 1]
alpha[:, 1] = x[:, 0] * (1 - x[:, 1])
alpha[:, 2] = 1 - x[:, 0]
return alpha
def beta_function(self, odd_even_x):
"""
Distance function.
Parameters
----------
odd_even_x : np.ndarray
Subset of decision variables (odd or even indexed).
Returns
-------
beta : np.ndarray
Distance function values.
"""
dim = odd_even_x.shape[1]
if self.dtype == 1:
beta = np.sum(odd_even_x ** 2, axis=1)
beta = 2 * beta / dim
elif self.dtype == 2:
a = np.sqrt(np.arange(1, dim + 1))
beta = np.sum(odd_even_x ** 2 * a, axis=1)
beta = 2 * beta / dim
elif self.dtype == 3:
beta = np.sum((2 * odd_even_x) ** 2, axis=1) - np.sum(np.cos(4 * np.pi * odd_even_x), axis=1)
beta = beta + dim
beta = 2 * beta / dim
elif self.dtype == 4:
sum1 = np.sum((2 * odd_even_x) ** 2, axis=1)
a = np.sqrt(np.arange(1, dim + 1))
cos_terms = np.cos(10 * np.pi * (2 * odd_even_x) / a)
# MATLAB bug: 按列累乘,取矩阵最后一个元素(标量)
prod_cumsum = np.cumprod(cos_terms, axis=0) # 按列累乘
prod_value = prod_cumsum[-1, -1] # 取最后一个元素(标量)
beta = 2 * (sum1 - 2 * prod_value + 2) / dim # 所有样本用同一个prod值
return beta
def objective_function(self, x):
"""
Evaluate objective functions.
Parameters
----------
x : np.ndarray
Decision variables, shape (n_samples, dim).
Returns
-------
fitness : np.ndarray
Objective values, shape (n_samples, num_of_objective).
"""
x = np.atleast_2d(x)
ltype_table = [21, 22, 23, 24, 26]
if self.num_of_objective == 2:
if self.ltype in ltype_table:
# Extract odd indices (3, 5, 7, ...) - Python uses 0-indexing
J1 = x[:, 2::2] # indices 2, 4, 6, ... (corresponds to 3, 5, 7, ... in MATLAB)
a = self.psfunc(J1, x[:, 0], 1)
# Extract even indices (2, 4, 6, ...) - Python uses 0-indexing
J2 = x[:, 1::2] # indices 1, 3, 5, ... (corresponds to 2, 4, 6, ... in MATLAB)
b = self.psfunc(J2, x[:, 0], 2)
g = self.beta_function(a)
h = self.beta_function(b)
alpha = self.alpha_function(x)
fitness_1 = alpha[:, 0] + h
fitness_2 = alpha[:, 1] + g
fitness = np.column_stack([fitness_1, fitness_2])
else: # ltype == 25
# Split into 3 groups
J1 = x[:, 3::3] # indices 3, 6, 9, ... (corresponds to 4, 7, 10, ... in MATLAB)
a = self.psfunc(J1, x[:, 0], 1)
J2 = x[:, 1::3] # indices 1, 4, 7, ... (corresponds to 2, 5, 8, ... in MATLAB)
b = self.psfunc(J2, x[:, 0], 2)
J3 = x[:, 2::3] # indices 2, 5, 8, ... (corresponds to 3, 6, 9, ... in MATLAB)
c = self.psfunc(J3, x[:, 0], 3)
# Combine: a with odd indices of c, b with even indices of c
a = np.column_stack([a, c[:, 0::2]])
b = np.column_stack([b, c[:, 1::2]])
g = self.beta_function(a)
h = self.beta_function(b)
alpha = self.alpha_function(x)
fitness_1 = alpha[:, 0] + h
fitness_2 = alpha[:, 1] + g
fitness = np.column_stack([fitness_1, fitness_2])
else: # 3 objectives
J1 = x[:, 3::3] # indices 3, 6, 9, ...
J2 = x[:, 4::3] # indices 4, 7, 10, ...
J3 = x[:, 2::3] # indices 2, 5, 8, ...
order1 = np.arange(4, x.shape[1] + 1, 3) # 4, 7, 10, ... (1-indexed for algorithm)
order2 = np.arange(5, x.shape[1] + 1, 3) # 5, 8, 11, ...
order3 = np.arange(3, x.shape[1] + 1, 3) # 3, 6, 9, ...
a = self.psfunc3(J1, x[:, 0], x[:, 1], order1)
b = self.psfunc3(J2, x[:, 0], x[:, 1], order2)
c = self.psfunc3(J3, x[:, 0], x[:, 1], order3)
g = self.beta_function(a)
h = self.beta_function(b)
e = self.beta_function(c)
alpha = self.alpha_function(x)
fitness_1 = alpha[:, 0] + g
fitness_2 = alpha[:, 1] + h
fitness_3 = alpha[:, 2] + e
fitness = np.column_stack([fitness_1, fitness_2, fitness_3])
return fitness
[docs]
class CEC19MTMO:
"""
Implementation of the CEC 2019 Competition on Evolutionary Multi-Task Multi-Objective
Optimization (MTMO) benchmark problems.
These problems are based on the LZ09 test suite and consist of multiple tasks
with different configurations designed to test knowledge transfer in multi-objective
optimization scenarios.
Notes
-----
Fixed parameters by benchmark definition:
- K=2 (number of tasks)
- D and M vary by problem (see individual method docstrings)
"""
problem_information = {
'n_cases': 10,
'n_tasks': '2',
'n_dims': '50',
'n_objs': '2',
'n_cons': '0',
'type': 'synthetic',
}
def __init__(self):
pass
[docs]
def P1(self) -> MTOP:
"""
Generates Problem P1 (CPLX1): **T1 (LZ09_F1) vs T2 (LZ09_F2)**.
Both tasks are 2-objective, 10-dimensional.
- T1: LZ09_F1 with ptype=21, dtype=1, ltype=21
- T2: LZ09_F2 with ptype=21, dtype=1, ltype=22
- Relationship: Same PF shape (ptype=21), different link functions
Returns
-------
MTOP
A Multi-Task Multi-Objective Optimization Problem instance.
"""
dim = 10
num_obj = 2
# Task 1: LZ09_F1
lz09_f1 = LZ09(dim=dim, num_of_objective=num_obj, ltype=21, dtype=1, ptype=21)
def T1(x):
return lz09_f1.objective_function(x)
# Task 2: LZ09_F2
lz09_f2 = LZ09(dim=dim, num_of_objective=num_obj, ltype=22, dtype=1, ptype=21)
def T2(x):
return lz09_f2.objective_function(x)
lb = -100.0 * np.ones(dim)
ub = 100.0 * np.ones(dim)
lb[0] = 0.0
ub[0] = 1.0
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 P2 (CPLX2): **T1 (LZ09_F1) vs T2 (LZ09_F7)**.
Both tasks are 2-objective, 10-dimensional.
- T1: LZ09_F1 with ptype=21, dtype=1, ltype=21
- T2: LZ09_F7 with ptype=21, dtype=3, ltype=21 # 修正:dtype=3
- Relationship: Same PF shape (ptype=21), different distance functions
Returns
-------
MTOP
A Multi-Task Multi-Objective Optimization Problem instance.
"""
dim = 10
num_obj = 2
# Task 1: LZ09_F1
lz09_f1 = LZ09(dim=dim, num_of_objective=num_obj, ltype=21, dtype=1, ptype=21)
def T1(x):
return lz09_f1.objective_function(x)
# Task 2: LZ09_F7
lz09_f7 = LZ09(dim=dim, num_of_objective=num_obj, ltype=21, dtype=3, ptype=21) # 修正
def T2(x):
return lz09_f7.objective_function(x)
lb = -5.0 * np.ones(dim)
ub = 5.0 * np.ones(dim)
lb[0] = 0.0
ub[0] = 1.0
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 P3 (CPLX3): **T1 (LZ09_F2) vs T2 (LZ09_F4)**.
Both tasks are 2-objective, 30-dimensional.
- T1: LZ09_F2 with ptype=21, dtype=1, ltype=22
- T2: LZ09_F4 with ptype=21, dtype=1, ltype=24
- Relationship: Same PF shape (ptype=21), different link functions and search spaces
Returns
-------
MTOP
A Multi-Task Multi-Objective Optimization Problem instance.
"""
num_obj = 2
# Task 1: LZ09_F2, 30-dimensional
dim1 = 30
lz09_f2 = LZ09(dim=dim1, num_of_objective=num_obj, ltype=22, dtype=1, ptype=21)
def T1(x):
return lz09_f2.objective_function(x)
lb1 = -2.0 * np.ones(dim1)
ub1 = 2.0 * np.ones(dim1)
lb1[0] = 0.0
ub1[0] = 1.0
# Task 2: LZ09_F4, 30-dimensional
dim2 = 30
lz09_f4 = LZ09(dim=dim2, num_of_objective=num_obj, ltype=24, dtype=1, ptype=21)
def T2(x):
return lz09_f4.objective_function(x)
lb2 = -1.0 * np.ones(dim2)
ub2 = 1.0 * np.ones(dim2)
lb2[0] = 0.0
ub2[0] = 1.0
problem = MTOP()
problem.add_task(T1, dim=dim1, lower_bound=lb1, upper_bound=ub1)
problem.add_task(T2, dim=dim2, lower_bound=lb2, upper_bound=ub2)
return problem
[docs]
def P4(self) -> MTOP:
"""
Generates Problem P4 (CPLX4): **T1 (LZ09_F2) vs T2 (LZ09_F9)**.
Both tasks are 2-objective, 30-dimensional.
- T1: LZ09_F2 with ptype=21, dtype=1, ltype=22
- T2: LZ09_F9 with ptype=22, dtype=1, ltype=22
- Relationship: Different PF shapes (ptype=21 vs ptype=22), same link function
Returns
-------
MTOP
A Multi-Task Multi-Objective Optimization Problem instance.
"""
dim = 30
num_obj = 2
# Task 1: LZ09_F2
lz09_f2 = LZ09(dim=dim, num_of_objective=num_obj, ltype=22, dtype=1, ptype=21)
def T1(x):
return lz09_f2.objective_function(x)
# Task 2: LZ09_F9
lz09_f9 = LZ09(dim=dim, num_of_objective=num_obj, ltype=22, dtype=1, ptype=22)
def T2(x):
return lz09_f9.objective_function(x)
lb = -100.0 * np.ones(dim)
ub = 100.0 * np.ones(dim)
lb[0] = 0.0
ub[0] = 1.0
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 P5 (CPLX5): **T1 (LZ09_F3, 2-obj) vs T2 (LZ09_F6, 3-obj)**.
Tasks have different objectives and dimensions.
- T1: LZ09_F3, 2-objective, 30-dimensional, ptype=21, dtype=1, ltype=23
- T2: LZ09_F6, 3-objective, 10-dimensional, ptype=31, dtype=1, ltype=32
- Relationship: Different number of objectives and dimensions
Returns
-------
MTOP
A Multi-Task Multi-Objective Optimization Problem instance.
"""
# Task 1: LZ09_F3, 2-objective, 30-dimensional
dim1 = 30
num_obj1 = 2
lz09_f3 = LZ09(dim=dim1, num_of_objective=num_obj1, ltype=23, dtype=1, ptype=21)
def T1(x):
return lz09_f3.objective_function(x)
lb1 = np.zeros(dim1)
ub1 = np.ones(dim1)
# Task 2: LZ09_F6, 3-objective, 10-dimensional
dim2 = 10
num_obj2 = 3
lz09_f6 = LZ09(dim=dim2, num_of_objective=num_obj2, ltype=32, dtype=1, ptype=31)
def T2(x):
return lz09_f6.objective_function(x)
lb2 = np.zeros(dim2)
ub2 = np.ones(dim2)
problem = MTOP()
problem.add_task(T1, dim=dim1, lower_bound=lb1, upper_bound=ub1)
problem.add_task(T2, dim=dim2, lower_bound=lb2, upper_bound=ub2)
return problem
[docs]
def P6(self) -> MTOP:
"""
Generates Problem P6 (CPLX6): **T1 (LZ09_F3) vs T2 (LZ09_F9)**.
Both tasks are 2-objective, 30-dimensional.
- T1: LZ09_F3 with ptype=21, dtype=1, ltype=23
- T2: LZ09_F9 with ptype=22, dtype=1, ltype=22
- Relationship: Different PF shapes and search spaces
Returns
-------
MTOP
A Multi-Task Multi-Objective Optimization Problem instance.
"""
dim = 30
num_obj = 2
# Task 1: LZ09_F3
lz09_f3 = LZ09(dim=dim, num_of_objective=num_obj, ltype=23, dtype=1, ptype=21)
def T1(x):
return lz09_f3.objective_function(x)
lb1 = -50.0 * np.ones(dim)
ub1 = 50.0 * np.ones(dim)
lb1[0] = 0.0
ub1[0] = 1.0
# Task 2: LZ09_F9
lz09_f9 = LZ09(dim=dim, num_of_objective=num_obj, ltype=22, dtype=1, ptype=22)
def T2(x):
return lz09_f9.objective_function(x)
lb2 = -100.0 * np.ones(dim)
ub2 = 100.0 * np.ones(dim)
lb2[0] = 0.0
ub2[0] = 1.0
problem = MTOP()
problem.add_task(T1, dim=dim, lower_bound=lb1, upper_bound=ub1)
problem.add_task(T2, dim=dim, lower_bound=lb2, upper_bound=ub2)
return problem
[docs]
def P7(self) -> MTOP:
"""
Generates Problem P7 (CPLX7): **T1 (LZ09_F4) vs T2 (LZ09_F5)**.
Both tasks are 2-objective, 30-dimensional.
- T1: LZ09_F4 with ptype=21, dtype=1, ltype=24
- T2: LZ09_F5 with ptype=21, dtype=1, ltype=26
- Relationship: Same PF shape (ptype=21), different link functions
Returns
-------
MTOP
A Multi-Task Multi-Objective Optimization Problem instance.
"""
dim = 30
num_obj = 2
# Task 1: LZ09_F4
lz09_f4 = LZ09(dim=dim, num_of_objective=num_obj, ltype=24, dtype=1, ptype=21)
def T1(x):
return lz09_f4.objective_function(x)
# Task 2: LZ09_F5
lz09_f5 = LZ09(dim=dim, num_of_objective=num_obj, ltype=26, dtype=1, ptype=21)
def T2(x):
return lz09_f5.objective_function(x)
lb = -80.0 * np.ones(dim)
ub = 80.0 * np.ones(dim)
lb[0] = 0.0
ub[0] = 1.0
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 P8 (CPLX8): **T1 (LZ09_F5) vs T2 (LZ09_F7)**.
Both tasks are 2-objective with different dimensions.
- T1: LZ09_F5, 30-dimensional, ptype=21, dtype=1, ltype=26
- T2: LZ09_F7, 10-dimensional, ptype=21, dtype=3, ltype=21
- Relationship: Same PF shape (ptype=21), different dimensions and link functions
- Note: x1 and x2 both in [0,1] for both tasks
Returns
-------
MTOP
A Multi-Task Multi-Objective Optimization Problem instance.
"""
num_obj = 2
# Task 1: LZ09_F5, 30-dimensional
dim1 = 30
lz09_f5 = LZ09(dim=dim1, num_of_objective=num_obj, ltype=26, dtype=1, ptype=21)
def T1(x):
return lz09_f5.objective_function(x)
lb1 = -20.0 * np.ones(dim1)
ub1 = 20.0 * np.ones(dim1)
lb1[0:2] = 0.0 # x1 and x2 in [0,1]
ub1[0:2] = 1.0
# Task 2: LZ09_F7, 10-dimensional
dim2 = 10
lz09_f7 = LZ09(dim=dim2, num_of_objective=num_obj, ltype=21, dtype=3, ptype=21)
def T2(x):
return lz09_f7.objective_function(x)
lb2 = -20.0 * np.ones(dim2)
ub2 = 20.0 * np.ones(dim2)
lb2[0:2] = 0.0 # x1 and x2 in [0,1]
ub2[0:2] = 1.0
problem = MTOP()
problem.add_task(T1, dim=dim1, lower_bound=lb1, upper_bound=ub1)
problem.add_task(T2, dim=dim2, lower_bound=lb2, upper_bound=ub2)
return problem
[docs]
def P9(self) -> MTOP:
"""
Generates Problem P9 (CPLX9): **T1 (LZ09_F6, 3-obj) vs T2 (LZ09_F9, 2-obj)**.
Tasks have different objectives and dimensions.
- T1: LZ09_F6, 3-objective, 10-dimensional, ptype=31, dtype=1, ltype=32
- T2: LZ09_F9, 2-objective, 30-dimensional, ptype=22, dtype=1, ltype=22
- Relationship: Different number of objectives, dimensions, and PF shapes
- Note: x1 and x2 both in [0,1] for both tasks
Returns
-------
MTOP
A Multi-Task Multi-Objective Optimization Problem instance.
"""
# Task 1: LZ09_F6, 3-objective, 10-dimensional
dim1 = 10
num_obj1 = 3
lz09_f6 = LZ09(dim=dim1, num_of_objective=num_obj1, ltype=32, dtype=1, ptype=31)
def T1(x):
return lz09_f6.objective_function(x)
lb1 = -50.0 * np.ones(dim1)
ub1 = 50.0 * np.ones(dim1)
lb1[0:2] = 0.0 # x1 and x2 in [0,1]
ub1[0:2] = 1.0
# Task 2: LZ09_F9, 2-objective, 30-dimensional
dim2 = 30
num_obj2 = 2
lz09_f9 = LZ09(dim=dim2, num_of_objective=num_obj2, ltype=22, dtype=1, ptype=22)
def T2(x):
return lz09_f9.objective_function(x)
lb2 = -100.0 * np.ones(dim2)
ub2 = 100.0 * np.ones(dim2)
lb2[0:2] = 0.0 # x1 and x2 in [0,1]
ub2[0:2] = 1.0
problem = MTOP()
problem.add_task(T1, dim=dim1, lower_bound=lb1, upper_bound=ub1)
problem.add_task(T2, dim=dim2, lower_bound=lb2, upper_bound=ub2)
return problem
[docs]
def P10(self) -> MTOP:
"""
Generates Problem P10 (CPLX10): **T1 (LZ09_F7) vs T2 (LZ09_F8)**.
Both tasks are 2-objective, 10-dimensional.
- T1: LZ09_F7 with ptype=21, dtype=3, ltype=21
- T2: LZ09_F8 with ptype=21, dtype=4, ltype=21
- Relationship: Same PF shape (ptype=21), different distance functions and search spaces
Returns
-------
MTOP
A Multi-Task Multi-Objective Optimization Problem instance.
"""
dim = 10
num_obj = 2
# Task 1: LZ09_F7
lz09_f7 = LZ09(dim=dim, num_of_objective=num_obj, ltype=21, dtype=3, ptype=21)
def T1(x):
return lz09_f7.objective_function(x)
lb1 = np.zeros(dim)
ub1 = np.ones(dim)
# Task 2: LZ09_F8
lz09_f8 = LZ09(dim=dim, num_of_objective=num_obj, ltype=21, dtype=4, ptype=21)
def T2(x):
return lz09_f8.objective_function(x)
lb2 = -10.0 * np.ones(dim)
ub2 = 10.0 * np.ones(dim)
lb2[0] = 0.0
ub2[0] = 1.0
problem = MTOP()
problem.add_task(T1, dim=dim, lower_bound=lb1, upper_bound=ub1)
problem.add_task(T2, dim=dim, lower_bound=lb2, upper_bound=ub2)
return problem
# --- True Pareto Front (PF) Functions ---
def P1_T1_PF(N, M=2) -> np.ndarray:
"""Computes the True Pareto Front (PF) for P1, Task 1."""
f1 = np.linspace(0, 1, N)
f2 = 1 - np.sqrt(f1)
return np.column_stack([f1, f2])
def P1_T2_PF(N, M=2) -> np.ndarray:
"""Computes the True Pareto Front (PF) for P1, Task 2."""
f1 = np.linspace(0, 1, N)
f2 = 1 - np.sqrt(f1)
return np.column_stack([f1, f2])
def P2_T1_PF(N, M=2) -> np.ndarray:
"""Computes the True Pareto Front (PF) for P2, Task 1."""
f1 = np.linspace(0, 1, N)
f2 = 1 - np.sqrt(f1)
return np.column_stack([f1, f2])
def P2_T2_PF(N, M=2) -> np.ndarray:
"""Computes the True Pareto Front (PF) for P2, Task 2."""
f1 = np.linspace(0, 1, N)
f2 = 1 - np.sqrt(f1)
return np.column_stack([f1, f2])
def P3_T1_PF(N, M=2) -> np.ndarray:
"""Computes the True Pareto Front (PF) for P3, Task 1."""
f1 = np.linspace(0, 1, N)
f2 = 1 - np.sqrt(f1)
return np.column_stack([f1, f2])
def P3_T2_PF(N, M=2) -> np.ndarray:
"""Computes the True Pareto Front (PF) for P3, Task 2."""
f1 = np.linspace(0, 1, N)
f2 = 1 - np.sqrt(f1)
return np.column_stack([f1, f2])
def P4_T1_PF(N, M=2) -> np.ndarray:
"""
Computes the True Pareto Front (PF) for P4, Task 1.
ptype=21: f2 = 1 - sqrt(f1)
"""
f1 = np.linspace(0, 1, N)
f2 = 1 - np.sqrt(f1)
return np.column_stack([f1, f2])
def P4_T2_PF(N, M=2) -> np.ndarray:
"""
Computes the True Pareto Front (PF) for P4, Task 2.
ptype=22: f2 = 1 - f1^2
"""
f1 = np.linspace(0, 1, N)
f2 = 1 - f1 ** 2
return np.column_stack([f1, f2])
def P5_T1_PF(N, M=2) -> np.ndarray:
"""
Computes the True Pareto Front (PF) for P5, Task 1.
ptype=21: f2 = 1 - sqrt(f1)
"""
f1 = np.linspace(0, 1, N)
f2 = 1 - np.sqrt(f1)
return np.column_stack([f1, f2])
def P5_T2_PF(N, M=3) -> np.ndarray:
"""
Computes the True Pareto Front (PF) for P5, Task 2.
ptype=31: Unit sphere surface in 3D
"""
# Generate uniform points on unit sphere
n_sqrt = int(np.sqrt(N))
theta = np.linspace(0, np.pi / 2, n_sqrt)
phi = np.linspace(0, np.pi / 2, n_sqrt)
points = []
for t in theta:
for p in phi:
# Spherical coordinates to Cartesian
f1 = np.cos(t) * np.cos(p)
f2 = np.cos(t) * np.sin(p)
f3 = np.sin(t)
points.append([f1, f2, f3])
pf = np.array(points)
# Normalize to ensure on unit sphere
pf = pf / np.sqrt(np.sum(pf ** 2, axis=1, keepdims=True))
return pf
def P6_T1_PF(N, M=2) -> np.ndarray:
"""
Computes the True Pareto Front (PF) for P6, Task 1.
ptype=21: f2 = 1 - sqrt(f1)
"""
f1 = np.linspace(0, 1, N)
f2 = 1 - np.sqrt(f1)
return np.column_stack([f1, f2])
def P6_T2_PF(N, M=2) -> np.ndarray:
"""
Computes the True Pareto Front (PF) for P6, Task 2.
ptype=22: f2 = 1 - f1^2
"""
f1 = np.linspace(0, 1, N)
f2 = 1 - f1 ** 2
return np.column_stack([f1, f2])
def P7_T1_PF(N, M=2) -> np.ndarray:
"""
Computes the True Pareto Front (PF) for P7, Task 1.
ptype=21: f2 = 1 - sqrt(f1)
"""
f1 = np.linspace(0, 1, N)
f2 = 1 - np.sqrt(f1)
return np.column_stack([f1, f2])
def P7_T2_PF(N, M=2) -> np.ndarray:
"""
Computes the True Pareto Front (PF) for P7, Task 2.
ptype=21: f2 = 1 - sqrt(f1)
"""
f1 = np.linspace(0, 1, N)
f2 = 1 - np.sqrt(f1)
return np.column_stack([f1, f2])
def P8_T1_PF(N, M=2) -> np.ndarray:
"""
Computes the True Pareto Front (PF) for P8, Task 1.
ptype=21: f2 = 1 - sqrt(f1)
"""
f1 = np.linspace(0, 1, N)
f2 = 1 - np.sqrt(f1)
return np.column_stack([f1, f2])
def P8_T2_PF(N, M=2) -> np.ndarray:
"""
Computes the True Pareto Front (PF) for P8, Task 2.
ptype=21: f2 = 1 - sqrt(f1)
"""
f1 = np.linspace(0, 1, N)
f2 = 1 - np.sqrt(f1)
return np.column_stack([f1, f2])
def P9_T1_PF(N, M=3) -> np.ndarray:
"""
Computes the True Pareto Front (PF) for P9, Task 1.
ptype=31: Unit sphere surface in 3D
"""
# Generate uniform points on unit sphere
n_sqrt = int(np.sqrt(N))
theta = np.linspace(0, np.pi / 2, n_sqrt)
phi = np.linspace(0, np.pi / 2, n_sqrt)
points = []
for t in theta:
for p in phi:
# Spherical coordinates to Cartesian
f1 = np.cos(t) * np.cos(p)
f2 = np.cos(t) * np.sin(p)
f3 = np.sin(t)
points.append([f1, f2, f3])
pf = np.array(points)
# Normalize to ensure on unit sphere
pf = pf / np.sqrt(np.sum(pf ** 2, axis=1, keepdims=True))
return pf
def P9_T2_PF(N, M=2) -> np.ndarray:
"""
Computes the True Pareto Front (PF) for P9, Task 2.
ptype=22: f2 = 1 - f1^2
"""
f1 = np.linspace(0, 1, N)
f2 = 1 - f1 ** 2
return np.column_stack([f1, f2])
def P10_T1_PF(N, M=2) -> np.ndarray:
"""
Computes the True Pareto Front (PF) for P10, Task 1.
ptype=21: f2 = 1 - sqrt(f1)
"""
f1 = np.linspace(0, 1, N)
f2 = 1 - np.sqrt(f1)
return np.column_stack([f1, f2])
def P10_T2_PF(N, M=2) -> np.ndarray:
"""
Computes the True Pareto Front (PF) for P10, Task 2.
ptype=21: f2 = 1 - sqrt(f1)
"""
f1 = np.linspace(0, 1, N)
f2 = 1 - np.sqrt(f1)
return np.column_stack([f1, f2])
SETTINGS = {
'metric': 'IGD',
'n_pf': 10000,
'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},
}