Source code for opfunu.utils.operator

#!/usr/bin/env python
# Created by "Thieu" at 10:49, 01/07/2022 ----------%                                                                               
#       Email: nguyenthieu2102@gmail.com            %                                                    
#       Github: https://github.com/thieu1995        %                         
# --------------------------------------------------%

import numpy as np


[docs]def rounder(x, condition): temp_2x = 2 * x dec, inter = np.modf(temp_2x) temp_2x = np.where(temp_2x <= 0.0, inter - (dec >= 0.5), temp_2x) temp_2x = np.where(dec < 0.5, inter, temp_2x) temp_2x = np.where(dec >= 0.5, inter + 1, temp_2x) return np.where(condition < 0.5, x, temp_2x / 2)
[docs]def griewank_func(x): x = np.array(x).ravel() idx = np.arange(1, len(x) + 1) t1 = np.sum(x ** 2) / 4000 t2 = np.prod(np.cos(x / np.sqrt(idx))) return t1 - t2 + 1
[docs]def rosenbrock_func(x, shift=0.0): x = np.array(x).ravel() + shift term1 = 100 * (x[:-1] ** 2 - x[1:]) ** 2 term2 = (x[:-1] - 1) ** 2 return np.sum(term1 + term2)
[docs]def scaffer_func(x): x = np.array(x).ravel() return 0.5 + (np.sin(np.sqrt(np.sum(x ** 2))) ** 2 - 0.5) / (1 + 0.001 * np.sum(x ** 2)) ** 2
[docs]def rastrigin_func(x): x = np.array(x).ravel() return np.sum(x ** 2 - 10 * np.cos(2 * np.pi * x) + 10)
[docs]def weierstrass_func(x, a=0.5, b=3., k_max=20): x = np.array(x).ravel() ndim = len(x) k = np.arange(0, k_max + 1) result = 0 for idx in range(0, ndim): result += np.sum(a ** k * np.cos(2 * np.pi * b ** k * (x[idx] + 0.5))) return result - ndim * np.sum(a ** k * np.cos(np.pi * b ** k))
[docs]def weierstrass_norm_func(x, a=0.5, b=3., k_max=20): """ This function matches CEC2005 description of F11 except for addition of the bias and follows the C implementation """ return weierstrass_func(x, a, b, k_max) - weierstrass_func(np.zeros(len(x)), a, b, k_max)
[docs]def ackley_func(x): x = np.array(x).ravel() ndim = len(x) t1 = np.sum(x ** 2) t2 = np.sum(np.cos(2 * np.pi * x)) return -20 * np.exp(-0.2 * np.sqrt(t1 / ndim)) - np.exp(t2 / ndim) + 20 + np.e
[docs]def sphere_func(x): x = np.array(x).ravel() return np.sum(x ** 2)
[docs]def rotated_expanded_schaffer_func(x): x = np.asarray(x).ravel() x_pairs = np.column_stack((x, np.roll(x, -1))) sum_sq = x_pairs[:, 0] ** 2 + x_pairs[:, 1] ** 2 # Calculate the Schaffer function for all pairs simultaneously schaffer_values = (0.5 + (np.sin(np.sqrt(sum_sq)) ** 2 - 0.5) / (1 + 0.001 * sum_sq) ** 2) return np.sum(schaffer_values)
[docs]def rotated_expanded_scaffer_func(x): x = np.array(x).ravel() results = [scaffer_func([x[idx], x[idx + 1]]) for idx in range(0, len(x) - 1)] return np.sum(results) + scaffer_func([x[-1], x[0]])
[docs]def grie_rosen_cec_func(x): """This is based on the CEC version which unrolls the griewank and rosenbrock functions for better performance""" z = np.array(x).ravel() z += 1.0 # This centers the optimal solution of rosenbrock to 0 tmp1 = (z[:-1] * z[:-1] - z[1:]) ** 2 tmp2 = (z[:-1] - 1.0) ** 2 temp = 100.0 * tmp1 + tmp2 f = np.sum(temp ** 2 / 4000.0 - np.cos(temp) + 1.0) # Last calculation tmp1 = (z[-1] * z[-1] - z[0]) ** 2 tmp2 = (z[-1] - 1.0) ** 2 temp = 100.0 * tmp1 + tmp2 f += (temp ** 2) / 4000.0 - np.cos(temp) + 1.0 return f
[docs]def f8f2_func(x): x = np.array(x).ravel() results = [griewank_func(rosenbrock_func([x[idx], x[idx + 1]])) for idx in range(0, len(x) - 1)] return np.sum(results) + griewank_func(rosenbrock_func([x[-1], x[0]]))
[docs]def non_continuous_expanded_scaffer_func(x): x = np.array(x).ravel() y = rounder(x, np.abs(x)) results = [scaffer_func([y[idx], y[idx + 1]]) for idx in range(0, len(x) - 1)] return np.sum(results) + scaffer_func([y[-1], y[0]])
[docs]def non_continuous_rastrigin_func(x): x = np.array(x).ravel() y = rounder(x, np.abs(x)) shifted_y = np.roll(y, -1) results = rastrigin_func(np.column_stack((y, shifted_y))) return np.sum(results)
[docs]def elliptic_func(x): x = np.array(x).ravel() ndim = len(x) idx = np.arange(0, ndim) return np.sum(10 ** (6.0 * idx / (ndim - 1)) * x ** 2)
[docs]def sphere_noise_func(x): x = np.array(x).ravel() return np.sum(x ** 2) * (1 + 0.1 * np.abs(np.random.normal(0, 1)))
[docs]def twist_func(x): # This function in CEC-2008 F7 return 4 * (x ** 4 - 2 * x ** 3 + x ** 2)
[docs]def doubledip(x, c, s): # This function in CEC-2008 F7 if -0.5 < x < 0.5: return (-6144 * (x - c) ** 6 + 3088 * (x - c) ** 4 - 392 * (x - c) ** 2 + 1) * s else: return 0
[docs]def fractal_1d_func(x): # This function in CEC-2008 F7 np.random.seed(0) result1 = 0.0 for k in range(1, 4): result2 = 0.0 upper = 2 ** (k - 1) + 1 for t in range(1, upper): selected = np.random.choice([0, 1, 2], p=1 / 3 * np.ones(3)) result2 += np.sum([doubledip(x, np.random.uniform(0, 1), 1.0 / (2 ** (k - 1) * (2 - np.random.uniform(0, 1)))) for _ in range(0, selected)]) result1 += result2 return result1
[docs]def schwefel_12_func(x): x = np.array(x).ravel() ndim = len(x) return np.sum([np.sum(x[:idx]) ** 2 for idx in range(0, ndim)])
[docs]def tosz_func(x): def transform(xi): if xi > 0: c1, c2, x_sign = 10., 7.9, 1.0 x_star = np.log(np.abs(xi)) elif xi == 0: c1, c2, x_sign, x_star = 5.5, 3.1, 0., 0. else: c1, c2, x_sign = 5.5, 3.1, -1. x_star = np.log(np.abs(xi)) return x_sign * np.exp(x_star + 0.049 * (np.sin(c1 * x_star) + np.sin(c2 * x_star))) x = np.array(x).ravel() x[0] = transform(x[0]) x[-1] = transform(x[-1]) return x
[docs]def tasy_func(x, beta=0.5): x = np.array(x).ravel() ndim = len(x) idx = np.arange(0, ndim) up = 1 + beta * ((idx - 1) / (ndim - 1)) * np.sqrt(np.abs(x)) x_temp = np.abs(x) ** up return np.where(x > 0, x_temp, x)
[docs]def bent_cigar_func(x): x = np.array(x).ravel() return x[0] ** 2 + 10 ** 6 * np.sum(x[1:] ** 2)
[docs]def discus_func(x): x = np.array(x).ravel() return 1e6 * x[0] ** 2 + np.sum(x[1:] ** 2)
[docs]def different_powers_func(x): x = np.array(x).ravel() ndim = len(x) idx = np.arange(0, ndim) up = 2 + 4 * idx / (ndim - 1) return np.sqrt(np.sum(np.abs(x) ** up))
[docs]def generate_diagonal_matrix(size, alpha=10): idx = np.arange(0, size) diagonal = alpha ** (idx / (2 * (size - 1))) matrix = np.zeros((size, size), float) np.fill_diagonal(matrix, diagonal) return matrix
[docs]def gz_func(x): x = np.array(x).ravel() ndim = len(x) t1 = (500 - np.mod(x, 500)) * np.sin(np.sqrt(np.abs(500 - np.mod(x, 500)))) - (x - 500) ** 2 / (10000 * ndim) t2 = (np.mod(np.abs(x), 500) - 500) * np.sin(np.sqrt(np.abs(np.mod(np.abs(x), 500) - 500))) - (x + 500) ** 2 / (10000 * ndim) t3 = x * np.sin(np.abs(x) ** 0.5) conditions = [x < -500, (-500 <= x) & (x <= 500), x > 500] choices = [t2, t3, t1] y = np.select(conditions, choices, default=np.nan) return y
[docs]def katsuura_func(x): # TODO: New function failed to pass 5 test cases. # powers_of_two = 2 ** np.arange(1, 34) # reciprocals_of_two = 1 / powers_of_two # for idx in range(0, ndim): # temp = np.sum(np.abs(powers_of_two * x[idx] - np.round(powers_of_two * x[idx])) * reciprocals_of_two) # result *= (1 + (idx + 1) * temp) ** (10.0 / ndim ** 1.2) # return (result - 1) * 10 / ndim ** 2 x = np.array(x).ravel() ndim = len(x) result = 1.0 for idx in range(0, ndim): temp = np.sum([np.abs(2 ** j * x[idx] - np.round(2 ** j * x[idx])) / 2 ** j for j in range(1, 33)]) result *= (1 + (idx + 1) * temp) ** (10.0 / ndim ** 1.2) return (result - 1) * 10 / ndim ** 2
[docs]def lunacek_bi_rastrigin_func(x, miu0=2.5, d=1, shift=0.0): x = np.array(x).ravel() + shift ndim = len(x) s = 1.0 - 1.0 / (2 * np.sqrt(ndim + 20) - 8.2) miu1 = -np.sqrt((miu0 ** 2 - d) / s) delta_x_miu0 = x - miu0 term1 = np.sum(delta_x_miu0 ** 2) term2 = np.sum((x - miu1) ** 2) * s + d * ndim result = min(term1, term2) + 10 * (ndim - np.sum(np.cos(2 * np.pi * delta_x_miu0))) return result
[docs]def calculate_weight(x, delta=1.): ndim = len(x) temp = np.sum(x ** 2) if temp != 0: weight = np.sqrt(1.0 / temp) * np.exp(-temp / (2 * ndim * delta ** 2)) else: weight = 1e99 # this is the INF definition in original CEC Calculate logic return weight
[docs]def modified_schwefel_func(x): """ This is a direct conversion of the CEC2021 C-Code for the Modified Schwefel F11 Function """ z = np.array(x).ravel() + 4.209687462275036e+002 nx = len(z) mask1 = z > 500 mask2 = z < -500 mask3 = ~mask1 & ~mask2 fx = np.zeros(nx) fx[mask1] -= ((500.0 - np.fmod(z[mask1], 500)) * np.sin(np.sqrt(500.0 - np.fmod(z[mask1], 500))) - ((z[mask1] - 500.0) / 100.) ** 2 / nx) fx[mask2] -= (-500.0 + np.fmod(np.abs(z[mask2]), 500)) * np.sin(np.sqrt(500.0 - np.fmod(np.abs(z[mask2]), 500))) - ( (z[mask2] + 500.0) / 100.) ** 2 / nx fx[mask3] -= z[mask3] * np.sin(np.sqrt(np.abs(z[mask3]))) return np.sum(fx) + 4.189828872724338e+002 * nx
[docs]def happy_cat_func(x, shift=0.0): z = np.array(x).ravel() + shift ndim = len(z) t1 = np.sum(z) t2 = np.sum(z ** 2) return np.abs(t2 - ndim) ** 0.25 + (0.5 * t2 + t1) / ndim + 0.5
[docs]def hgbat_func(x, shift=0.0): x = np.array(x).ravel() + shift ndim = len(x) t1 = np.sum(x) t2 = np.sum(x ** 2) return np.abs(t2 ** 2 - t1 ** 2) ** 0.5 + (0.5 * t2 + t1) / ndim + 0.5
[docs]def zakharov_func(x): x = np.array(x).ravel() temp = np.sum(0.5 * x) return np.sum(x ** 2) + temp ** 2 + temp ** 4
[docs]def levy_func(x, shift=0.0): x = np.array(x).ravel() + shift w = 1. + (x - 1.) / 4 t1 = np.sin(np.pi * w[0]) ** 2 + (w[-1] - 1) ** 2 * (1 + np.sin(2 * np.pi * w[-1]) ** 2) t2 = np.sum((w[:-1] - 1) ** 2 * (1 + 10 * np.sin(np.pi * w[:-1] + 1) ** 2)) return t1 + t2
[docs]def expanded_schaffer_f6_func(x): """ This is a direct conversion of the CEC2021 C-Code for the Expanded Schaffer F6 Function """ z = np.array(x).ravel() temp1 = np.sin(np.sqrt(z[:-1] ** 2 + z[1:] ** 2)) temp1 = temp1 ** 2 temp2 = 1.0 + 0.001 * (z[:-1] ** 2 + z[1:] ** 2) f = np.sum(0.5 + (temp1 - 0.5) / (temp2 ** 2)) temp1_last = np.sin(np.sqrt(z[-1] ** 2 + z[0] ** 2)) temp1_last = temp1_last ** 2 temp2_last = 1.0 + 0.001 * (z[-1] ** 2 + z[0] ** 2) f += 0.5 + (temp1_last - 0.5) / (temp2_last ** 2) return f
[docs]def schaffer_f7_func(x): x = np.array(x).ravel() ndim = len(x) result = 0.0 for idx in range(0, ndim - 1): t = x[idx] ** 2 + x[idx + 1] ** 2 result += np.sqrt(t) * (np.sin(50. * t ** 0.2) + 1) return (result / (ndim - 1)) ** 2
[docs]def chebyshev_func(x): """ The following was converted from the cec2019 C code Storn's Tchebychev - a 2nd ICEO function - generalized version """ x = np.array(x).ravel() ndim = len(x) sample = 32 * ndim dx_arr = np.zeros(ndim) dx_arr[:2] = [1.0, 1.2] for i in range(2, ndim): dx_arr[i] = 2.4 * dx_arr[i-1] - dx_arr[i-2] dx = dx_arr[-1] dy = 2.0 / sample px, y, sum_val = 0, -1, 0 for i in range(sample + 1): px = x[0] for j in range(1, ndim): px = y * px + x[j] if px < -1 or px > 1: sum_val += (1.0 - abs(px)) ** 2 y += dy for _ in range(2): px = np.sum(1.2 * x[1:]) + x[0] mask = px < dx sum_val += np.sum(px[mask] ** 2) return sum_val
[docs]def inverse_hilbert_func(x): """ This is a direct conversion of the cec2019 C code for python optimized to use numpy """ x = np.array(x).ravel() ndim = len(x) b = int(np.sqrt(ndim)) # Create the Hilbert matrix i, j = np.indices((b, b)) hilbert = 1.0 / (i + j + 1) # Reshape x and compute H*x x = x.reshape((b, b)) y = np.dot(hilbert, x).dot(hilbert.T) # Compute the absolute deviations result = np.sum(np.abs(y - np.eye(b))) return result
[docs]def lennard_jones_func(x): """ This version is a direct python conversion from the C-Code of CEC2019 implementation. Find the atomic configuration with minimum energy (Lennard-Jones potential) Valid for any dimension, D = 3 * k, k = 2, 3, 4, ..., 25. k is the number of atoms in 3-D space. """ x = np.array(x).ravel() ndim = len(x) # Minima values from Cambridge cluster database: http://www-wales.ch.cam.ac.uk/~jon/structures/LJ/tables.150.html minima = np.array([-1., -3., -6., -9.103852, -12.712062, -16.505384, -19.821489, -24.113360, -28.422532, -32.765970, -37.967600, -44.326801, -47.845157, -52.322627, -56.815742, -61.317995, -66.530949, -72.659782, -77.1777043, -81.684571, -86.809782, -02.844472, -97.348815, -102.372663]) k = ndim // 3 sum_val = 0 x_matrix = x.reshape((k, 3)) for i in range(k-1): for j in range(i + 1, k): # Use slicing to get the differences between points i and j diff = x_matrix[i] - x_matrix[j] # Calculate the squared Euclidean distance ed = np.sum(diff ** 2) # Calculate ud and update sum_val accordingly ud = ed ** 3 if ud > 1.0e-10: sum_val += (1.0 / ud - 2.0) / ud else: sum_val += 1.0e20 # cec2019 version penalizes when ud is <=1e-10 return sum_val - minima[k - 2] # Subtract known minima for k
expanded_griewank_rosenbrock_func = grie_rosen_cec_func expanded_scaffer_f6_func = rotated_expanded_scaffer_func