-
-
Notifications
You must be signed in to change notification settings - Fork 463
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Additive random mutation with gene_space
low
and high
#229
Comments
My default approach to this would be to use rejection sampling and Gaussian noise, but I'm not sure how well it aligns with the methods currently used for additive random mutations in PyGAD, which seem to rely on uniform sampling from a fixed range. I suggest:
Let me know if you'd be happy with this and I'll submit a PR. Example code: def mutate(offspring: np.ndarray, ga_instance: pygad.GA) -> np.ndarray:
"""Apply random Gaussian noise to a proportion of genes in the offspring.
Parameters
----------
offspring : np.ndarray
Array of shape (sol_per_pop, num_genes) containing the offspring.
ga_instance : pygad.GA
Instance of the GA class
"""
# Convert the bounds to numpy arrays
lower_bounds = np.tile(
np.array([b["low"] for b in ga_instance.gene_space]), (offspring.shape[0], 1)
)
upper_bounds = np.tile(
np.array([b["high"] for g in ga_instance.gene_space]), (offspring.shape[0], 1)
)
# Select the genes to mutate
# This generates a boolean array of the same shape as offspring, with True for each gene that will be mutated
genes_to_mutate = rng.random(offspring.shape) < ga_instance.mutation_probability
print("Total genes to mutate: ", np.sum(genes_to_mutate))
# Generate random values to add to the selected genes
# Use rejection sampling to ensure that the mutated genes remain within the bounds
remaining_genes_to_mutate = genes_to_mutate[:]
while np.any(remaining_genes_to_mutate):
print("Remaining genes to mutate: ", np.sum(remaining_genes_to_mutate))
# Generate candidate mutated values
# This generates an array of floats with the same shape as offspring
candidate_values = rng.normal(
loc=offspring, scale=ga_instance.mutation_noise_variance, size=offspring.shape
)
# Accept only the candidates that are within the bounds
candidate_is_valid = (candidate_values >= lower_bounds) & (
candidate_values <= upper_bounds
)
# Accept only the candidates that are yet to be accepted
candidate_is_valid &= remaining_genes_to_mutate
# Update the remaining genes to mutate
remaining_genes_to_mutate &= ~candidate_is_valid
# Update the offspring array
offspring = np.where(candidate_is_valid, candidate_values, offspring)
return offspring
``` |
You are right. But this should be supported without adding additional parameters. The 2 parameters:
should be used to generate the random value. |
Release Date 29 January 2024 1. Solve bugs when multi-objective optimization is used. #238 2. When the `stop_ciiteria` parameter is used with the `reach` keyword, then multiple numeric values can be passed when solving a multi-objective problem. For example, if a problem has 3 objective functions, then `stop_criteria="reach_10_20_30"` means the GA stops if the fitness of the 3 objectives are at least 10, 20, and 30, respectively. The number values must match the number of objective functions. If a single value found (e.g. `stop_criteria=reach_5`) when solving a multi-objective problem, then it is used across all the objectives. #238 3. The `delay_after_gen` parameter is now deprecated and will be removed in a future release. If it is necessary to have a time delay after each generation, then assign a callback function/method to the `on_generation` parameter to pause the evolution. 4. Parallel processing now supports calculating the fitness during adaptive mutation. #201 5. The population size can be changed during runtime by changing all the parameters that would affect the size of any thing used by the GA. For more information, check the [Change Population Size during Runtime](https://pygad.readthedocs.io/en/latest/pygad_more.html#change-population-size-during-runtime) section. #234 6. When a dictionary exists in the `gene_space` parameter without a step, then mutation occurs by adding a random value to the gene value. The random vaue is generated based on the 2 parameters `random_mutation_min_val` and `random_mutation_max_val`. For more information, check the [How Mutation Works with the gene_space Parameter?](https://pygad.readthedocs.io/en/latest/pygad_more.html#how-mutation-works-with-the-gene-space-parameter) section. #229 7. Add `object` as a supported data type for int (GA.supported_int_types) and float (GA.supported_float_types). #174 8. Use the `raise` clause instead of the `sys.exit(-1)` to terminate the execution. #213 9. Fix a bug when multi-objective optimization is used with batch fitness calculation (e.g. `fitness_batch_size` set to a non-zero number). 10. Fix a bug in the `pygad.py` script when finding the index of the best solution. It does not work properly with multi-objective optimization where `self.best_solutions_fitness` have multiple columns.
In the docs, it says that:
However, if a
gene_space
is defined as a dict withlow
andhigh
parameters, it should be possible to generate additive mutations, so thatnew_value = old_value + random_value
, rather thannew_value = random_value
.I had a brief look in the source code, and this wasn't supported at the moment.
The text was updated successfully, but these errors were encountered: