Skip to content

Commit 4ef8cd5

Browse files
committed
Support of NSGA-II
1 parent 0ea3674 commit 4ef8cd5

File tree

3 files changed

+42
-6
lines changed

3 files changed

+42
-6
lines changed

pygad/pygad.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1683,6 +1683,12 @@ def cal_pop_fitness(self):
16831683
if self.fitness_batch_size in [1, None]:
16841684
fitness = self.fitness_func(self, sol, sol_idx)
16851685
if type(fitness) in GA.supported_int_float_types:
1686+
# The fitness function returns a single numeric value.
1687+
# This is a single-objective optimization problem.
1688+
pass
1689+
elif type(fitness) in [list, tuple, numpy.ndarray]:
1690+
# The fitness function returns a list/tuple/numpy.ndarray.
1691+
# This is a multi-objective optimization problem.
16861692
pass
16871693
else:
16881694
raise ValueError(f"The fitness function should return a number but the value {fitness} of type {type(fitness)} found.")
@@ -1718,6 +1724,12 @@ def cal_pop_fitness(self):
17181724

17191725
for index, fitness in zip(batch_indices, batch_fitness):
17201726
if type(fitness) in GA.supported_int_float_types:
1727+
# The fitness function returns a single numeric value.
1728+
# This is a single-objective optimization problem.
1729+
pop_fitness[index] = fitness
1730+
elif type(fitness) in [list, tuple, numpy.ndarray]:
1731+
# The fitness function returns a list/tuple/numpy.ndarray.
1732+
# This is a multi-objective optimization problem.
17211733
pop_fitness[index] = fitness
17221734
else:
17231735
raise ValueError(f"The fitness function should return a number but the value {fitness} of type {type(fitness)} found.")
@@ -1779,6 +1791,12 @@ def cal_pop_fitness(self):
17791791
if self.fitness_batch_size in [1, None]:
17801792
for index, fitness in zip(solutions_to_submit_indices, executor.map(self.fitness_func, [self]*len(solutions_to_submit_indices), solutions_to_submit, solutions_to_submit_indices)):
17811793
if type(fitness) in GA.supported_int_float_types:
1794+
# The fitness function returns a single numeric value.
1795+
# This is a single-objective optimization problem.
1796+
pop_fitness[index] = fitness
1797+
elif type(fitness) in [list, tuple, numpy.ndarray]:
1798+
# The fitness function returns a list/tuple/numpy.ndarray.
1799+
# This is a multi-objective optimization problem.
17821800
pop_fitness[index] = fitness
17831801
else:
17841802
raise ValueError(f"The fitness function should return a number but the value {fitness} of type {type(fitness)} found.")
@@ -1810,6 +1828,12 @@ def cal_pop_fitness(self):
18101828

18111829
for index, fitness in zip(batch_indices, batch_fitness):
18121830
if type(fitness) in GA.supported_int_float_types:
1831+
# The fitness function returns a single numeric value.
1832+
# This is a single-objective optimization problem.
1833+
pop_fitness[index] = fitness
1834+
elif type(fitness) in [list, tuple, numpy.ndarray]:
1835+
# The fitness function returns a list/tuple/numpy.ndarray.
1836+
# This is a multi-objective optimization problem.
18131837
pop_fitness[index] = fitness
18141838
else:
18151839
raise ValueError(f"The fitness function should return a number but the value ({fitness}) of type {type(fitness)} found.")

pygad/utils/mutation.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,13 @@ def adaptive_mutation_population_fitness(self, offspring):
471471

472472
first_idx = len(parents_to_keep)
473473
last_idx = fitness.shape[0]
474-
fitness[first_idx:last_idx] = [0]*(last_idx - first_idx)
474+
if len(fitness.shape) > 1:
475+
# TODO This is a multi-objective optimization problem.
476+
# fitness[first_idx:last_idx] = [0]*(last_idx - first_idx)
477+
raise ValueError('Edit adaptive mutation to work with multi-objective optimization problems.')
478+
else:
479+
# This is a single-objective optimization problem.
480+
fitness[first_idx:last_idx] = [0]*(last_idx - first_idx)
475481

476482
if self.fitness_batch_size in [1, None]:
477483
# Calculate the fitness for each individual solution.
@@ -667,7 +673,7 @@ def adaptive_mutation_by_space(self, offspring):
667673
gene_type=self.gene_type,
668674
num_trials=10)
669675
return offspring
670-
676+
671677
def adaptive_mutation_randomly(self, offspring):
672678

673679
"""

pygad/utils/parent_selection.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,9 @@ def nsga2_selection(self,
395395

396396
# The number of remaining parents to be selected.
397397
num_remaining_parents = num_parents
398-
398+
399+
# Index of the current parent.
400+
current_parent_idx = 0
399401
# A loop variable holding the index of the current pareto front.
400402
pareto_front_idx = 0
401403
while num_remaining_parents != 0 and pareto_front_idx < len(pareto_fronts):
@@ -407,10 +409,12 @@ def nsga2_selection(self,
407409
for sol_idx in range(len(current_pareto_front)):
408410
selected_solution_idx = current_pareto_front[sol_idx, 0]
409411
# Insert the parent into the parents array.
410-
parents[sol_idx, :] = self.population[selected_solution_idx, :].copy()
412+
parents[current_parent_idx, :] = self.population[selected_solution_idx, :].copy()
411413
# Insert the index of the selected parent.
412414
parents_indices.append(selected_solution_idx)
413-
415+
# Increase the parent index.
416+
current_parent_idx += 1
417+
414418
# Decrement the number of remaining parents by the length of the pareto front.
415419
num_remaining_parents -= len(current_pareto_front)
416420
else:
@@ -422,9 +426,11 @@ def nsga2_selection(self,
422426

423427
for selected_solution_idx in crowding_dist_pop_sorted_indices[0:num_remaining_parents]:
424428
# Insert the parent into the parents array.
425-
parents[sol_idx, :] = self.population[selected_solution_idx, :].copy()
429+
parents[current_parent_idx, :] = self.population[selected_solution_idx, :].copy()
426430
# Insert the index of the selected parent.
427431
parents_indices.append(selected_solution_idx)
432+
# Increase the parent index.
433+
current_parent_idx += 1
428434

429435
# Decrement the number of remaining parents by the number of selected parents.
430436
num_remaining_parents -= num_remaining_parents

0 commit comments

Comments
 (0)