def add_edge(network): """ Random mutation of adding a single edge between two random chosen nodes. :param network: PeepoNetwork to mutate :return: mutated PeepoNetwork """ node_pool = network.get_root_nodes() if not node_pool: logging.debug( 'Model contains no valid nodes to add edge from... Adding a new node' ) return add_node(network) parent_node = random.choice(node_pool) child_pool = np.setdiff1d(network.get_leaf_nodes(), network.get_outgoing_edges(parent_node), assume_unique=True) if not child_pool.size: return remove_edge(network) child_node = random.choice(child_pool) logging.info('Adding edge from %s to %s', parent_node, child_node) network.add_edge((parent_node, child_node)) parents_card = [ network.cardinality_map[x] for x in network.get_incoming_edges(child_node) ] network.add_cpd(child_node, ga_child_cpd(parents_card, network.omega_map[child_node])) return network
def remove_edge(network): """ Random mutation of removing a single edge between two random chosen nodes. :param network: PeepoNetwork to mutate :return: mutated PeepoNetwork """ node_pool = network.get_root_nodes() if not node_pool: logging.debug( 'Model contains no valid nodes to remove an edge from... Adding a new node' ) return add_node(network) parent_node = random.choice(node_pool) outgoing_edges = network.get_outgoing_edges(parent_node) if len(outgoing_edges) <= 1: logging.debug( 'Model contains no valid edges to remove... Adding a new edge instead' ) return add_edge(network) child_node = random.choice(outgoing_edges) network.remove_edge((parent_node, child_node)) logging.info('Removed edge (%s, %s)', parent_node, child_node) parents_card = [ network.cardinality_map[x] for x in network.get_incoming_edges(child_node) ] network.add_cpd(child_node, ga_child_cpd(parents_card, network.omega_map[child_node])) return network
def add_node(network): """ Random mutation of adding a single node and an edge. :param network: PeepoNetwork to mutate :return: mutated PeepoNetwork """ new_parent_node = str(uuid.uuid4())[:8] child_node = random.choice(network.get_leaf_nodes()) logging.info('Adding new node with edge to: %s to %s', new_parent_node, child_node) network.add_belief_node(new_parent_node, 2) network.add_edge((new_parent_node, child_node)) parents_card = [ network.cardinality_map[x] for x in network.get_incoming_edges(child_node) ] network.add_omega(new_parent_node, np.random.rand(2) * (2 * math.pi)) network.add_cpd(new_parent_node, ga_parent_cpd(network.omega_map[new_parent_node])) network.add_cpd(child_node, ga_child_cpd(parents_card, network.omega_map[child_node])) return network
def mutate_cpds(network): epsilon = random.uniform(0.05, 0.75) for leaf in network.get_leaf_nodes(): parents_card = [ network.cardinality_map[x] for x in network.get_incoming_edges(leaf) ] network.omega_map[leaf] += ( 0.5 - np.random.rand(network.cardinality_map[leaf])) * epsilon network.add_cpd( leaf, ga_child_cpd(parents_card, network.omega_map[leaf])) return network
def first_generation(self): """ Generates the 0th generation population. :return New population """ peepo_template = read_from_file(self.source) population = [] if not peepo_template.get_root_nodes(): for _ in range(0, int(len(peepo_template.get_leaf_nodes()) / 3)): peepo_template.add_belief_node(str(uuid.uuid4())[:8], 2) # TODO: use get_topologies once accepted topologies = get_topologies(peepo_template, simple_first=self.simple_start, max_topologies=self.n_pop) for topology in topologies: peepo_template.edges = topology['edges'] individual = peepo_template.copy() for node in individual.get_nodes(): parent_nodes = individual.get_incoming_edges(node) if len(parent_nodes) == 0: omega = [] cpd = np.full(individual.cardinality_map[node], 1 / individual.cardinality_map[node]) else: parents_card = [ individual.cardinality_map[p] for p in parent_nodes ] max_omega = 2 * math.pi * np.prod(parents_card) omega = np.random.rand( individual.cardinality_map[node]) * max_omega cpd = ga_child_cpd(parents_card, omega) individual.add_cpd(node, cpd) individual.add_omega(node, omega) individual.assemble() population.append(Individual(0.0, individual)) self.best_chromosome = population[0] self.last_generation = (0.0, population) return population
def cross_over(self, selected_parents): selected_offspring = [] mating_couples = list(itertools.combinations(selected_parents, 2)) # To control exponential growth, limit number of combinations if len(mating_couples) > self.n_pop: random.shuffle(mating_couples) mating_couples = mating_couples[0:int(self.n_pop / 2.)] for n, chrom in enumerate(mating_couples): map_1 = get_adjency_map(chrom[0].network) map_2 = get_adjency_map(chrom[1].network) diff = np.abs(map_1 - map_2) i_sum = np.sum(diff) if i_sum == 0 or i_sum > GeneticAlgorithm.THRESHOLD: selected_offspring.append( (Individual(0.0, chrom[0].network.copy()), 0, 0)) selected_offspring.append( (Individual(0.0, chrom[1].network.copy()), 0, 0)) continue indices = np.argwhere(diff == 1) combinations = [[1, 0], [0, 1]] if len(indices) > 1: combinations = np.transpose( get_index_matrix(np.full(len(indices), 2).tolist())) for comb in combinations: i_map = np.copy(map_1) for pos, index in enumerate(indices): i_map[index[0], index[1]] = comb[pos] if 0 in np.sum(i_map, axis=1) or np.array_equal( i_map, map_1) or np.array_equal(i_map, map_2): continue edges = adjency_to_edges(chrom[0].network, i_map) new_peepo = chrom[0].network.copy() new_peepo.disassemble() new_peepo.edges = edges for node in new_peepo.get_nodes(): incoming_nodes = new_peepo.get_incoming_edges(node) if len(incoming_nodes) == 0: my_cpd = np.full(new_peepo.cardinality_map[node], 1. / new_peepo.cardinality_map[node]) my_omega = [] else: my_card_parents = [] [ my_card_parents.append( new_peepo.cardinality_map[nod]) for nod in incoming_nodes ] max_omega = 2 * math.pi * np.prod(my_card_parents) my_omega = np.random.rand( new_peepo.cardinality_map[node]) * max_omega my_cpd = ga_child_cpd(my_card_parents, my_omega) new_peepo.add_cpd(node, my_cpd) new_peepo.add_omega(node, my_omega) new_peepo.assemble() if np.array_equal(comb[0], comb[1]): selected_offspring.append((Individual(0.0, new_peepo), 0, 0)) else: selected_offspring.append( (Individual(0.0, new_peepo), random.uniform(0, 1), random.uniform(0, 1))) # If there's not enough offspring, fill it up with parents while True: if len(selected_parents) + len(selected_offspring) >= self.n_pop: break for parent in selected_parents: if len(selected_parents) + len( selected_offspring) >= self.n_pop: break selected_offspring.append((parent, 0, 0)) return selected_offspring