Releases: ahmedfgad/GeneticAlgorithmPython
Releases · ahmedfgad/GeneticAlgorithmPython
PyGAD-3.5.0
- Fix a bug when minus sign (-) is used inside the 
stop_criteriaparameter for multi-objective problems. #314 #323 - Fix a bug when the 
stop_criteriaparameter 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.Plotclass to import the matplotlib library. #315 - Create a new helper method called 
select_unique_value()inside thepygad/helper/unique.pyscript to select a unique gene from an array of values. - Create a new helper method called 
get_random_mutation_range()inside thepygad/utils/mutation.pyscript 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_dtypeinside thepygad/utils/mutation.pyscript 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.pyscript that rounds the value used to apply random mutation. - Create the 
pygad/helper/misc.pyscript with a class calledHelperthat 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_constraintparameter is satisfied or not.get_gene_dtype(): Returns the gene data type from thegene_typeinstance attribute.get_random_mutation_range(): Returns the random mutation range using therandom_mutation_min_valandrandom_mutation_min_valinstance attributes.get_initial_population_range(): Returns the initial population values range using theinit_range_lowandinit_range_highinstance attributes.generate_gene_value_from_space(): Generates/selects a value for a gene using thegene_spaceinstance attribute.generate_gene_value_randomly(): Generates a random value for the gene. Only used ifgene_spaceisNone.generate_gene_value(): Generates a value for the gene. It checks whethergene_spaceisNoneand 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.pyscript that generates constrained random values for mutation. It calls eithergenerate_gene_value()orget_valid_gene_constraint_values()based on whether thegene_constraintparameter is used or not. - A new parameter called 
gene_constraintis 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_sizeis 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_genesorgene_constraintis used. An instance attribute of the same name is created in the instances of thepygad.GAclass. Check the [sample_size Parameter](https://pygad.readthedocs.io/en/latest/pygad_more.html#sample-size-parameter) section for more information. - Use the 
sample_sizeparameter instead ofnum_trialsin the methodssolve_duplicate_genes_randomly()andunique_float_gene_from_range()inside thepygad/helper/unique.pyscript. 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.pyscript to accept an optional parameter calledfind_best_solutionwhen 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.pyscript. 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_genparameter is removed from thepygad.GAclass constructor. As a result, it is no longer an attribute of thepygad.GAclass instances. To add a delay after each generation, apply it inside theon_generationcallback. #283 - In the 
single_point_crossover()method of thepygad.utils.crossover.Crossoverclass, all the random crossover points are returned before theforloop. 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 theforloop K times, once for each individual offspring. - Bug fix in the 
examples/example_custom_operators.pyscript. #285 - While making prediction using the 
pygad.torchga.predict()function, no gradients are calculated. - The 
gene_typeparameter 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.Uniqueclass 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.pyscript 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 
Matplotliblibrary is only imported when a method inside thepygad/visualize/plot.pyscript is used. This is more efficient than usingimport matplotlib.pyplotat the module level as this causes it to be imported whenpygadis imported even when it is not needed. #292 - Fix a bug when minus sign (-) is used inside the 
stop_criteriaparameter (e.g.stop_criteria=["saturate_10", "reach_-0.5"]). #296 - Make sure 
self.best_solutionsis a list of lists inside thecal_pop_fitnessmethod. #293 - Fix a bug where the 
cal_pop_fitness()method was using theprevious_generation_fitnessattribute 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_fitnessattribute 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_parents2)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_ciiteriaparameter is used with thereachkeyword, 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_genparameter 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_generationparameter 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_spaceparameter 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_valandrandom_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 
objectas a supported data type for int (GA.supported_int_types) and float (GA.supported_float_types). #174 - Use the 
raiseclause 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_sizeset to a non-zero number). - Fix a bug in the 
pygad.pyscript when finding the index of the best solution. It does not work properly with multi-objective optimization whereself.best_solutions_fitnesshave 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.nsga2is created that has theNSGA2class 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 
NSGA2class in thepygad.utils.nsga2module. Just return alist,tuple, ornumpy.ndarrayfrom 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_selectionmodule: 1) Tournament selection for NSGA-II 2) NSGA-II selection. - The 
plot_fitness()method in thepygad.plotmodule has a new optional parameter namedlabelto accept the label of the plots. This is only used for multi-objective problems. Otherwise, it is ignored. It defaults toNoneand accepts alist,tuple, ornumpy.ndarray. The labels are used in a legend inside the plot. - The default color in the methods of the 
pygad.plotmodule is changed to the greenish#64f20ccolor. - A new instance attribute named 
pareto_frontsadded to thepygad.GAinstances that holds the pareto fronts when solving a multi-objective problem. - The 
gene_typeaccepts alist,tuple, ornumpy.ndarrayfor 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=Trueand the solution is found in thebest_solutionsattribute. 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 
99999999999is replaced byfloat('inf')in the 2 methodswheel_cumulative_probs()andstochastic_universal_selection()inside thepygad.utils.parent_selection.ParentSelectionclass. - The 
plot_result()method in thepygad.visualize.plot.Plotclass 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_spaceparameter can no longer be assigned a tuple. - Fix a bug when the 
gene_spaceparameter has a member of typetuple. - A new instance attribute called 
gene_space_unpackedwhich 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_spaceattribute. - When a 
dictis used with thegene_spaceattribute, the new gene value was calculated by summing 2 values: 1) the value sampled from thedict2) a random value returned from the random mutation range defined by the 2 parametersrandom_mutation_min_valandrandom_mutation_max_val. This might cause the gene value to exceed the range limit defined in thegene_space. To respect thegene_spacerange, this release only returns the value from thedictwithout summing it to a random value. - Formatting the strings using f-string instead of the 
format()method. #189 - In the 
__init__()of thepygad.GAclass, the logged error messages are handled using atry-exceptblock instead of repeating thelogger.error()command. #189 - A new class named 
CustomLoggeris created in thepygad.cnnmodule to create a default logger using theloggingmodule assigned to theloggerattribute. This class is extended in all other classes in the module. The constructors of these classes have a new parameter namedloggerwhich defaults toNone. If no logger is passed, then the default logger in theCustomLoggerclass is used. - Except for the 
pygad.nnmodule, theprint()function in all other modules are replaced by theloggingmodule 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=Falseand a user-definedgene_spaceis 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_valandrandom_mutation_max_valcan 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_lowandinit_range_highcan 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 
dataparameter in thepredict()function of thepygad.kerasgamodule can be assigned a data generator. #115 #207 - The 
predict()function of thepygad.kerasgamodule 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_spaceis used withintorfloatdata 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.pymodule are moved to thepygad.utils,pygad.helper, andpygad.visualizesubmodules. - The 
pygad.utils.parent_selectionmodule has a class namedParentSelectionwhere all the parent selection operators exist. Thepygad.GAclass extends this class. - The 
pygad.utils.crossovermodule has a class namedCrossoverwhere all the crossover operators exist. Thepygad.GAclass extends this class. - The 
pygad.utils.mutationmodule has a class namedMutationwhere all the mutation operators exist. Thepygad.GAclass extends this class. - The 
pygad.helper.uniquemodule has a class namedUniquesome helper methods exist to solve duplicate genes and make sure every gene is unique. Thepygad.GAclass extends this class. - The 
pygad.visualize.plotmodule has a class namedPlotwhere all the methods that create plots exist. Thepygad.GAclass 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 
loggingmodule to log the outputs to both the console and text file instead of using theprint()function. This is by assigning thelogging.Loggerto the newloggerparameter. Check the [Logging Outputs](https://pygad.readthedocs.io/en/latest/README_pygad_ReadTheDocs.html#logging-outputs) for more information. - A new instance attribute called 
loggerto save the logger. - The function/method passed to the 
fitness_funcparameter accepts a new parameter that refers to the instance of thepygad.GAclass. 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_populationparameter. - Validate the type and length of the 
pop_fitnessparameter 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_valandrandom_mutation_max_val) instead of using the parametersinit_range_lowandinit_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_generationparameter is removed. Use theon_generationparameter instead. - There was an issue when using the 
parallel_processingparameter 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.floatbyfloatin 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_sizeis supported to calculate the fitness function in batches. If it is assigned the value1orNone(default), then the normal flow is used where the fitness function is called for each individual solution. If thefitness_batch_sizeparameter is assigned a value satisfying this condition1 < fitness_batch_size <= sol_per_pop, then the solutions are grouped into batches of sizefitness_batch_sizeand 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 
cloudpicklelibrary (https://github.com/cloudpipe/cloudpickle) is used instead of thepicklelibrary to pickle thepygad.GAobjects. This solves the issue of having to redefine the functions (e.g. fitness function). Thecloudpicklelibrary is added as a dependancy in therequirements.txtfile. #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 Brennafor 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=Truethat 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_indicesadded 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)