From 2865a2c0b6426640df29a77ebc5375cb035f3b03 Mon Sep 17 00:00:00 2001 From: Ahmed Gad Date: Mon, 6 Nov 2023 13:15:30 -0500 Subject: [PATCH] More tests for NSGA-II --- pygad/pygad.py | 2 +- tests/test_number_fitness_function_calls.py | 109 +++++++++++++++++--- 2 files changed, 94 insertions(+), 17 deletions(-) diff --git a/pygad/pygad.py b/pygad/pygad.py index 4d98416..5d175a6 100644 --- a/pygad/pygad.py +++ b/pygad/pygad.py @@ -880,7 +880,7 @@ def __init__(self, self.select_parents = self.rank_selection else: self.valid_parameters = False - raise TypeError(f"Undefined parent selection type: {parent_selection_type}. \nThe assigned value to the 'parent_selection_type' parameter does not refer to one of the supported parent selection techniques which are: \n-sss (for steady state selection)\n-rws (for roulette wheel selection)\n-sus (for stochastic universal selection)\n-rank (for rank selection)\n-random (for random selection)\n-tournament (for tournament selection).\n") + raise TypeError(f"Undefined parent selection type: {parent_selection_type}. \nThe assigned value to the 'parent_selection_type' parameter does not refer to one of the supported parent selection techniques which are: \n-sss (steady state selection)\n-rws (roulette wheel selection)\n-sus (stochastic universal selection)\n-rank (rank selection)\n-random (random selection)\n-tournament (tournament selection)\n-tournament_nsga2: (Tournament selection for NSGA-II)\n-nsga2: (NSGA-II parent selection).\n") # For tournament selection, validate the K value. if (parent_selection_type == "tournament"): diff --git a/tests/test_number_fitness_function_calls.py b/tests/test_number_fitness_function_calls.py index 4d03454..4968db1 100644 --- a/tests/test_number_fitness_function_calls.py +++ b/tests/test_number_fitness_function_calls.py @@ -14,20 +14,33 @@ def number_calls_fitness_function(keep_elitism=1, keep_parents=-1, mutation_type="random", - mutation_percent_genes="default"): + mutation_percent_genes="default", + parent_selection_type='sss', + multi_objective=False): actual_num_fitness_calls = 0 - def fitness_func(ga, solution, idx): + def fitness_func_no_batch_single(ga, solution, idx): nonlocal actual_num_fitness_calls actual_num_fitness_calls = actual_num_fitness_calls + 1 return 1 + def fitness_func_no_batch_multi(ga_instance, solution, solution_idx): + nonlocal actual_num_fitness_calls + actual_num_fitness_calls = actual_num_fitness_calls + 1 + return [1, 1] + + if multi_objective == True: + fitness_func = fitness_func_no_batch_multi + else: + fitness_func = fitness_func_no_batch_single + ga_optimizer = pygad.GA(num_generations=num_generations, sol_per_pop=sol_per_pop, num_genes=6, num_parents_mating=num_parents_mating, fitness_func=fitness_func, mutation_type=mutation_type, + parent_selection_type=parent_selection_type, mutation_percent_genes=mutation_percent_genes, keep_elitism=keep_elitism, keep_parents=keep_parents, @@ -64,46 +77,68 @@ def test_number_calls_fitness_function_default_keep(): actual, expected = number_calls_fitness_function() assert actual == expected -def test_number_calls_fitness_function_no_keep(): +def test_number_calls_fitness_function_no_keep(multi_objective=False, + parent_selection_type='sss'): actual, expected = number_calls_fitness_function(keep_elitism=0, - keep_parents=0) + keep_parents=0, + parent_selection_type=parent_selection_type, + multi_objective=multi_objective) assert actual == expected -def test_number_calls_fitness_function_keep_elitism(): +def test_number_calls_fitness_function_keep_elitism(multi_objective=False, + parent_selection_type='sss'): actual, expected = number_calls_fitness_function(keep_elitism=3, - keep_parents=0) + keep_parents=0, + parent_selection_type=parent_selection_type, + multi_objective=multi_objective) assert actual == expected -def test_number_calls_fitness_function_keep_parents(): +def test_number_calls_fitness_function_keep_parents(multi_objective=False, + parent_selection_type='sss'): actual, expected = number_calls_fitness_function(keep_elitism=0, - keep_parents=4) + keep_parents=4, + parent_selection_type=parent_selection_type, + multi_objective=multi_objective) assert actual == expected -def test_number_calls_fitness_function_both_keep(): +def test_number_calls_fitness_function_both_keep(multi_objective=False, + parent_selection_type='sss'): actual, expected = number_calls_fitness_function(keep_elitism=3, - keep_parents=4) + keep_parents=4, + parent_selection_type=parent_selection_type, + multi_objective=multi_objective) assert actual == expected -def test_number_calls_fitness_function_no_keep_adaptive_mutation(): +def test_number_calls_fitness_function_no_keep_adaptive_mutation(multi_objective=False, + parent_selection_type='sss'): actual, expected = number_calls_fitness_function(keep_elitism=0, keep_parents=0, + parent_selection_type=parent_selection_type, mutation_type="adaptive", - mutation_percent_genes=[10, 5]) + mutation_percent_genes=[10, 5], + multi_objective=multi_objective) assert actual == expected -def test_number_calls_fitness_function_default_adaptive_mutation(): +def test_number_calls_fitness_function_default_adaptive_mutation(multi_objective=False, + parent_selection_type='sss'): actual, expected = number_calls_fitness_function(mutation_type="adaptive", - mutation_percent_genes=[10, 5]) + parent_selection_type=parent_selection_type, + mutation_percent_genes=[10, 5], + multi_objective=multi_objective) assert actual == expected -def test_number_calls_fitness_function_both_keep_adaptive_mutation(): +def test_number_calls_fitness_function_both_keep_adaptive_mutation(multi_objective=False, + parent_selection_type='sss'): actual, expected = number_calls_fitness_function(keep_elitism=3, keep_parents=4, + parent_selection_type=parent_selection_type, mutation_type="adaptive", - mutation_percent_genes=[10, 5]) + mutation_percent_genes=[10, 5], + multi_objective=multi_objective) assert actual == expected if __name__ == "__main__": + #### Single-objective print() test_number_calls_fitness_function_default_keep() print() @@ -121,3 +156,45 @@ def test_number_calls_fitness_function_both_keep_adaptive_mutation(): print() test_number_calls_fitness_function_both_keep_adaptive_mutation() print() + + #### Multi-Objective + print() + test_number_calls_fitness_function_no_keep(multi_objective=True) + print() + test_number_calls_fitness_function_keep_elitism(multi_objective=True) + print() + test_number_calls_fitness_function_keep_parents(multi_objective=True) + print() + test_number_calls_fitness_function_both_keep(multi_objective=True) + print() + test_number_calls_fitness_function_no_keep_adaptive_mutation(multi_objective=True) + print() + test_number_calls_fitness_function_default_adaptive_mutation(multi_objective=True) + print() + test_number_calls_fitness_function_both_keep_adaptive_mutation(multi_objective=True) + print() + + #### Multi-Objective NSGA-II Parent Selection + print() + test_number_calls_fitness_function_no_keep(multi_objective=True, + parent_selection_type='nsga2') + print() + test_number_calls_fitness_function_keep_elitism(multi_objective=True, + parent_selection_type='nsga2') + print() + test_number_calls_fitness_function_keep_parents(multi_objective=True, + parent_selection_type='nsga2') + print() + test_number_calls_fitness_function_both_keep(multi_objective=True, + parent_selection_type='nsga2') + print() + test_number_calls_fitness_function_no_keep_adaptive_mutation(multi_objective=True, + parent_selection_type='nsga2') + print() + test_number_calls_fitness_function_default_adaptive_mutation(multi_objective=True, + parent_selection_type='nsga2') + print() + test_number_calls_fitness_function_both_keep_adaptive_mutation(multi_objective=True, + parent_selection_type='nsga2') + print() +