Source code for DETAlgs.eps_ade

import copy
import random
import numpy as np
from detpy.DETAlgs.base import BaseAlg
from detpy.DETAlgs.data.alg_data import EPSADEData
from detpy.DETAlgs.methods.methods_de import mutation, crossing
from detpy.DETAlgs.methods.methods_eps_ade import control_epsilon_level, adaptive_de_operation
from detpy.DETAlgs.methods.methods_eps_de import calculate_epsilon_constrained, epsilon_level_comparisons, \
    epsilon_constrained_method
from detpy.DETAlgs.methods.methods_eps_deag import calculate_epsilon_level
from detpy.DETAlgs.methods.methods_eps_deg import calculate_init_epsilon_level
from detpy.models.enums.basevectorschema import BaseVectorSchema
from detpy.models.enums.boundary_constrain import fix_boundary_constraints
from detpy.models.enums.crossingtype import CrossingType
from detpy.models.population import Population


[docs] class EPSADE(BaseAlg): """ EPSADE - Constrained Adaptive Differential Evolution Links: https://ieeexplore.ieee.org/abstract/document/5586545 References: Tetsuyuki Takahama; Setsuko Sakai; "Efficient constrained optimization by the ε constrained adaptive differential evolution", 2010 IEEE Congress on Evolutionary Computation, 18-23 July 2010, Barcelona, Spain doi: 10.1109/CEC.2010.5586545. """ def __init__(self, params: EPSADEData, db_conn=None, db_auto_write=False): super().__init__(EPSADE.__name__, params, db_conn, db_auto_write) self.init_mutation_factor = params.init_mutation_factor # F self.init_crossover_rate = params.init_crossover_rate # Cr self.mu_mutation_factory = self.init_mutation_factor self.mu_crossover_rate = self.init_crossover_rate self.number_of_successful_operation = 0 self.mutation_factor_sum = 0 self.crossover_rate_sum = 0 self.mutation_factor_perturbation_width = params.mutation_factor_perturbation_width self.crossover_rate_perturbation_width = params.crossover_rate_perturbation_width self.weight_of_update = np.clip(params.weight_of_update, 1e-12, 1) self.truncation_mechanism_factory = params.truncation_mechanism_factory # ap self.g_funcs = params.g_funcs # Inequality constraints functions self.h_funcs = params.h_funcs # Equality constraints functions self.tolerance_h = params.tolerance_h self.control_generations = params.control_generations self.epsilon_scaling_factor = params.epsilon_scaling_factor self.penalty_power = params.penalty_power self.theta = params.theta if params.theta is not None else int(0.2 * self.population_size) self.epsilon_constrained = calculate_epsilon_constrained(self._pop, self.g_funcs, self.h_funcs, self.penalty_power, self.tolerance_h) self.init_epsilon_level = calculate_init_epsilon_level(self.epsilon_constrained, self.theta) self.epsilon_level = self.init_epsilon_level self.penalty_power = params.penalty_power
[docs] def selection(self, modified_population: Population) -> Population | None: if self._pop.size != modified_population.size: print("Selection: populations have different sizes") return None if self._pop.optimization != modified_population.optimization: print("Selection: populations have different optimization types") return None optimization = self._pop.optimization modified_epsilon_constrained = calculate_epsilon_constrained(modified_population, self.g_funcs, self.h_funcs, self.penalty_power, self.tolerance_h) new_members = [] for i in range(self._pop.size): if epsilon_level_comparisons(modified_population.members[i], self._pop.members[i], modified_epsilon_constrained[i], self.epsilon_constrained[i], self.epsilon_level, optimization): new_members.append(copy.deepcopy(modified_population.members[i])) else: mutation_factor = np.clip( self.mu_mutation_factory + self.mutation_factor_perturbation_width * random.uniform(-0.5, 0.5) , 0.4, 0.9) crossover_rate = np.clip( self.mu_crossover_rate + self.crossover_rate_perturbation_width * random.uniform(-0.5, 0.5) , 0, 1) new_member = adaptive_de_operation(self._pop, self._pop.members[i], mutation_factor, crossover_rate, self._function) new_member_epsilon_constrained = epsilon_constrained_method(new_member.get_chromosomes(), self.g_funcs, self.h_funcs, self.penalty_power, self.tolerance_h) if epsilon_level_comparisons(new_member, self._pop.members[i], new_member_epsilon_constrained, self.epsilon_constrained[i], self.epsilon_level, optimization): new_members.append(new_member) self.number_of_successful_operation += 1 self.mutation_factor_sum += mutation_factor self.crossover_rate_sum += crossover_rate else: new_members.append(copy.deepcopy(self._pop.members[i])) new_population = Population( lb=self._pop.lb, ub=self._pop.ub, arg_num=self._pop.arg_num, size=self._pop.size, optimization=self._pop.optimization ) new_population.members = np.array(new_members) return new_population
[docs] def update_adaptive_parameters(self): if self.number_of_successful_operation > 0: self.mu_mutation_factory = (1 - self.weight_of_update) * self.mu_mutation_factory + ( self.weight_of_update * self.mutation_factor_sum) / self.number_of_successful_operation self.mu_crossover_rate = (1 - self.weight_of_update) * self.mu_crossover_rate + ( self.weight_of_update * self.crossover_rate_sum) / self.number_of_successful_operation
[docs] def next_epoch(self): self.number_of_successful_operation = 0 self.mutation_factor_sum = 0 self.crossover_rate_sum = 0 # New population after mutation v_pop = mutation(self._pop, base_vector_schema=BaseVectorSchema.RAND, optimization_type=self.optimization_type, y=1, f=self.init_mutation_factor) # Apply boundary constrains on population in place fix_boundary_constraints(v_pop, self.boundary_constraints_fun) # New population after crossing u_pop = crossing(self._pop, v_pop, cr=self.init_crossover_rate, crossing_type=CrossingType.EXPOTENTIAL) # Update values before selection u_pop.update_fitness_values(self._function.eval, self.parallel_processing) # Select new population new_pop = self.selection(u_pop) self.update_adaptive_parameters() self.epsilon_level = calculate_epsilon_level(self.init_epsilon_level, self._epoch_number, self.control_generations, self.epsilon_scaling_factor) self.epsilon_constrained = calculate_epsilon_constrained(new_pop, self.g_funcs, self.h_funcs, self.penalty_power, self.tolerance_h) self.epsilon_level = control_epsilon_level(self.epsilon_level, self.epsilon_constrained, self.truncation_mechanism_factory, self.population_size) # Override data self._pop = new_pop