Releases: ahmedfgad/GeneticAlgorithmPython
Releases · ahmedfgad/GeneticAlgorithmPython
PyGAD-3.5.0
- Fix a bug when minus sign (-) is used inside the
stop_criteria
parameter for multi-objective problems. #314 #323 - Fix a bug when the
stop_criteria
parameter is passed as an iterable (e.g. list) for multi-objective problems (e.g.['reach_50_60', 'reach_20, 40']
). #314 - Call the
get_matplotlib()
function from theplot_genes()
method inside thepygad.visualize.plot.Plot
class to import the matplotlib library. #315 - Create a new helper method called
select_unique_value()
inside thepygad/helper/unique.py
script to select a unique gene from an array of values. - Create a new helper method called
get_random_mutation_range()
inside thepygad/utils/mutation.py
script that returns the random mutation range (min and max) for a single gene by its index. - Create a new helper method called
change_random_mutation_value_dtype
inside thepygad/utils/mutation.py
script that changes the data type of the value used to apply random mutation. - Create a new helper method called
round_random_mutation_value()
inside thepygad/utils/mutation.py
script that rounds the value used to apply random mutation. - Create the
pygad/helper/misc.py
script with a class calledHelper
that has the following helper methods:change_population_dtype_and_round()
: For each gene in the population, round the gene value and change the data type.change_gene_dtype_and_round()
: Round the change the data type of a single gene.mutation_change_gene_dtype_and_round()
: Decides whether mutation is done by replacement or not. Then it rounds and change the data type of the new gene value.validate_gene_constraint_callable_output()
: Validates the output of the user-defined callable/function that checks whether the gene constraint defined in thegene_constraint
parameter is satisfied or not.get_gene_dtype()
: Returns the gene data type from thegene_type
instance attribute.get_random_mutation_range()
: Returns the random mutation range using therandom_mutation_min_val
andrandom_mutation_min_val
instance attributes.get_initial_population_range()
: Returns the initial population values range using theinit_range_low
andinit_range_high
instance attributes.generate_gene_value_from_space()
: Generates/selects a value for a gene using thegene_space
instance attribute.generate_gene_value_randomly()
: Generates a random value for the gene. Only used ifgene_space
isNone
.generate_gene_value()
: Generates a value for the gene. It checks whethergene_space
isNone
and calls eithergenerate_gene_value_randomly()
orgenerate_gene_value_from_space()
.filter_gene_values_by_constraint()
: Receives a list of values for a gene. Then it filters such values using the gene constraint.get_valid_gene_constraint_values()
: Selects one valid gene value that satisfy the gene constraint. It simply callsgenerate_gene_value()
to generate some gene values then it filters such values usingfilter_gene_values_by_constraint()
.
- Create a new helper method called
mutation_process_random_value()
inside thepygad/utils/mutation.py
script that generates constrained random values for mutation. It calls eithergenerate_gene_value()
orget_valid_gene_constraint_values()
based on whether thegene_constraint
parameter is used or not. - A new parameter called
gene_constraint
is added. It accepts a list of callables (i.e. functions) acting as constraints for the gene values. Before selecting a value for a gene, the callable is called to ensure the candidate value is valid. Check the [Gene Constraint](https://pygad.readthedocs.io/en/latest/pygad_more.html#gene-constraint) section for more information. #119 - A new parameter called
sample_size
is added. To select a gene value that respects a constraint, this variable defines the size of the sample from which a value is selected randomly. Useful if eitherallow_duplicate_genes
orgene_constraint
is used. An instance attribute of the same name is created in the instances of thepygad.GA
class. Check the [sample_size Parameter](https://pygad.readthedocs.io/en/latest/pygad_more.html#sample-size-parameter) section for more information. - Use the
sample_size
parameter instead ofnum_trials
in the methodssolve_duplicate_genes_randomly()
andunique_float_gene_from_range()
inside thepygad/helper/unique.py
script. It is the maximum number of values to generate as the search space when looking for a unique float value out of a range. - Fixed a bug in population initialization when
allow_duplicate_genes=False
. Previously, gene values were checked for duplicates before rounding, which could allow near-duplicates like 7.61 and 7.62 to pass. After rounding (e.g., both becoming 7.6), this resulted in unintended duplicates. The fix ensures gene values are now rounded before duplicate checks, preventing such cases. - More tests are created.
- More examples are created.
- Edited the
sort_solutions_nsga2()
method in thepygad/utils/nsga2.py
script to accept an optional parameter calledfind_best_solution
when calling this method just to find the best solution. - Fixed a bug while applying the non-dominated sorting in the
get_non_dominated_set()
method inside thepygad/utils/nsga2.py
script. It was swapping the non-dominated and dominated sets. In other words, it used the non-dominated set as if it is the dominated set and vice versa. All the calls to this method were edited accordingly. #320. - Fix a bug retrieving in the
best_solution()
method when retrieving the best solution for multi-objective problems. #331
PyGAD-3.4.0
- The
delay_after_gen
parameter is removed from thepygad.GA
class constructor. As a result, it is no longer an attribute of thepygad.GA
class instances. To add a delay after each generation, apply it inside theon_generation
callback. #283 - In the
single_point_crossover()
method of thepygad.utils.crossover.Crossover
class, all the random crossover points are returned before thefor
loop. This is by calling thenumpy.random.randint()
function only once before the loop to generate all the K points (where K is the offspring size). This is compared to calling thenumpy.random.randint()
function inside thefor
loop K times, once for each individual offspring. - Bug fix in the
examples/example_custom_operators.py
script. #285 - While making prediction using the
pygad.torchga.predict()
function, no gradients are calculated. - The
gene_type
parameter of thepygad.helper.unique.Unique.unique_int_gene_from_range()
method accepts the type of the current gene only instead of the full gene_type list. - Created a new method called
unique_float_gene_from_range()
inside thepygad.helper.unique.Unique
class to find a unique floating-point number from a range. - Fix a bug in the
pygad.helper.unique.Unique.unique_gene_by_space()
method to return the numeric value only instead of a NumPy array. - Refactoring the
pygad/helper/unique.py
script to remove duplicate codes and reformatting the docstrings. - The plot_pareto_front_curve() method added to the pygad.visualize.plot.Plot class to visualize the Pareto front for multi-objective problems. It only supports 2 objectives. #279
- Fix a bug converting a nested NumPy array to a nested list. #300
- The
Matplotlib
library is only imported when a method inside thepygad/visualize/plot.py
script is used. This is more efficient than usingimport matplotlib.pyplot
at the module level as this causes it to be imported whenpygad
is imported even when it is not needed. #292 - Fix a bug when minus sign (-) is used inside the
stop_criteria
parameter (e.g.stop_criteria=["saturate_10", "reach_-0.5"]
). #296 - Make sure
self.best_solutions
is a list of lists inside thecal_pop_fitness
method. #293 - Fix a bug where the
cal_pop_fitness()
method was using theprevious_generation_fitness
attribute to return the parents fitness. This instance attribute was not using the fitness of the latest population, instead the fitness of the population before the last one. The issue is solved by updating theprevious_generation_fitness
attribute to the latest population fitness before the GA completes. #291
PyGAD 3.3.1
- After the last generation and before the
run()
method completes, update the 2 instance attributes: 1)last_generation_parents
2)last_generation_parents_indices
. This is to keep the list of parents up-to-date with the latest population fitnesslast_generation_fitness
. #275 - 4 methods with names starting with
run_
. Their purpose is to keep the main loop inside therun()
method clean. Check the [Other Methods](https://pygad.readthedocs.io/en/latest/pygad.html#other-methods) section for more information.
PyGAD-3.3.0
Release Date 29 January 2024
- Solve bugs when multi-objective optimization is used. #238
- When the
stop_ciiteria
parameter is used with thereach
keyword, then multiple numeric values can be passed when solving a multi-objective problem. For example, if a problem has 3 objective functions, thenstop_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 - 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 theon_generation
parameter to pause the evolution. - Parallel processing now supports calculating the fitness during adaptive mutation. #201
- 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
- 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 parametersrandom_mutation_min_val
andrandom_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 - Add
object
as a supported data type for int (GA.supported_int_types) and float (GA.supported_float_types). #174 - Use the
raise
clause instead of thesys.exit(-1)
to terminate the execution. #213 - Fix a bug when multi-objective optimization is used with batch fitness calculation (e.g.
fitness_batch_size
set to a non-zero number). - 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 whereself.best_solutions_fitness
have multiple columns.
self.best_solution_generation = numpy.where(numpy.array(
self.best_solutions_fitness) == numpy.max(numpy.array(self.best_solutions_fitness)))[0][0]
PyGAD-3.2.0
- A new module
pygad.utils.nsga2
is created that has theNSGA2
class that includes the functionalities of NSGA-II. The class has these methods: 1)get_non_dominated_set()
2)non_dominated_sorting()
3)crowding_distance()
4)sort_solutions_nsga2()
. Check [this section](https://pygad.readthedocs.io/en/latest/pygad_more.html#multi-objective-optimization) for an example. - Support of multi-objective optimization using Non-Dominated Sorting Genetic Algorithm II (NSGA-II) using the
NSGA2
class in thepygad.utils.nsga2
module. Just return alist
,tuple
, ornumpy.ndarray
from the fitness function and the library will consider the problem as multi-objective optimization. All the objectives are expected to be maximization. Check [this section](https://pygad.readthedocs.io/en/latest/pygad_more.html#multi-objective-optimization) for an example. - The parent selection methods and adaptive mutation are edited to support multi-objective optimization.
- Two new NSGA-II parent selection methods are supported in the
pygad.utils.parent_selection
module: 1) Tournament selection for NSGA-II 2) NSGA-II selection. - The
plot_fitness()
method in thepygad.plot
module has a new optional parameter namedlabel
to accept the label of the plots. This is only used for multi-objective problems. Otherwise, it is ignored. It defaults toNone
and accepts alist
,tuple
, ornumpy.ndarray
. The labels are used in a legend inside the plot. - The default color in the methods of the
pygad.plot
module is changed to the greenish#64f20c
color. - A new instance attribute named
pareto_fronts
added to thepygad.GA
instances that holds the pareto fronts when solving a multi-objective problem. - The
gene_type
accepts alist
,tuple
, ornumpy.ndarray
for integer data types given that the precision is set toNone
(e.g.gene_type=[float, [int, None]]
). - In the
cal_pop_fitness()
method, the fitness value is re-used ifsave_best_solutions=True
and the solution is found in thebest_solutions
attribute. These parameters also can help re-using the fitness of a solution instead of calling the fitness function:keep_elitism
,keep_parents
, andsave_solutions
. - The value
99999999999
is replaced byfloat('inf')
in the 2 methodswheel_cumulative_probs()
andstochastic_universal_selection()
inside thepygad.utils.parent_selection.ParentSelection
class. - The
plot_result()
method in thepygad.visualize.plot.Plot
class is removed. Instead, please use theplot_fitness()
if you did not upgrade yet.
PyGAD-3.1.0
Release Date 20 June 2023
- Fix a bug when the initial population has duplciate genes if a nested gene space is used.
- The
gene_space
parameter can no longer be assigned a tuple. - Fix a bug when the
gene_space
parameter has a member of typetuple
. - A new instance attribute called
gene_space_unpacked
which has the unpackedgene_space
. It is used to solve duplicates. For infinite ranges in thegene_space
, they are unpacked to a limited number of values (e.g. 100). - Bug fixes when creating the initial population using
gene_space
attribute. - When a
dict
is used with thegene_space
attribute, the new gene value was calculated by summing 2 values: 1) the value sampled from thedict
2) a random value returned from the random mutation range defined by the 2 parametersrandom_mutation_min_val
andrandom_mutation_max_val
. This might cause the gene value to exceed the range limit defined in thegene_space
. To respect thegene_space
range, this release only returns the value from thedict
without summing it to a random value. - Formatting the strings using f-string instead of the
format()
method. #189 - In the
__init__()
of thepygad.GA
class, the logged error messages are handled using atry-except
block instead of repeating thelogger.error()
command. #189 - A new class named
CustomLogger
is created in thepygad.cnn
module to create a default logger using thelogging
module assigned to thelogger
attribute. This class is extended in all other classes in the module. The constructors of these classes have a new parameter namedlogger
which defaults toNone
. If no logger is passed, then the default logger in theCustomLogger
class is used. - Except for the
pygad.nn
module, theprint()
function in all other modules are replaced by thelogging
module to log messages. - The callback functions/methods
on_fitness()
,on_parents()
,on_crossover()
, andon_mutation()
can return values. These returned values override the corresponding properties. The output ofon_fitness()
overrides the population fitness. Theon_parents()
function/method must return 2 values representing the parents and their indices. The output ofon_crossover()
overrides the crossover offspring. The output ofon_mutation()
overrides the mutation offspring. - Fix a bug when adaptive mutation is used while
fitness_batch_size
>1. #195 - When
allow_duplicate_genes=False
and a user-definedgene_space
is used, it sometimes happen that there is no room to solve the duplicates between the 2 genes by simply replacing the value of one gene by another gene. This release tries to solve such duplicates by looking for a third gene that will help in solving the duplicates. These examples explain how it works. Check [this section](https://pygad.readthedocs.io/en/latest/pygad.html#prevent-duplicates-in-gene-values) for more information. - Use probabilities to select parents using the rank parent selection method. #205
- The 2 parameters
random_mutation_min_val
andrandom_mutation_max_val
can accept iterables (list/tuple/numpy.ndarray) with length equal to the number of genes. This enables customizing the mutation range for each individual gene. #198 - The 2 parameters
init_range_low
andinit_range_high
can accept iterables (list/tuple/numpy.ndarray) with length equal to the number of genes. This enables customizing the initial range for each individual gene when creating the initial population. - The
data
parameter in thepredict()
function of thepygad.kerasga
module can be assigned a data generator. #115 #207 - The
predict()
function of thepygad.kerasga
module accepts 3 optional parameters: 1)batch_size=None
,verbose=0
, andsteps=None
. Check documentation of the [Keras Model.predict()](https://keras.io/api/models/model_training_apis) method for more information. #207 - The documentation is updated to explain how mutation works when
gene_space
is used withint
orfloat
data types. Check [this section](https://pygad.readthedocs.io/en/latest/pygad.html#limit-the-gene-value-range-using-the-gene-space-parameter). #198
PyGAD-3.0.1
Fix an issue with passing user-defined function/method for parent selection. #179
PyGAD-3.0.0
This release has a major change where the fitness function accepts a mandatory parameter referring to the instance of the pygad.GA
class.
This is the release notes:
- The structure of the library is changed and some methods defined in the
pygad.py
module are moved to thepygad.utils
,pygad.helper
, andpygad.visualize
submodules. - The
pygad.utils.parent_selection
module has a class namedParentSelection
where all the parent selection operators exist. Thepygad.GA
class extends this class. - The
pygad.utils.crossover
module has a class namedCrossover
where all the crossover operators exist. Thepygad.GA
class extends this class. - The
pygad.utils.mutation
module has a class namedMutation
where all the mutation operators exist. Thepygad.GA
class extends this class. - The
pygad.helper.unique
module has a class namedUnique
some helper methods exist to solve duplicate genes and make sure every gene is unique. Thepygad.GA
class extends this class. - The
pygad.visualize.plot
module has a class namedPlot
where all the methods that create plots exist. Thepygad.GA
class extends this class.
...
class GA(utils.parent_selection.ParentSelection,
utils.crossover.Crossover,
utils.mutation.Mutation,
helper.unique.Unique,
visualize.plot.Plot):
...
- Support of using the
logging
module to log the outputs to both the console and text file instead of using theprint()
function. This is by assigning thelogging.Logger
to the newlogger
parameter. Check the [Logging Outputs](https://pygad.readthedocs.io/en/latest/README_pygad_ReadTheDocs.html#logging-outputs) for more information. - A new instance attribute called
logger
to save the logger. - The function/method passed to the
fitness_func
parameter accepts a new parameter that refers to the instance of thepygad.GA
class. Check this for an example: [Use Functions and Methods to Build Fitness Function and Callbacks](https://pygad.readthedocs.io/en/latest/README_pygad_ReadTheDocs.html#use-functions-and-methods-to-build-fitness-and-callbacks). #163 - Update the documentation to include an example of using functions and methods to calculate the fitness and build callbacks. Check this for more details: [Use Functions and Methods to Build Fitness Function and Callbacks](https://pygad.readthedocs.io/en/latest/README_pygad_ReadTheDocs.html#use-functions-and-methods-to-build-fitness-and-callbacks). #92 (comment)
- Validate the value passed to the
initial_population
parameter. - Validate the type and length of the
pop_fitness
parameter of thebest_solution()
method. - Some edits in the documentation. #106
- Fix an issue when building the initial population as (some) genes have their value taken from the mutation range (defined by the parameters
random_mutation_min_val
andrandom_mutation_max_val
) instead of using the parametersinit_range_low
andinit_range_high
. - The
summary()
method returns the summary as a single-line string. Just log/print the returned string it to see it properly. - The
callback_generation
parameter is removed. Use theon_generation
parameter instead. - There was an issue when using the
parallel_processing
parameter with Keras and PyTorch. As Keras/PyTorch are not thread-safe, thepredict()
method gives incorrect and weird results when more than 1 thread is used. #145 ahmedfgad/TorchGA#5 ahmedfgad/KerasGA#6. Thanks to this [StackOverflow answer](https://stackoverflow.com/a/75606666/5426539). - Replace
numpy.float
byfloat
in the 2 parent selection operators roulette wheel and stochastic universal. #168
PyGAD-2.19.2
- Fix an issue when paralell processing was used where the elitism solutions' fitness values are not re-used. #160 (comment)
PyGAD-2.19.1
- A new
summary()
method is supported to return a Keras-like summary of the PyGAD lifecycle. - A new optional parameter called
fitness_batch_size
is supported to calculate the fitness function in batches. If it is assigned the value1
orNone
(default), then the normal flow is used where the fitness function is called for each individual solution. If thefitness_batch_size
parameter is assigned a value satisfying this condition1 < fitness_batch_size <= sol_per_pop
, then the solutions are grouped into batches of sizefitness_batch_size
and the fitness function is called once for each batch. In this case, the fitness function must return a list/tuple/numpy.ndarray with a length equal to the number of solutions passed. #136. - The
cloudpickle
library (https://github.com/cloudpipe/cloudpickle) is used instead of thepickle
library to pickle thepygad.GA
objects. This solves the issue of having to redefine the functions (e.g. fitness function). Thecloudpickle
library is added as a dependancy in therequirements.txt
file. #159 - Support of assigning methods to these parameters:
fitness_func
,crossover_type
,mutation_type
,parent_selection_type
,on_start
,on_fitness
,on_parents
,on_crossover
,on_mutation
,on_generation
, andon_stop
. #92 #138 - Validating the output of the parent selection, crossover, and mutation functions.
- The built-in parent selection operators return the parent's indices as a NumPy array.
- The outputs of the parent selection, crossover, and mutation operators must be NumPy arrays.
- Fix an issue when
allow_duplicate_genes=True
. #39 - Fix an issue creating scatter plots of the solutions' fitness.
- Sampling from a
set()
is no longer supported in Python 3.11. Instead, sampling happens from alist()
. ThanksMarco Brenna
for pointing to this issue. - The lifecycle is updated to reflect that the new population's fitness is calculated at the end of the lifecycle not at the beginning. #154 (comment)
- There was an issue when
save_solutions=True
that causes the fitness function to be called for solutions already explored and have their fitness pre-calculated. #160 - A new instance attribute named
last_generation_elitism_indices
added to hold the indices of the selected elitism. This attribute helps to re-use the fitness of the elitism instead of calling the fitness function. - Fewer calls to the
best_solution()
method which in turns saves some calls to the fitness function. - Some updates in the documentation to give more details about the
cal_pop_fitness()
method. #79 (comment)