def produce_offspring(parent_a, parent_b): """ ______ Input: two parent genomes ______ Output: offspring genome ______ The weights of the more fit parent are kept To achieve this it is possible to just add the genes that are unique to the flop genome to the fit genome """ fit_parent, flop_parent = sorted( [parent_a, parent_b], key=lambda x: x.fitness, reverse=True) #reverse sort is from highest to lowest fit_genome, flop_genome = utils.load_bot_genome( fit_parent.name), utils.load_bot_genome(flop_parent.name) offspring_genome = fit_genome for net in ['play', 'bid', 'stm']: fit_connection_genome, flop_connection_genome = fit_genome[ "{}_connection_genome".format(net)], flop_genome[ "{}_connection_genome".format(net)] fit_node_genome, flop_node_genome = fit_genome["{}_node_genome".format( net)], flop_genome["{}_node_genome".format(net)] offspring_genome["{}_connection_genome".format( net)] = produce_net_connection_offspring(fit_connection_genome, flop_connection_genome) offspring_genome["{}_node_genome".format( net)] = produce_net_node_offspring(fit_node_genome, flop_node_genome) #check for recursive structure in the connection genome if utils.genome_check_for_recursion(fit_parent, genome=offspring_genome): print("Recursive Offspring Prevented") return False return offspring_genome
def mutation_step(bot_name, link_thresh, node_thresh, weights_mut_thresh, rand_weight_thresh, pert_rate): """ ______ Input: The name of the bot that is mutated The probabilities for mutations to ocurr ______ Output: None The bots genome is changed """ reset_score_bool = False for net in ["stm", "bid", "play"]: thresh_list = [link_thresh, node_thresh, weights_mut_thresh] mutate_list = [ chance <= thresh_list[chance_idx] for chance_idx, chance in enumerate(np.random.uniform(size=3)) ] link_mut, node_mut, weights_mut = mutate_list if any(mutate_list): bot_genome = utils.load_bot_genome(bot_name) connection_genome, node_genome = bot_genome[ "{}_connection_genome".format(net)], bot_genome[ "{}_node_genome".format(net)] if link_mut: connection_genome, link_mutation = mutate_link( node_genome, connection_genome, net) if node_mut: node_genome, connection_genome, in_mutation, out_mutation = mutate_node( node_genome, connection_genome, net) if weights_mut: connection_genome = mutate_weights( connection_genome, node_genome, rand_weight_thresh, pert_rate=pert_rate ) #does not need the net type bc no innovation numbers are incremented bot_genome["{}_connection_genome".format(net)] = connection_genome bot_genome["{}_node_genome".format(net)] = node_genome utils.save_bot_genome(bot_name, bot_genome) if sum(thresh_list) > 0: reset_score_bool = True if reset_score_bool: utils.reset_score(bot_name)
def __init__(self, name, sigmoid_function=expit): self.name = name self.species = None self.fitness = None self.round_score = 0 self.game_score = 0 self.cards = [] #an empty hand so to speak self.current_stm = [0 for _ in range(10)] #Initiating stm self.sigmoid = sigmoid_function if os.path.exists(base_path + '\Bots\{}'.format(self.name)): genome = utils.load_bot_genome(self.name) bid_node_genome, bid_connection_genome = genome[ "bid_node_genome"], genome["bid_connection_genome"] play_node_genome, play_connection_genome = genome[ "play_node_genome"], genome["play_connection_genome"] stm_node_genome, stm_connection_genome = genome[ "stm_node_genome"], genome["stm_connection_genome"] self.bid_net = self.Network(bid_node_genome, bid_connection_genome, net_sigmoid_function=self.sigmoid) self.play_net = self.Network(play_node_genome, play_connection_genome, net_sigmoid_function=self.sigmoid) self.stm_net = self.Network(stm_node_genome, stm_connection_genome, net_sigmoid_function=self.sigmoid) #print('{} loaded'.format(self.name)) else: print("ERROR: Player {} Directory does not exist.".format(name))
def reproduce(bots, bot_species, names, species_size, preservation_rate): """ ______ Input: bots --> a list of bot objects bot_species --> a list of bot names ______ Output: names of the new set of bots of the same size as the input set ______ makes the species of bots reproduce into a new set of bots 25% of offspring is not crossover i.e. only mutations There is no specification as to who mate with who The better the score the more offspring a bot produces So the first produces another 37.5% of the offspring each the Second produces another 18.75%, third produces 9.375% etc. """ print("Species Size: ", species_size) new_generation = [] bots = [bot for bot in bots if bot.name in bot_species] #from name to object bots.sort(key=lambda bot: bot.fitness, reverse=True) #highest score to lowest if species_size <= 5: #in case the species is too small to reproduce if len(bots) >= 5: new_species_names, kill_list_names = [ bot.name for bot in bots[:species_size] ], [bot for bot in bots[species_size:]] return new_species_names, kill_list_names else: #just reproduce the best bot as many times as needed for new generation bot_offspring_count = 0 for bot in range(species_size): offspring_genome = utils.load_bot_genome(bots[0].name) utils.save_init_genome( (offspring_name := names[bot_offspring_count]), offspring_genome) utils.save_init_score(offspring_name) new_generation.append(offspring_name) bot_offspring_count += 1 return new_generation, [bot.name for bot in bots] kill_list = [ bot.name for bot in bots[int(np.round(preservation_rate * species_size)):] ] #incinerate the bad part of the generation after speciation bots = bots[:int(np.round( preservation_rate * species_size))] #remove the incinerated botnames from the bot list for bot in bots[:int(np.round(species_size * 0.25))]: new_generation.append(bot.name) """ This whole bot_count aspect of the reproduction method should be gotten rid of but I have not the patience for that rn """ species_offspring_count = 0 while (len(new_generation) < species_size): percentage = 0.375 for bot in bots: bot_offspring_count = 0 while bot_offspring_count / species_size <= percentage and int( np.round(percentage * species_size)) >= 1: if (offspring_genome := produce_offspring(bot, random.choice(bots))): utils.save_init_genome( offspring_name := names[species_offspring_count + bot_offspring_count], offspring_genome) utils.save_init_score(offspring_name) new_generation.append(offspring_name) bot_offspring_count += 1 species_offspring_count += bot_offspring_count percentage /= 2
def graph(bot_name, net_type, added_only=True): """ TODO https://www.geeksforgeeks.org/python-visualize-graphs-generated-in-networkx-using-matplotlib/ https://networkx.github.io/documentation/stable/_modules/networkx/drawing/nx_pylab.html#draw """ """ ______ Input: Bot Genome Neural Net Type ______ Output: None Plots graph of each a neural net in the bot genome ______ The layout can be customized with nx.draw(nn_graph,pos = dictionary) """ bot_genome = utils.load_bot_genome(bot_name) connection_genome = bot_genome["{}_connection_genome".format(net_type)] node_genome = bot_genome["{}_node_genome".format(net_type)] init_innovation_number = utils.init_innovation_numbers[net_type] nn_graph = nx.DiGraph( ) #initializing the graph; adding the nodes and edges for node in node_genome: nn_graph.add_node(node["INDEX"], bias=node["BIAS"]) for gene in connection_genome: if gene["INNOVATION"] > init_innovation_number or added_only == False: nn_graph.add_edge(gene["IN"], gene["OUT"], weight=gene["WEIGHT"]) try: #listing the weights and biases st. the graph can be colored edges, weights = zip( *nx.get_edge_attributes(nn_graph, 'weight').items()) nodes, biases = zip(*nx.get_node_attributes(nn_graph, 'bias').items()) except ValueError: print(f"No Connections in {bot_name}'s {net_type} net") return except Exception as exception: sys.exit(f"Graphing {bot_name}'s {net_type} net failed: {exception}") plt.title(f"{bot_name} Added Graph Structure in {net_type} net" ) #only works if called before nx.draw cmap = plt.cm.seismic sm = plt.cm.ScalarMappable(cmap=cmap, norm=plt.Normalize(vmin=min(weights + biases), vmax=max(weights + biases))) sm._A = [] plt.colorbar(sm) #colorbar legend so the colors are identifiable nx.draw(nn_graph, arrows=True, alpha=0.5, pos=node_positions(nn_graph, net_type), edge_color=weights, node_color=biases, edge_cmap=cmap, cmap=cmap) nx.draw_networkx_labels(nn_graph, pos=node_positions(nn_graph, net_type)) plt.show()