Ejemplo n.º 1
0
 def test_filter_individuals(self):
     set_db()
     environment_params = {
         'tree_height': 1.0,
         'temperature': 20.0,
         'predators_speed': 10.0,
         'food_animals_speed': 10.0,
         'food_animals_strength': 1.0
     }
     environment = Environment('Bla', environment_params)
     population = DataWrapper()
     collection = []
     for i in range(0, get_population_size() + 50):
         ind = {
             'height': 1,
             'arm_length': 0,
             'speed': 10,
             'strength': i,
             'jump': 0,
             'skin_thickness': 0.05,
             'total_reach': 2
         }
         collection.append(ind)
     population['Bla_1'] = collection
     filtered_individuals = filter_individuals(population, environment, 1)
     self.assertEqual(len(filtered_individuals['Bla_1_filtered']), int(get_population_size() * 0.6))
     rand_pos = random.randint(0, 49)
     self.assertGreater(filtered_individuals['Bla_1'][rand_pos+1]['strength'],
                        filtered_individuals['Bla_1'][rand_pos]['strength'])
Ejemplo n.º 2
0
 def test_obtain_randomized_individuals(self):
     my_indivs = obtain_randomized_pairs(int(get_population_size() * 0.6))
     self.assertEqual(len(my_indivs), int(get_population_size() * 0.3))
     for ind1, i in enumerate(my_indivs):
         for ind2, j in enumerate(my_indivs):
             if ind1 != ind2 and i == j:
                 raise Exception
Ejemplo n.º 3
0
async def pair_individuals(current_population, list_of_pairs, iteration, filtered_coll):
    """
    This method creates the asynchronous tasks to obtain two childs for each pair of parents
    :param current_population: individuals to reproduce
    :type current_population: list or DBWrapper
    :param list_of_pairs: list of randomized pairs
    :type list_of_pairs: list of tuples of 2 ints
    :param iteration: current iteration
    :type iteration: int
    :param filtered_coll: name of the filtered collection
    :type filtered_coll: str
    :return: list of the obtained children or list of _id's of the new children
    :rtype: list of dicts or list of ints
    """
    tasks = []
    for ind, pair in enumerate(list_of_pairs):
        for step in [0, int(get_population_size() * 0.3)]:
            tasks.append(
                asyncio.ensure_future(
                    obtain_children(ind + int(get_population_size() * 0.6) + step,
                                    iteration,
                                    pair[0],
                                    pair[1],
                                    current_population,
                                    filtered_coll
                                    )
                )
            )
    responses = await asyncio.gather(*tasks)
    return responses
Ejemplo n.º 4
0
def reproduction_stage(iteration, current_population, environment_name):
    """
    This method pairs random individuals, obtains their children, and adds them to the population
    :param iteration: current iteration
    :type iteration: int
    :param current_population: set of individuals to reproduce
    :type current_population: list or MongoWrapper
    :param environment_name:
    :type environment_name:
    :return: resulting set of individuals after reproduction stage
    :rtype: list or DBWrapper
    """
    filtered_coll = f'{environment_name}_{iteration}_filtered'
    reproduce_coll = f'{environment_name}_{iteration}_reproduction'
    if is_elitist():
        individuals_pairs = obtain_randomized_pairs(int(get_population_size() * 0.6))
    else:
        individuals_pairs = obtain_ordered_pairs(int(get_population_size() * 0.6))
    new_iter_individuals = obtain_pairs_of_individuals(
        current_population,
        individuals_pairs,
        filtered_coll
    )
    newly_created_individuals = asyncio.run(pair_individuals(current_population,
                                                             individuals_pairs,
                                                             iteration,
                                                             filtered_coll))
    logging.debug(f"Created {len(newly_created_individuals)} new individuals")
    current_population[reproduce_coll].extend(new_iter_individuals)
    return current_population
 def test_natural_death(self):
     set_db()
     population = DataWrapper()
     collection = []
     for i in range(0, get_population_size() + 100):
         ind = {
             'age': i % 5,
             'height': 1,
             'arm_length': 0,
             'speed': 10,
             'strength': 1,
             'jump': 0,
             'skin_thickness': 0.05
         }
         collection.append(ind)
     population['Bla_1_reproduction'] = collection
     new_pop = natural_death(1, population, 'Bla')
     self.assertEqual(len(new_pop['Bla_2']), get_population_size())
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
 def check_converged(self, prev_analysis):
     """
     This method checks if the current iteration individuals have changed much compared to the previous
     iteration individuals
     :param prev_analysis: the previous iteration individuals average parameters
     :type prev_analysis: PopulationAnalysis object
     :return: true if the current iteration individual parameters are really similar to the previous one. false
     otherwise
     :rtype: boolean
     """
     if self.averages['value'] >= 0.7:
         if self.averages['fitting'] >= int(get_population_size() * 0.80):
             total_dif = 0
             for key, val in self.averages.items():
                 total_dif += abs(val - prev_analysis.averages[key])
             if total_dif < 1:
                 return True
         if self.averages['fitting'] >= int(get_population_size() * 0.95):
             return True
     return False
Ejemplo n.º 8
0
 def test_obtain_randomized_pair_of_individuals(self):
     num_inds = 6000
     individuals = []
     for i in range(0, num_inds):
         indiv = {
             'height': 1,
             'arm_length': 2,
             'speed': 3,
             'strength': 4,
             'jump': 5,
             'skin_thickness': 6
         }
         individuals.append(indiv)
     curr_pop = {'bla_1_filtered': individuals}
     my_pairs = obtain_randomized_pairs(num_inds)
     new_indivs = obtain_pairs_of_individuals(curr_pop, my_pairs,
                                              'bla_1_filtered')
     self.assertEquals(len(my_pairs), int(get_population_size() * 0.3))
     self.assertEquals(len(new_indivs), int(get_population_size() * 0.6))
     self.assertTrue('_id' in new_indivs[0])
     for pair in my_pairs:
         self.assertTrue(len(pair) == 2)
Ejemplo n.º 9
0
def filter_individuals(current_population, environment, iteration):
    """
    Main filter method
    :param current_population: set of individuals to test against the environment
    :type current_population: list or DBWrapper
    :param environment: the current parameters against which the individuals are being tested
    :type environment: Environment
    :param iteration: current iteration
    :type iteration: int
    :return: resulting set of individuals after filtering stage
    :rtype: list or DBWrapper
    """
    filtered_collection = f'{environment.name}_{iteration}_{"filtered"}'
    _ = asyncio.run(create_evaluation_tasks(current_population, environment, iteration))
    current_population[filtered_collection].sort(key=operator.itemgetter('value'), reverse=True)
    deleted = 0
    for idx, item in enumerate(current_population[filtered_collection]):
        if idx < int(get_population_size() * 0.4):
            current_population[filtered_collection].pop(get_population_size() - idx - 1)
            deleted += 1
    logging.debug(f"Deleted {int(get_population_size() * 0.4)} individuals")
    return current_population
Ejemplo n.º 10
0
def create_individuals(environment_name):
    """
    This method creates the initial set of individuals that will be tested against the environment
    :param environment_name: name of the environment
    :type environment_name: str
    :return: resulting set of individuals
    :rtype: list or DBWrapper
    """
    current_population = return_db()
    for index in range(0, get_population_size()):
        params = obtain_params(index)
        current_population[f'{environment_name}_{1}'].append(params)
    logging.debug(
        f"Created a starting set of {get_population_size()} individuals")
    return current_population
Ejemplo n.º 11
0
def obtain_randomized_pairs(current_population_len):
    """
    This method obtains a randomized pairs list containing all current individuals
    :param current_population_len: total number of individuals to randomize
    :type current_population_len: int
    :return: the resulting list of randomized pairs
    :rtype: list of tuples of 2 ints
    """
    random_individuals = [i for i in range(0, current_population_len)]
    random.shuffle(random_individuals)
    random_pairs = []
    for i in range(0, int(get_population_size() * 0.3)):
        ind1 = random_individuals.pop()
        ind2 = random_individuals.pop()
        random_pairs.append((ind1, ind2))
    return random_pairs
Ejemplo n.º 12
0
    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)
Ejemplo n.º 13
0
async def create_evaluation_tasks(current_population, environment, iteration):
    """
    Creates a task for each individual and waits for the result
    :param current_population: set of individuals to test against the environment
    :type current_population: list or DBWrapper
    :param environment: the current parameters against which the individuals are being tested
    :type environment: dict
    :param iteration: current iteration
    :type iteration: int
    :return: pairs of individuals with their values
    :rtype: list of tuples of floats
    """
    tasks = [
        asyncio.ensure_future(evaluate_individual(current_population, individual_id, environment, iteration))
        for individual_id in range(0, get_population_size())
    ]
    responses = await asyncio.gather(*tasks)
    return responses
Ejemplo n.º 14
0
def mongo_obtain_pairs_of_individuals(current_population, filtered_population, individuals_pairs):
    """
    This method inserts the reproduction stage 'parents' into the new collection
    :param current_population: individuals to reproduce
    :type current_population: DBWrapper instance
    :param filtered_population: the specific population to be reproduced
    :type filtered_population: MongoCollectionWrapper instance
    :param individuals_pairs: list of pairs
    :type individuals_pairs: list of tuples of 2 ints
    :return: list of randomized pairs
    :rtype: list of tuples of 2 ints
    """
    for index, individual_pair in enumerate(individuals_pairs):
        for index2, step in enumerate([0, int(get_population_size() * 0.3)]):
            individual = filtered_population[individual_pair[index2]]
            individual['_id'] = index
            current_population.current_collection.insert_one(individual)
    return individuals_pairs
Ejemplo n.º 15
0
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
Ejemplo n.º 16
0
def natural_death(iteration, current_population, environment_name):
    """
    Kill all individuals which have as age the current iteration.
    :param iteration: current iteration
    :type iteration: int
    :param current_population: Object containing the individuals collections
    :type current_population: DBWrapper
    :param environment_name: the current parameters against which the individuals are being tested
    :type environment_name: str
    :return: the individuals that survived the filtering stage
    :rtype: list or DBWrapper
    """
    coll_to_trim = current_population[f'{environment_name}_{iteration}_{"reproduction"}']
    new_col = current_population[f'{environment_name}_{iteration + 1}']
    coll_to_trim.sort(key=operator.itemgetter('age'), reverse=True)
    for idx, individual in enumerate(coll_to_trim):
        if idx < get_population_size():
            individual['_id'] = idx
            new_col.append(individual)
    return current_population
Ejemplo n.º 17
0
def obtain_pairs_of_individuals(current_population, individuals_pairs, filtered_coll):
    """
    This method inserts the reproduction stage 'parents' into the new collection
    :param current_population: individuals to reproduce
    :type current_population: list
    :param individuals_pairs: list of pairs
    :type individuals_pairs: list of tuples of 2 ints
    :param filtered_coll: name of the filtered collection
    :type filtered_coll: str
    :return: parents added to a new list
    :rtype: list of dicts
    """
    new_iter_individuals = []
    for index, individual_pair in enumerate(individuals_pairs):
        ind1 = current_population[filtered_coll][individual_pair[0]]
        ind1['_id'] = index
        new_iter_individuals.append(ind1)
        ind2 = current_population[filtered_coll][individual_pair[1]]
        ind2['_id'] = index + int(get_population_size() * 0.3)
        new_iter_individuals.append(ind2)
    return new_iter_individuals
Ejemplo n.º 18
0
 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)
Ejemplo n.º 19
0
    async def async_obtain_children(self, indiv1_ind, indiv2_ind):
        set_db()
        rand_idx = random.randint(0, get_population_size())
        rand_iter = random.randint(0, get_population_size())

        indiv1_rand_height = random.uniform(HUMAN_PARAMS['height'][0],
                                            HUMAN_PARAMS['height'][1])
        indiv2_rand_height = random.uniform(HUMAN_PARAMS['height'][0],
                                            HUMAN_PARAMS['height'][1])
        indiv1_arm_length = random.uniform(HUMAN_PARAMS['arm_length'][0],
                                           HUMAN_PARAMS['arm_length'][1])
        indiv2_arm_length = random.uniform(HUMAN_PARAMS['arm_length'][0],
                                           HUMAN_PARAMS['arm_length'][1])
        indiv1_speed = random.uniform(HUMAN_PARAMS['speed'][0],
                                      HUMAN_PARAMS['speed'][1])
        indiv2_speed = random.uniform(HUMAN_PARAMS['speed'][0],
                                      HUMAN_PARAMS['speed'][1])
        indiv1_strength = random.uniform(HUMAN_PARAMS['strength'][0],
                                         HUMAN_PARAMS['strength'][1])
        indiv2_strength = random.uniform(HUMAN_PARAMS['strength'][0],
                                         HUMAN_PARAMS['strength'][1])
        indiv1_jump = random.uniform(HUMAN_PARAMS['jump'][0],
                                     HUMAN_PARAMS['jump'][1])
        indiv2_jump = random.uniform(HUMAN_PARAMS['jump'][0],
                                     HUMAN_PARAMS['jump'][1])
        indiv1_skin_thickness = random.uniform(
            HUMAN_PARAMS['skin_thickness'][0],
            HUMAN_PARAMS['skin_thickness'][1])
        indiv2_skin_thickness = random.uniform(
            HUMAN_PARAMS['skin_thickness'][0],
            HUMAN_PARAMS['skin_thickness'][1])
        indiv1 = {
            'height': indiv1_rand_height,
            'arm_length': indiv1_arm_length,
            'speed': indiv1_speed,
            'strength': indiv1_strength,
            'jump': indiv1_jump,
            'skin_thickness': indiv1_skin_thickness
        }

        indiv2 = {
            'height': indiv2_rand_height,
            'arm_length': indiv2_arm_length,
            'speed': indiv2_speed,
            'strength': indiv2_strength,
            'jump': indiv2_jump,
            'skin_thickness': indiv2_skin_thickness
        }
        current_population = DataWrapper()
        current_population["test_pop"] = [indiv1, indiv2]
        new_child = [
            asyncio.ensure_future(
                obtain_children(rand_idx, rand_iter, indiv1_ind, indiv2_ind,
                                current_population, "test_pop"))
        ]
        _ = await asyncio.gather(*new_child)
        new_child = current_population["test_reproduction"][0]
        self.assertTrue(
            new_child['height'] > (indiv1['height'] + indiv2['height']) / 2 -
            ((indiv1['height'] + indiv2['height']) * mutation_factor))
        self.assertTrue(
            new_child['height'] < (indiv1['height'] + indiv2['height']) / 2 +
            ((indiv1['height'] + indiv2['height']) * mutation_factor))
        self.assertTrue(
            new_child['arm_length'] >
            (indiv1['arm_length'] + indiv2['arm_length']) / 2 -
            ((indiv1['arm_length'] + indiv2['arm_length']) * mutation_factor))
        self.assertTrue(
            new_child['arm_length'] <
            (indiv1['arm_length'] + indiv2['arm_length']) / 2 +
            ((indiv1['arm_length'] + indiv2['arm_length']) * mutation_factor))
        self.assertTrue(
            new_child['speed'] > (indiv1['speed'] + indiv2['speed']) / 2 -
            ((indiv1['speed'] + indiv2['speed']) * mutation_factor))
        self.assertTrue(
            new_child['speed'] < (indiv1['speed'] + indiv2['speed']) / 2 +
            ((indiv1['speed'] + indiv2['speed']) * mutation_factor))
        self.assertTrue(
            new_child['strength'] >
            (indiv1['strength'] + indiv2['strength']) / 2 -
            ((indiv1['strength'] + indiv2['strength']) * mutation_factor))
        self.assertTrue(
            new_child['strength'] <
            (indiv1['strength'] + indiv2['strength']) / 2 +
            ((indiv1['strength'] + indiv2['strength']) * mutation_factor))
        self.assertTrue(
            new_child['jump'] > (indiv1['jump'] + indiv2['jump']) / 2 -
            ((indiv1['jump'] + indiv2['jump']) * mutation_factor))
        self.assertTrue(
            new_child['jump'] < (indiv1['jump'] + indiv2['jump']) / 2 +
            ((indiv1['jump'] + indiv2['jump']) * mutation_factor))
        self.assertTrue(
            new_child['skin_thickness'] >
            (indiv1['skin_thickness'] + indiv2['skin_thickness']) / 2 -
            ((indiv1['skin_thickness'] + indiv2['skin_thickness']) *
             mutation_factor))
        self.assertTrue(
            new_child['skin_thickness'] <
            (indiv1['skin_thickness'] + indiv2['skin_thickness']) / 2 +
            ((indiv1['skin_thickness'] + indiv2['skin_thickness']) *
             mutation_factor))
        return 1