async def evaluate_individual(current_population, individual_id, environment, iteration): """ This method obtains an overall value for an individual in an environment :param current_population: set of individuals to test against the environment :type current_population: list or DBWrapper :param individual_id: id of the individual to evaluate :type individual_id: int :param environment: the current parameters against which the individuals are being tested :type environment: Environment :param iteration: current iteration :type iteration: int :return: pair of individual with its value :rtype: tuple """ base_coll_name = f'{environment.name}_{iteration}' individual = current_population[base_coll_name][individual_id] if not is_generic(): individual_value = human_value_function(individual, environment.data) if not is_food_accessible(individual, environment.data): individual_value = individual_value * 0.5 individual_value = human_penalize_extremes(individual, individual_value, environment.data) else: individual_value = generic_value_function(individual, environment.data) individual_value = generic_penalize_extremes(individual, individual_value, environment.data) individual['value'] = individual_value current_population[f'{environment.name}_{iteration}_{"filtered"}'].append(individual) return individual_value
def add_limits(self, environment): """ This method is used to add some horizontal axis's to the plots to understand better if the results make sens. :param environment: the current parameters against which the individuals are being tested :type environment: dict """ if not is_generic(): temp_threshold = 0.05 + (abs(environment['temperature'] - 20) * (0.30 / 30)) self.ax1.axhline(y=environment['predators_speed'], c="red", linewidth=0.5, zorder=0) self.ax1.axhline(y=environment['food_animals_speed'], c="blue", linewidth=0.5, zorder=0) self.ax2.axhline(y=environment['food_animals_strength'], c="blue", linewidth=0.5, zorder=0) self.ax3.axhline(y=temp_threshold, c="blue", linewidth=0.5, zorder=0) self.ax4.axhline(y=environment['tree_height'], c="blue", linewidth=0.5, zorder=0) environment_params = '\n'.join( [f'{key}: {value}' for key, value in environment.items()]) self.ax6.text(0.2, 0.5, environment_params, horizontalalignment='left', verticalalignment='center', size=15) self.ax6.axis('off') else: for key in environment.keys(): self.__getattribute__(key).axhline(y=environment[key], c="red", linewidth=0.5, zorder=0) environment_params = '\n'.join( [f'{key}: {value}' for key, value in environment.items()]) self.data.text(0.2, 0.5, environment_params, horizontalalignment='left', verticalalignment='center', size=15) self.data.axis('off')
def set_plots(self, environment): if not is_generic(): self.ax1 = self.fig.add_subplot(3, 2, 1) self.ax1.set_title('Average Speed') self.ax1.set_ylim([ HUMAN_PARAMS['speed'][0] * 0.8, HUMAN_PARAMS['speed'][1] * 1.2 ]) self.ax2 = self.fig.add_subplot(3, 2, 2) self.ax2.set_title('Average Strength') self.ax2.set_ylim([ HUMAN_PARAMS['strength'][0] * 0.8, HUMAN_PARAMS['strength'][1] * 1.2 ]) self.ax3 = self.fig.add_subplot(3, 2, 3) self.ax3.set_title('Average Skin thickness') self.ax3.set_ylim([ HUMAN_PARAMS['skin_thickness'][0] * 0.8, HUMAN_PARAMS['skin_thickness'][1] * 1.2 ]) self.ax4 = self.fig.add_subplot(3, 2, 4) self.ax4.set_title('Average Total Reach') self.ax4.set_ylim([1 * 0.8, 2.5 * 1.2]) self.ax5 = self.fig.add_subplot(3, 2, 5) self.ax5.set_title('Individuals fitting') self.ax5.set_ylim([ (get_population_size() * 0.9) - get_population_size(), get_population_size() * 1.1 ]) self.ax6 = self.fig.add_subplot(3, 2, 6) else: ind = 1 num_attrs = len(environment.data.keys()) num_rows = int((num_attrs + 2) / 2) + 1 num_cols = 2 for key, val in environment.data.items(): self.__setattr__(key, self.fig.add_subplot(num_rows, num_cols, ind)) self.__getattribute__(key).set_title(key) self.__getattribute__(key).set_ylim([ GENERIC_PARAMS[key][0] * 0.8, GENERIC_PARAMS[key][1] * 1.2 ]) ind += 1 self.fitting = self.fig.add_subplot(num_rows, num_cols, ind) self.fitting.set_title('Individuals fitting') self.fitting.set_ylim([ (get_population_size() * 0.9) - get_population_size(), get_population_size() * 1.1 ]) self.data = self.fig.add_subplot(num_rows, num_cols, ind + 1) plt.xlabel("Iterations") plt.tight_layout() plt.gcf().subplots_adjust(bottom=0.08, right=0.9, left=0.1, top=0.9)
def __init__(self, environment, iteration): if is_generic(): self.averages = {} for param, _ in GENERIC_PARAMS.items(): self.averages[param] = 0 self.averages['fitting'] = 0 self.averages['value'] = 0 else: self.averages = { 'speed': 0, 'strength': 0, 'skin': 0, 'total_reach': 0, 'fitting': 0, 'value': 0 } self.environment = environment self.iteration = iteration
def obtain_params(index): """ This method creates an individual for the first iteration, by randomly obtaining values in a defined range for each parameters, and assigning an age and initial iteration :param index: individual index :type index: int :return: the individual containing all its parameters :rtype: dict """ params = { '_id': index, 'age': int(index / (get_population_size() / 5)) + 1, 'value': 0 } individual_params = dict(GENERIC_PARAMS) if is_generic() else dict( HUMAN_PARAMS) for k, v in individual_params.items(): params[k] = round(random.uniform(v[0], v[1]), 3) return params
async def obtain_children(index, iteration, individual1_ind, individual2_ind, current_population, filtered_coll): """ This method takes the indexes of the new child parents, obtains the parents parameters, and creates the new child parameters from the average of each of the parents parameters, adding a small mutation factor :param index: _id of the new children :type index: int :param iteration: current iteration :type iteration: int :param individual1_ind: parent 1 _id :type individual1_ind: int :param individual2_ind: parent 1 _id :type individual2_ind: int :param current_population: individuals to reproduce :type current_population: list or DBWrapper :param filtered_coll: name of the filtered collection :type filtered_coll: str :return: obtained child or _id of the new child :rtype: dict or int """ ind1 = current_population[filtered_coll][individual1_ind] ind2 = current_population[filtered_coll][individual2_ind] child = dict() child['_id'] = index child['age'] = int((index - int(get_population_size()*0.6)) / int(get_population_size()*0.6 / 5)) \ + iteration \ + 1 mutation_factor = get_mutation_factor() PARAMS_TO_READ = GENERIC_PARAMS if is_generic() else HUMAN_PARAMS for parameter, value in ind1.items(): if parameter != '_id' and parameter != 'age' and parameter != 'value': child[parameter] = round( float(np.clip( (ind1[parameter] + ind2[parameter]) / 2 * random.uniform(1 - mutation_factor, 1 + mutation_factor), PARAMS_TO_READ[parameter][0] * 0.8, PARAMS_TO_READ[parameter][1] * 1.2)), 3 ) child['value'] = 0 reproduction_collection = f'{"_".join(filtered_coll.split("_")[:-1])}_{"reproduction"}' current_population[reproduction_collection].append(child) return index
def add_data(self, results, iteration): """ This method adds the points to plot for the current iteration :param results: object containing the iteration average results :type results: dict :param iteration: current iteration :type iteration: int """ if not is_generic(): self.ax1.scatter(iteration, results['speed'], color='r', s=3) self.ax2.scatter(iteration, results['strength'], color='g', s=3) self.ax3.scatter(iteration, results['skin'], color='b', s=3) self.ax4.scatter(iteration, results['total_reach'], color='c', s=3) self.ax5.scatter(iteration, results['fitting'], color='k', s=3) else: for key, val in results.items(): if key != 'value' and key != 'age' and key != '_id': self.__getattribute__(key).scatter(iteration, results[key], color='r', s=3) self.fitting.scatter(iteration, results['fitting'], color='k', s=3)
def analyze_population(self, current_population, environment_name, iteration): """ This method obtains the averages for the current iteration individuals and saves the results to be plot :param current_population: current set of individuals :type current_population: list or DBWrapper :param environment_name: the current parameters against which the individuals are being tested :type environment_name: str :param iteration: current iteration :type iteration: int """ coll_name = f'{environment_name}_{iteration + 1}' if not is_generic(): total_speed = 0 total_strength = 0 total_skin = 0 total_reach = 0 total_value = 0 to_evaluate = 0 total_fitting = 0 for individual in current_population[coll_name]: total_speed += individual['speed'] total_strength += individual['strength'] total_skin += individual['skin_thickness'] if 'value' in individual: total_value += individual['value'] to_evaluate += 1 reach = individual['height'] + individual['arm_length'] + individual['jump'] total_reach += reach if (reach > self.environment['tree_height'] or (individual['speed'] > self.environment['food_animals_speed'] and individual['strength'] > self.environment['food_animals_strength'])) and \ is_fast_enough(individual, self.environment) and \ is_warm_enough(individual, self.environment): total_fitting += 1 self.averages = { 'speed': total_speed / get_population_size(), 'strength': total_strength / get_population_size(), 'skin': total_skin / get_population_size(), 'total_reach': total_reach / get_population_size(), 'value': total_value / to_evaluate, 'fitting': total_fitting } else: total_value = 0 evaluated = 0 for individual in current_population[coll_name]: fits = True for param, value in individual.items(): if param != '_id' and param != 'age' and param != 'value': self.averages[param] += value if fits and \ not (GENERIC_ENVIRONMENT_DEFAULT[param]-2 < value < GENERIC_ENVIRONMENT_DEFAULT[param]+2): fits = False if param == 'value': total_value += value evaluated += 1 if fits: self.averages['fitting'] += 1 self.averages['value'] = total_value / max(evaluated, 1) for param, value in GENERIC_PARAMS.items(): self.averages[param] = self.averages[param] / get_population_size() my_plot.add_data(self.averages, self.iteration)