Source code for desdeo_emo.recombination.biogp_xover

import numpy as np
from copy import deepcopy
from random import choice
from random import shuffle


[docs]def mate(mating_pop, individuals: list, params): """Perform BioGP crossover functions. Produce two offsprings by swapping genetic material of the two parents. Standard crossover: Swap two random subtrees between the parents. Height-fair crossover: Swap two random subtrees between the parents at the selected depth. Parameters ---------- mating_pop : list List of indices of individuals to mate. If None, choose from population randomly. Each entry should contain two indices, one for each parent. individuals : list List of all individuals. params : dict Parameters for evolution. If None, use defaults. Returns ------- offspring : list The offsprings produced as a result of crossover. """ prob_crossover = params.get("prob_crossover", 0.9) prob_standard = 0.5 prob_height_fair = prob_crossover - prob_standard r = np.random.rand() if mating_pop is None: mating_pop = [] for i in range(len(individuals)): mating_pop.append([i, np.random.randint(len(individuals))]) offspring = [] for mates in mating_pop: offspring1 = deepcopy(individuals[mates[0]]) offspring2 = deepcopy(individuals[mates[1]]) # Height-fair xover if r <= prob_height_fair: depth = min(offspring1.total_depth, offspring2.total_depth) rand_node1 = choice(offspring1.nodes_at_depth[depth]) rand_node2 = choice(offspring2.nodes_at_depth[depth]) tmp_value = rand_node1.value tmp_roots = rand_node1.roots rand_node1.value = rand_node2.value rand_node1.roots = rand_node2.roots rand_node2.value = tmp_value rand_node2.roots = tmp_roots offspring1.nodes = offspring1.get_sub_nodes() offspring2.nodes = offspring2.get_sub_nodes() # Standard xover elif r <= prob_height_fair + prob_standard: rand_node1 = choice(offspring1.nodes[1:]) # Exclude linear node rand_node2 = choice(offspring2.nodes[1:]) tmp_value = rand_node1.value tmp_roots = rand_node1.roots rand_node1.value = rand_node2.value rand_node1.roots = rand_node2.roots rand_node2.value = tmp_value rand_node2.roots = tmp_roots offspring1.nodes = offspring1.get_sub_nodes() offspring2.nodes = offspring2.get_sub_nodes() else: pass offspring.extend((offspring1, offspring2)) return offspring
[docs]class BioGP_xover: def __init__( self, probability_crossover: float = 0.9, probability_standard: float = 0.5 ): self.probability_crossover: float = probability_crossover if probability_standard > probability_crossover: msg = ( f"Probability of standard crossover ({probability_standard}) should be " f"less than probability of crossover ({probability_crossover})" ) raise ValueError(msg) self.probability_standard: float = probability_standard
[docs] def do(self, pop, mating_pop_ids): prob_height_fair = self.probability_crossover - self.probability_standard pop_size = pop.shape[0] if mating_pop_ids is None: shuffled_ids = list(range(pop_size)) shuffle(shuffled_ids) else: shuffled_ids = mating_pop_ids if np.asarray(shuffled_ids).ndim == 1: mating_pop = [ [shuffled_ids[x], shuffled_ids[x]] for x in range(len(shuffled_ids)) if x % 2 == 0 ] elif np.asarray(shuffled_ids).ndim == 2: mating_pop = shuffled_ids offspring = [] r = np.random.rand() for mates in mating_pop: offspring1 = deepcopy(pop[mates[0]][0]) offspring2 = deepcopy(pop[mates[1]][0]) # Height-fair xover if r <= prob_height_fair: depth = min(offspring1.total_depth, offspring2.total_depth) rand_node1 = choice(offspring1.nodes_at_depth[depth]) rand_node2 = choice(offspring2.nodes_at_depth[depth]) tmp_value = rand_node1.value tmp_roots = rand_node1.roots rand_node1.value = rand_node2.value rand_node1.roots = rand_node2.roots rand_node2.value = tmp_value rand_node2.roots = tmp_roots offspring1.nodes = offspring1.get_sub_nodes() offspring2.nodes = offspring2.get_sub_nodes() # Standard xover elif r <= self.probability_crossover: rand_node1 = choice(offspring1.nodes[1:]) # Exclude linear node rand_node2 = choice(offspring2.nodes[1:]) tmp_value = rand_node1.value tmp_roots = rand_node1.roots rand_node1.value = rand_node2.value rand_node1.roots = rand_node2.roots rand_node2.value = tmp_value rand_node2.roots = tmp_roots offspring1.nodes = offspring1.get_sub_nodes() offspring2.nodes = offspring2.get_sub_nodes() else: pass offspring.extend((offspring1, offspring2)) return np.asarray(offspring).reshape(-1,1)