Source code for ddmtolab.Problems.STMO.CF

import numpy as np
from ddmtolab.Methods.mtop import MTOP
from ddmtolab.Methods.Algo_Methods.uniform_point import uniform_point


[docs] class CF: """ Implementation of the CF test suite (CEC 2009) for constrained multi-objective optimization. The CF test problems (CF1 to CF10) are standard constrained multi-objective optimization benchmarks from the CEC 2009 competition. References ---------- [1] Q. Zhang, A. Zhou, S. Zhao, P. N. Suganthan, W. Liu, and S. Tiwari. "Multiobjective optimization test instances for the CEC 2009 special session and competition." University of Essex, Colchester, UK, Tech. Rep. CES-487, 2009. """ problem_information = { 'n_cases': 10, 'n_tasks': '1', 'n_dims': 'D', 'n_objs': '[2, 3]', 'n_cons': '1', 'type': 'synthetic', }
[docs] def CF1(self, M=2, D=None) -> MTOP: """ Generates the **CF1** problem. """ if D is None: D = 10 def T1(x): x = np.atleast_2d(x) N, n_vars = x.shape J1 = np.arange(2, n_vars, 2) J2 = np.arange(1, n_vars, 2) # Exponents for the transformation y1_exp = 0.5 * (1 + 3 * (J1 + 1 - 2) / (D - 2)) y2_exp = 0.5 * (1 + 3 * (J2 + 1 - 2) / (D - 2)) y1 = x[:, J1] - x[:, 0:1] ** y1_exp y2 = x[:, J2] - x[:, 0:1] ** y2_exp obj = np.zeros((N, M)) obj[:, 0] = x[:, 0] + (2 * np.mean(y1 ** 2, axis=1) if J1.size > 0 else 0) obj[:, 1] = 1 - x[:, 0] + (2 * np.mean(y2 ** 2, axis=1) if J2.size > 0 else 0) return obj def C1(x): obj = T1(x) # Constraint: f1 + f2 >= 1 + abs(sin(...)) # Transformed to <= 0 form: 1 + abs(...) - f1 - f2 <= 0 return 1 - obj[:, 0] - obj[:, 1] + np.abs(np.sin(10 * np.pi * (obj[:, 0] - obj[:, 1] + 1))) lb = np.zeros(D) ub = np.ones(D) problem = MTOP() problem.add_task(objective_func=T1, dim=D, constraint_func=C1, lower_bound=lb, upper_bound=ub) return problem
[docs] def CF2(self, M=2, D=None) -> MTOP: """ Generates the **CF2** problem. """ if D is None: D = 10 def T1(x): x = np.atleast_2d(x) N, n_vars = x.shape J1 = np.arange(2, n_vars, 2) J2 = np.arange(1, n_vars, 2) term1 = (x[:, J1] - np.sin(6 * np.pi * x[:, 0:1] + (J1 + 1) * np.pi / n_vars)) ** 2 term2 = (x[:, J2] - np.cos(6 * np.pi * x[:, 0:1] + (J2 + 1) * np.pi / n_vars)) ** 2 obj = np.zeros((N, M)) obj[:, 0] = x[:, 0] + (2 * np.mean(term1, axis=1) if J1.size > 0 else 0) obj[:, 1] = 1 - np.sqrt(x[:, 0]) + (2 * np.mean(term2, axis=1) if J2.size > 0 else 0) return obj def C1(x): obj = T1(x) t = obj[:, 1] + np.sqrt(obj[:, 0]) - np.sin(2 * np.pi * (np.sqrt(obj[:, 0]) - obj[:, 1] + 1)) - 1 # PlatEMO: PopCon = -t / (1 + exp(4*abs(t))) # Returns <= 0 if feasible (t >= 0) return -t / (1 + np.exp(4 * np.abs(t))) lb = np.zeros(D) lb[1:] = -1.0 ub = np.ones(D) problem = MTOP() problem.add_task(objective_func=T1, dim=D, constraint_func=C1, lower_bound=lb, upper_bound=ub) return problem
[docs] def CF3(self, M=2, D=None) -> MTOP: """ Generates the **CF3** problem. """ if D is None: D = 10 def T1(x): x = np.atleast_2d(x) N, n_vars = x.shape J1 = np.arange(2, n_vars, 2) J2 = np.arange(1, n_vars, 2) Y = x - np.sin(6 * np.pi * x[:, 0:1] + (np.arange(n_vars) + 1) * np.pi / n_vars) # For J1 term1 = 4 * np.sum(Y[:, J1] ** 2, axis=1) - 2 * np.prod(np.cos(20 * Y[:, J1] * np.pi / np.sqrt(J1 + 1)), axis=1) + 2 # For J2 term2 = 4 * np.sum(Y[:, J2] ** 2, axis=1) - 2 * np.prod(np.cos(20 * Y[:, J2] * np.pi / np.sqrt(J2 + 1)), axis=1) + 2 obj = np.zeros((N, M)) obj[:, 0] = x[:, 0] + (2 / J1.size * term1 if J1.size > 0 else 0) obj[:, 1] = 1 - x[:, 0] ** 2 + (2 / J2.size * term2 if J2.size > 0 else 0) return obj def C1(x): obj = T1(x) # Constraint: f2 + f1^2 >= 1 + sin(...) return 1 - obj[:, 1] - obj[:, 0] ** 2 + np.sin(2 * np.pi * (obj[:, 0] ** 2 - obj[:, 1] + 1)) lb = np.zeros(D) lb[1:] = -2.0 ub = np.ones(D) ub[1:] = 2.0 problem = MTOP() problem.add_task(objective_func=T1, dim=D, constraint_func=C1, lower_bound=lb, upper_bound=ub) return problem
[docs] def CF4(self, M=2, D=None) -> MTOP: """ Generates the **CF4** problem. """ if D is None: D = 10 def T1(x): x = np.atleast_2d(x) N, n_vars = x.shape J1 = np.arange(2, n_vars, 2) J2 = np.arange(1, n_vars, 2) Y = x - np.sin(6 * np.pi * x[:, 0:1] + (np.arange(n_vars) + 1) * np.pi / n_vars) h = Y ** 2 # Special handling for h[:, 1] (index 1) temp = Y[:, 1] < 1.5 * (1 - np.sqrt(0.5)) h[temp, 1] = np.abs(Y[temp, 1]) h[~temp, 1] = 0.125 + (Y[~temp, 1] - 1) ** 2 obj = np.zeros((N, M)) obj[:, 0] = x[:, 0] + np.sum(h[:, J1], axis=1) obj[:, 1] = 1 - x[:, 0] + np.sum(h[:, J2], axis=1) return obj def C1(x): # PlatEMO: t = x2 - sin(...) - 0.5*x1 + 0.25 t = x[:, 1] - np.sin(6 * np.pi * x[:, 0] + 2 * np.pi / x.shape[1]) - 0.5 * x[:, 0] + 0.25 return -t / (1 + np.exp(4 * np.abs(t))) lb = np.zeros(D) lb[1:] = -2.0 ub = np.ones(D) ub[1:] = 2.0 problem = MTOP() problem.add_task(objective_func=T1, dim=D, constraint_func=C1, lower_bound=lb, upper_bound=ub) return problem
[docs] def CF5(self, M=2, D=None) -> MTOP: """ Generates the **CF5** problem. """ if D is None: D = 10 def T1(x): x = np.atleast_2d(x) N, n_vars = x.shape J1 = np.arange(2, n_vars, 2) J2 = np.arange(1, n_vars, 2) Y = np.zeros_like(x) Y[:, J1] = x[:, J1] - 0.8 * x[:, 0:1] * np.cos(6 * np.pi * x[:, 0:1] + (J1 + 1) * np.pi / n_vars) Y[:, J2] = x[:, J2] - 0.8 * x[:, 0:1] * np.sin(6 * np.pi * x[:, 0:1] + (J2 + 1) * np.pi / n_vars) h = 2 * Y ** 2 - np.cos(4 * np.pi * Y) + 1 # Special handling for Y[:, 1] temp = Y[:, 1] < 1.5 * (1 - np.sqrt(0.5)) h[temp, 1] = np.abs(Y[temp, 1]) h[~temp, 1] = 0.125 + (Y[~temp, 1] - 1) ** 2 obj = np.zeros((N, M)) obj[:, 0] = x[:, 0] + np.sum(h[:, J1], axis=1) obj[:, 1] = 1 - x[:, 0] + np.sum(h[:, J2], axis=1) return obj def C1(x): # PlatEMO: -x2 + 0.8*x1*sin(...) + 0.5*x1 - 0.25 return -x[:, 1] + 0.8 * x[:, 0] * np.sin(6 * np.pi * x[:, 0] + 2 * np.pi / x.shape[1]) + 0.5 * x[ :, 0] - 0.25 lb = np.zeros(D) lb[1:] = -2.0 ub = np.ones(D) ub[1:] = 2.0 problem = MTOP() problem.add_task(objective_func=T1, dim=D, constraint_func=C1, lower_bound=lb, upper_bound=ub) return problem
[docs] def CF6(self, M=2, D=None) -> MTOP: """ Generates the **CF6** problem. """ if D is None: D = 10 def T1(x): x = np.atleast_2d(x) N, n_vars = x.shape J1 = np.arange(2, n_vars, 2) J2 = np.arange(1, n_vars, 2) Y = np.zeros_like(x) Y[:, J1] = x[:, J1] - 0.8 * x[:, 0:1] * np.cos(6 * np.pi * x[:, 0:1] + (J1 + 1) * np.pi / n_vars) Y[:, J2] = x[:, J2] - 0.8 * x[:, 0:1] * np.sin(6 * np.pi * x[:, 0:1] + (J2 + 1) * np.pi / n_vars) obj = np.zeros((N, M)) obj[:, 0] = x[:, 0] + np.sum(Y[:, J1] ** 2, axis=1) obj[:, 1] = (1 - x[:, 0]) ** 2 + np.sum(Y[:, J2] ** 2, axis=1) return obj def C1(x): D = x.shape[1] term1 = 0.5 * (1 - x[:, 0]) - (1 - x[:, 0]) ** 2 term2 = 0.25 * np.sqrt(1 - x[:, 0]) - 0.5 * (1 - x[:, 0]) c1 = -x[:, 1] + 0.8 * x[:, 0] * np.sin(6 * np.pi * x[:, 0] + 2 * np.pi / n_vars) + \ np.sign(term1) * np.sqrt(np.abs(term1)) c2 = -x[:, 3] + 0.8 * x[:, 0] * np.sin(6 * np.pi * x[:, 0] + 4 * np.pi / n_vars) + \ np.sign(term2) * np.sqrt(np.abs(term2)) return np.column_stack([c1, c2]) lb = np.zeros(D) lb[1:] = -2.0 ub = np.ones(D) ub[1:] = 2.0 problem = MTOP() problem.add_task(objective_func=T1, dim=D, constraint_func=C1, lower_bound=lb, upper_bound=ub) return problem
[docs] def CF7(self, M=2, D=None) -> MTOP: """ Generates the **CF7** problem. """ if D is None: D = 10 def T1(x): x = np.atleast_2d(x) N, n_vars = x.shape J1 = np.arange(2, n_vars, 2) J2 = np.arange(1, n_vars, 2) Y = np.zeros_like(x) Y[:, J1] = x[:, J1] - np.cos(6 * np.pi * x[:, 0:1] + (J1 + 1) * np.pi / n_vars) Y[:, J2] = x[:, J2] - np.sin(6 * np.pi * x[:, 0:1] + (J2 + 1) * np.pi / n_vars) h = 2 * Y ** 2 - np.cos(4 * np.pi * Y) + 1 # Special handling for h[:, 1] (index 1) and h[:, 3] (index 3) h[:, 1] = Y[:, 1] ** 2 h[:, 3] = Y[:, 3] ** 2 obj = np.zeros((N, M)) obj[:, 0] = x[:, 0] + np.sum(h[:, J1], axis=1) obj[:, 1] = (1 - x[:, 0]) ** 2 + np.sum(h[:, J2], axis=1) return obj def C1(x): D = x.shape[1] term1 = 0.5 * (1 - x[:, 0]) - (1 - x[:, 0]) ** 2 term2 = 0.25 * np.sqrt(1 - x[:, 0]) - 0.5 * (1 - x[:, 0]) c1 = -x[:, 1] + np.sin(6 * np.pi * x[:, 0] + 2 * np.pi / n_vars) + \ np.sign(term1) * np.sqrt(np.abs(term1)) c2 = -x[:, 3] + np.sin(6 * np.pi * x[:, 0] + 4 * np.pi / n_vars) + \ np.sign(term2) * np.sqrt(np.abs(term2)) return np.column_stack([c1, c2]) lb = np.zeros(D) lb[1:] = -2.0 ub = np.ones(D) ub[1:] = 2.0 problem = MTOP() problem.add_task(objective_func=T1, dim=D, constraint_func=C1, lower_bound=lb, upper_bound=ub) return problem
[docs] def CF8(self, M=3, D=None) -> MTOP: """ Generates the **CF8** problem. """ if D is None: D = 10 def T1(x): x = np.atleast_2d(x) N, n_vars = x.shape J1 = np.arange(3, n_vars, 3) # Indices 3, 6, 9... J2 = np.arange(4, n_vars, 3) # Indices 4, 7, 10... J3 = np.arange(2, n_vars, 3) # Indices 2, 5, 8... Y = x - 2 * x[:, 1:2] * np.sin(2 * np.pi * x[:, 0:1] + (np.arange(n_vars) + 1) * np.pi / n_vars) obj = np.zeros((N, M)) obj[:, 0] = np.cos(0.5 * x[:, 0] * np.pi) * np.cos(0.5 * x[:, 1] * np.pi) + ( 2 * np.mean(Y[:, J1] ** 2, axis=1) if J1.size > 0 else 0) obj[:, 1] = np.cos(0.5 * x[:, 0] * np.pi) * np.sin(0.5 * x[:, 1] * np.pi) + ( 2 * np.mean(Y[:, J2] ** 2, axis=1) if J2.size > 0 else 0) obj[:, 2] = np.sin(0.5 * x[:, 0] * np.pi) + (2 * np.mean(Y[:, J3] ** 2, axis=1) if J3.size > 0 else 0) return obj def C1(x): obj = T1(x) # Constraint involves objectives: 1 - (f1^2+f2^2)/(1-f3^2) + 4*abs(...) num = obj[:, 0] ** 2 + obj[:, 1] ** 2 den = 1 - obj[:, 2] ** 2 # Safe division with np.errstate(divide='ignore', invalid='ignore'): term = num / den term = np.nan_to_num(term) val = 1 - term + 4 * np.abs(np.sin(2 * np.pi * ((obj[:, 0] ** 2 - obj[:, 1] ** 2) / den + 1))) return val lb = np.zeros(D) ub = np.ones(D) lb[2:] = -4.0 ub[2:] = 4.0 problem = MTOP() problem.add_task(objective_func=T1, dim=D, constraint_func=C1, lower_bound=lb, upper_bound=ub) return problem
[docs] def CF9(self, M=3, D=None) -> MTOP: """ Generates the **CF9** problem. """ if D is None: D = 10 def T1(x): x = np.atleast_2d(x) N, n_vars = x.shape J1 = np.arange(3, n_vars, 3) J2 = np.arange(4, n_vars, 3) J3 = np.arange(2, n_vars, 3) Y = x - 2 * x[:, 1:2] * np.sin(2 * np.pi * x[:, 0:1] + (np.arange(n_vars) + 1) * np.pi / n_vars) obj = np.zeros((N, M)) obj[:, 0] = np.cos(0.5 * x[:, 0] * np.pi) * np.cos(0.5 * x[:, 1] * np.pi) + ( 2 * np.mean(Y[:, J1] ** 2, axis=1) if J1.size > 0 else 0) obj[:, 1] = np.cos(0.5 * x[:, 0] * np.pi) * np.sin(0.5 * x[:, 1] * np.pi) + ( 2 * np.mean(Y[:, J2] ** 2, axis=1) if J2.size > 0 else 0) obj[:, 2] = np.sin(0.5 * x[:, 0] * np.pi) + (2 * np.mean(Y[:, J3] ** 2, axis=1) if J3.size > 0 else 0) return obj def C1(x): obj = T1(x) num = obj[:, 0] ** 2 + obj[:, 1] ** 2 den = 1 - obj[:, 2] ** 2 with np.errstate(divide='ignore', invalid='ignore'): term = num / den term = np.nan_to_num(term) val = 1 - term + 3 * np.sin(2 * np.pi * ((obj[:, 0] ** 2 - obj[:, 1] ** 2) / den + 1)) return val lb = np.zeros(D) ub = np.ones(D) lb[2:] = -2.0 ub[2:] = 2.0 problem = MTOP() problem.add_task(objective_func=T1, dim=D, constraint_func=C1, lower_bound=lb, upper_bound=ub) return problem
[docs] def CF10(self, M=3, D=None) -> MTOP: """ Generates the **CF10** problem. """ if D is None: D = 10 def T1(x): x = np.atleast_2d(x) N, n_vars = x.shape J1 = np.arange(3, n_vars, 3) J2 = np.arange(4, n_vars, 3) J3 = np.arange(2, n_vars, 3) Y = x - 2 * x[:, 1:2] * np.sin(2 * np.pi * x[:, 0:1] + (np.arange(n_vars) + 1) * np.pi / n_vars) h_J1 = 4 * Y[:, J1] ** 2 - np.cos(8 * np.pi * Y[:, J1]) + 1 h_J2 = 4 * Y[:, J2] ** 2 - np.cos(8 * np.pi * Y[:, J2]) + 1 h_J3 = 4 * Y[:, J3] ** 2 - np.cos(8 * np.pi * Y[:, J3]) + 1 obj = np.zeros((N, M)) obj[:, 0] = np.cos(0.5 * x[:, 0] * np.pi) * np.cos(0.5 * x[:, 1] * np.pi) + ( 2 * np.mean(h_J1, axis=1) if J1.size > 0 else 0) obj[:, 1] = np.cos(0.5 * x[:, 0] * np.pi) * np.sin(0.5 * x[:, 1] * np.pi) + ( 2 * np.mean(h_J2, axis=1) if J2.size > 0 else 0) obj[:, 2] = np.sin(0.5 * x[:, 0] * np.pi) + (2 * np.mean(h_J3, axis=1) if J3.size > 0 else 0) return obj def C1(x): # Same as CF9 constraint obj = T1(x) num = obj[:, 0] ** 2 + obj[:, 1] ** 2 den = 1 - obj[:, 2] ** 2 with np.errstate(divide='ignore', invalid='ignore'): term = num / den term = np.nan_to_num(term) val = 1 - term + np.sin(2 * np.pi * ((obj[:, 0] ** 2 - obj[:, 1] ** 2) / den + 1)) return val lb = np.zeros(D) ub = np.ones(D) lb[2:] = -2.0 ub[2:] = 2.0 problem = MTOP() problem.add_task(objective_func=T1, dim=D, constraint_func=C1, lower_bound=lb, upper_bound=ub) return problem
# --- Pareto Front (PF) Functions --- def CF1_PF(N: int, M: int = 2) -> np.ndarray: """Pareto Front for CF1.""" f1 = np.linspace(0, 1, 21) f2 = 1 - f1 return np.column_stack([f1, f2]) def CF2_PF(N: int, M: int = 2) -> np.ndarray: """Pareto Front for CF2.""" f1 = np.linspace(0, 1, N) f2 = 1 - np.sqrt(f1) # Filter infeasible mask = ((f1 > 0) & (f1 < 1 / 16)) | ((f1 > 1 / 4) & (f1 < 9 / 16)) return np.column_stack([f1[~mask], f2[~mask]]) def CF3_PF(N: int, M: int = 2) -> np.ndarray: """Pareto Front for CF3.""" f1 = np.linspace(0, 1, N) f2 = 1 - f1 ** 2 # Filter infeasible mask = ((f1 > 0) & (f1 < 0.5)) | ((f1 > np.sqrt(0.5)) & (f1 < np.sqrt(0.75))) return np.column_stack([f1[~mask], f2[~mask]]) def CF4_PF(N: int, M: int = 2) -> np.ndarray: """Pareto Front for CF4.""" f1 = np.linspace(0, 1, N) f2 = 1 - f1 mask1 = (f1 > 0.5) & (f1 <= 0.75) f2[mask1] = -0.5 * f1[mask1] + 0.75 mask2 = f1 > 0.75 f2[mask2] = 1 - f1[mask2] + 0.125 return np.column_stack([f1, f2]) def CF5_PF(N: int, M: int = 2) -> np.ndarray: """Pareto Front for CF5.""" return CF4_PF(N, M) def CF6_PF(N: int, M: int = 2) -> np.ndarray: """Pareto Front for CF6.""" f1 = np.linspace(0, 1, N) f2 = (1 - f1) ** 2 mask1 = (f1 > 0.5) & (f1 <= 0.75) f2[mask1] = 0.5 * (1 - f1[mask1]) mask2 = f1 > 0.75 f2[mask2] = 0.25 * np.sqrt(1 - f1[mask2]) return np.column_stack([f1, f2]) def CF7_PF(N: int, M: int = 2) -> np.ndarray: """Pareto Front for CF7.""" return CF6_PF(N, M) def CF8_PF(N: int, M: int = 3) -> np.ndarray: """Pareto Front for CF8.""" n_per_group = max(1, N // 5) R = [] for i in range(5): r3 = np.sin(np.linspace(0, 1, n_per_group) * np.pi / 2) r1 = np.sqrt(i / 4.0 * (1 - r3 ** 2)) r2 = np.sqrt(np.maximum(1 - r1 ** 2 - r3 ** 2, 0)) R.append(np.column_stack([r1, r2, r3])) return np.vstack(R) def CF9_PF(N: int, M: int = 3) -> np.ndarray: """Pareto Front for CF9.""" W, _ = uniform_point(N, 3) norm = np.sqrt(np.sum(W ** 2, axis=1, keepdims=True)) R = W / norm term = 1 - R[:, 2] ** 2 c1 = np.sqrt(term / 4.0) c2 = np.sqrt(term / 2.0) c3 = np.sqrt(3 * term / 4.0) mask = ((R[:, 0] > 1e-5) & (R[:, 0] < c1)) | \ ((R[:, 0] > c2) & (R[:, 0] < c3)) return R[~mask] def CF10_PF(N: int, M: int = 3) -> np.ndarray: """Pareto Front for CF10.""" return CF9_PF(N, M) SETTINGS = { 'metric': 'IGD', 'n_ref': 10000, 'CF1': {'T1': CF1_PF}, 'CF2': {'T1': CF2_PF}, 'CF3': {'T1': CF3_PF}, 'CF4': {'T1': CF4_PF}, 'CF5': {'T1': CF5_PF}, 'CF6': {'T1': CF6_PF}, 'CF7': {'T1': CF7_PF}, 'CF8': {'T1': CF8_PF}, 'CF9': {'T1': CF9_PF}, 'CF10': {'T1': CF10_PF}, }