예제 #1
0
def get_individuals():
    individuals = [
        Individual(params=[1.0, 0.1, -0.5, 4.3, 2.4],
                   reax_energies=[43.2, 10.6, -174.2, 1008.4]),
        Individual(params=[0.5, 0.05, -0.76, 8.6, 2.1],
                   reax_energies=[56.9, 11.2, -164.1, 994.8]),
        Individual(params=[1.24, 0.17, -0.07, 6.3, 2.24],
                   reax_energies=[102.4, 5.5, -155.5, 1008.12]),
        Individual(params=[0.73, 0.25, -0.25, 10.2, 1.7],
                   reax_energies=[40.2, 11.2, -104.1, 1018.32]),
    ]
    return individuals
예제 #2
0
    def crossover(parent1: Individual, parent2: Individual,
                  root_individual: RootIndividual,
                  **kwargs) -> Tuple[Individual, Individual]:
        """Execute uniform crossover. Take the ith row of parent1 and randomly swap bits with the ith row of p2."""
        sieve = np.random.randint(2, size=len(
            parent1.params))  # Array of 0's and 1's
        not_sieve = sieve ^ 1  # Complement of sieve

        child1 = Individual(list(parent1.params * sieve +
                                 parent2.params * not_sieve),
                            root_individual=root_individual)
        child2 = Individual(list(parent1.params * not_sieve +
                                 parent2.params * sieve),
                            root_individual=root_individual)

        return child1, child2
예제 #3
0
def test_individual_from_root_individual(root_individual):
    individual_from_root = Individual.from_root_individual(root_individual)
    assert isinstance(individual_from_root, Individual)
    assert individual_from_root.params == root_individual.root_params
    assert individual_from_root.reax_energies is None
    assert individual_from_root.ffield is not None
    assert individual_from_root.cost is None
예제 #4
0
    def get_population(self, generation_number: int) -> Tuple[List[Individual], List[int]]:
        generation_dir_path = os.path.join(self.population_path, self.GENERATION_FOLDER_PREFIX + str(generation_number))
        root_individual = self.get_root_individual()

        population = []
        successfully_retrieved_case_numbers = []
        for case_number in range(self.population_size):
            child_dir = os.path.join(generation_dir_path, self.INDIVIDUAL_FOLDER_PREFIX + str(case_number))
            self.population_reax_reader.dir_path = child_dir

            try:
                child_fort99_data = self.population_reax_reader.read_fort99()
                child_ffield, _ = self.population_reax_reader.read_ffield()
                child_params = [get_param(key, child_ffield) for key in self.param_keys]

                fort99_extractor = Fort99Extractor(child_fort99_data)
                child_reax_energies = fort99_extractor.get_reax_energies()

                # noinspection PyTypeChecker
                child = Individual(child_params, child_reax_energies, root_individual, error_calculator=ReaxError)

                population.append(child)
                successfully_retrieved_case_numbers.append(case_number)

            except FileNotFoundError:
                # 'fort.99' file does not exist
                print("fort.99 not found in '{}'...continuing to next case".format(child_dir))
                continue
            except ValueError:
                # Invalid number of columns in fort.99 -> skip and continue to next case
                # TODO: Log
                continue

        return population, successfully_retrieved_case_numbers
예제 #5
0
    def crossover(parent1: Individual, parent2: Individual,
                  root_individual: RootIndividual,
                  **kwargs) -> Tuple[Individual, Individual]:
        """Execute single-point crossover. Cut the parameter vectors from two children at random positions
        and join to yield two new vectors (children).

        :param parent1: The first individual participating in crossover.
        :param parent2: The second individual participating in crossover.
        :return: Two new Children generated from the mating/crossover.
        """
        choice = random.randrange(0, len(parent1.params))
        child1 = Individual(parent1.params[:choice] + parent2.params[choice:],
                            root_individual=root_individual)
        child2 = Individual(parent2.params[:choice] + parent1.params[choice:],
                            root_individual=root_individual)
        return child1, child2
예제 #6
0
 def crossover(parent1: Individual, parent2: Individual,
               root_individual: RootIndividual,
               **kwargs) -> Tuple[Individual, Individual]:
     """Execute two-point crossover."""
     idx = random.sample(len(parent1.params), 2)
     smaller_id = min(idx)
     bigger_id = max(idx)
     child1 = Individual(parent1.params[:smaller_id] +
                         parent2.params[smaller_id:bigger_id] +
                         parent1.params[bigger_id:],
                         root_individual=root_individual)
     child2 = Individual(parent2.params[:smaller_id] +
                         parent1.params[smaller_id:bigger_id] +
                         parent2.params[bigger_id:],
                         root_individual=root_individual)
     return child1, child2
예제 #7
0
    def crossover(parent1: Individual, parent2: Individual,
                  root_individual: RootIndividual,
                  **kwargs) -> Tuple[Individual, Individual]:
        """Double Pareto crossover from Thakur's 2014 - "A new GA for global optimization of multimodal continuous
        functions."
        NOTE: Thakur is unclear about modified beta if/then command.
        I have ASSUMED the following:
        if u >= 1/2:
            >> use first expression
        else: (u < 1/2):
            >> use second expression
        This SHOULD be correct, as x = 0 corresponds to f(x), which is the Pareto density function, equal to 0.5!
        """
        alpha = kwargs.get('dpx_alpha', 10)
        beta = kwargs.get('dpx_beta', 1)

        child1_params = []
        child2_params = []
        for parent1_param, parent2_param in zip(parent1.params,
                                                parent2.params):
            u = random.uniform(0, 1)
            if u >= 1 / 2:
                modified_beta = alpha * beta * (1 - (2 * u)**(-1 / alpha))
            else:
                modified_beta = alpha * beta * ((1 -
                                                 (2 * u))**(-1 / alpha) - 1)

            child1_param = (
                (parent1_param + parent2_param) +
                modified_beta * abs(parent1_param - parent2_param)) / 2
            child2_param = (
                (parent1_param + parent2_param) -
                modified_beta * abs(parent1_param - parent2_param)) / 2

            child1_params.append(child1_param)
            child2_params.append(child2_param)

        child1 = Individual(child1_params, root_individual=root_individual)
        child2 = Individual(child2_params, root_individual=root_individual)
        return child1, child2
 def mutation(parent: Individual, root_individual: RootIndividual,
              **kwargs) -> Individual:
     """Inspired by Monte Carlo/GA guidelines for ReaxFF paper.
     Use a random number (determined by uniform distribution) in the central segment for each parameter range.
     So, if a parameter has a range of [p_min, p_max], a uniform random number will be generated in the bounds
     [p_min + (p_max - p_min)/4, p_max - (p_max - p_min)/4].
     Mutates all parameters (doesn't consider `FRAC_PARAMS_MUTATE`).
     """
     param_bounds = kwargs['param_bounds']
     new_params = []
     for (lower_bound, upper_bound) in param_bounds:
         delta = (upper_bound - lower_bound) / 4
         new_param = random.uniform(lower_bound + delta,
                                    upper_bound - delta)
         new_params.append(new_param)
     return Individual(new_params, root_individual=root_individual)
예제 #9
0
 def mutation(parent: Individual, root_individual: RootIndividual,
              **kwargs) -> Individual:
     """Polynomial mutation adapted from Deb and Agrawal's paper.
     ADAPTED TO FUNCTION WITHOUT UPPER/LOWER BOUNDS FOR PARAMETERS.
     """
     eta = kwargs.get('polynomial_eta', 60)
     poly_degree = 1 / (1 + eta)
     new_params = []
     for param in parent.params:
         u = random.random()
         if u <= 0.5:
             delta_l = (2 * u)**poly_degree - 1
             param = param + delta_l * param
         else:
             delta_r = 1 - (2 * (1 - u))**poly_degree
             param = param + delta_r * param
         new_params.append(param)
     return Individual(new_params, root_individual=root_individual)
예제 #10
0
    def mutation(parent: Individual, root_individual: RootIndividual,
                 **kwargs) -> Individual:
        """Mutate Child's `params` using Nakata's methodology.
        new_param = old_param + (scale * rand_num * old_param).

        `scale` can be float or List with len(`scale`) = len(self.params),
        e.g., when using param_increments is desired.
        param_bounds are currently being used as (min, max) conditions for params, if they exist.
        if param is outside param_bounds, param is set using uniform distribution with (min, max) bounds.

        :return: New Individual after mutation.
        """
        scale = kwargs.get('nakata_scale', 0.1)
        low = kwargs.get('nakata_rand_lower', -1.0)
        high = kwargs.get('nakata_rand_higher', 1.0)
        new_params = [
            param + (scale * random.uniform(low, high) * param)
            for param in parent.params
        ]
        return Individual(new_params, root_individual=root_individual)
예제 #11
0
 def mutation(parent: Individual, root_individual: RootIndividual,
              **kwargs) -> Individual:
     """UNCONSTRAINED Gaussian mutation.
     Upper and lower bounds are not required for this version.
     Allows usage of multiple scaling factors for the normal distribution for mutation.
     Each scaling factor needs a corresponding probability (gauss_frac) of using that given factor.
     """
     stds = kwargs.get('gauss_std', [0.1])
     probabilities = kwargs.get('gauss_frac', [1.0])
     u = random.uniform(0, 1)
     cumulative_probability = 0
     for std, probability in zip(stds, probabilities):
         if cumulative_probability < u <= (cumulative_probability +
                                           probability):
             new_params = [
                 param + param * random.gauss(0, std)
                 for param in parent.params
             ]
             break
         cumulative_probability += probability
     return Individual(new_params, root_individual=root_individual)
예제 #12
0
def test_individual_init():
    params = [0.5, 0.4, 1.0, -4.7, 8.6]
    reax_energies = [43.2, 10.6, -174.2, 1008.4]
    individual = Individual(params=params, reax_energies=reax_energies)
    assert individual.params == params
    assert individual.reax_energies == reax_energies
예제 #13
0
def individual():
    params = [0.5, 0.4, 1.0, -4.7, 8.6]
    reax_energies = [43.2, 10.6, -174.2, 1008.4]
    individual = Individual(params=params, reax_energies=reax_energies, error_calculator=ReaxError)
    return individual
예제 #14
0
 def execute(self) -> List[Individual]:
     root_individual = self.population_repository.get_root_individual()
     individual = Individual.from_root_individual(root_individual)
     population = [self.strategy.mutation(individual, root_individual, **self.mutation_settings_dict)
                   for _ in range(self.population_size)]
     return population