Skip to content

Commit 464bfd6

Browse files
committed
Batch fitness for adaptive mutation
1 parent 63e8312 commit 464bfd6

File tree

2 files changed

+39
-14
lines changed

2 files changed

+39
-14
lines changed

pygad/pygad.py

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1531,8 +1531,7 @@ def cal_pop_fitness(self):
15311531
elif (self.keep_elitism > 0) and (self.last_generation_elitism is not None) and (len(self.last_generation_elitism) > 0) and (list(sol) in last_generation_elitism_as_list):
15321532
# Return the index of the elitism from the elitism array 'self.last_generation_elitism'.
15331533
# This is not its index within the population. It is just its index in the 'self.last_generation_elitism' array.
1534-
elitism_idx = last_generation_elitism_as_list.index(
1535-
list(sol))
1534+
elitism_idx = last_generation_elitism_as_list.index(list(sol))
15361535
# Use the returned elitism index to return its index in the last population.
15371536
elitism_idx = self.last_generation_elitism_indices[elitism_idx]
15381537
# Use the elitism's index to return its pre-calculated fitness value.
@@ -1544,8 +1543,7 @@ def cal_pop_fitness(self):
15441543
# Index of the parent in the 'self.last_generation_parents' array.
15451544
# This is not its index within the population. It is just its index in the 'self.last_generation_parents' array.
15461545
# parent_idx = numpy.where(numpy.all(self.last_generation_parents == sol, axis=1))[0][0]
1547-
parent_idx = last_generation_parents_as_list.index(
1548-
list(sol))
1546+
parent_idx = last_generation_parents_as_list.index(list(sol))
15491547
# Use the returned parent index to return its index in the last population.
15501548
parent_idx = self.last_generation_parents_indices[parent_idx]
15511549
# Use the parent's index to return its pre-calculated fitness value.
@@ -1573,13 +1571,11 @@ def cal_pop_fitness(self):
15731571
solutions_indices = numpy.where(
15741572
numpy.array(pop_fitness) == "undefined")[0]
15751573
# Number of batches.
1576-
num_batches = int(numpy.ceil(
1577-
len(solutions_indices) / self.fitness_batch_size))
1574+
num_batches = int(numpy.ceil(len(solutions_indices) / self.fitness_batch_size))
15781575
# For each batch, get its indices and call the fitness function.
15791576
for batch_idx in range(num_batches):
15801577
batch_first_index = batch_idx * self.fitness_batch_size
1581-
batch_last_index = (batch_idx + 1) * \
1582-
self.fitness_batch_size
1578+
batch_last_index = (batch_idx + 1) * self.fitness_batch_size
15831579
batch_indices = solutions_indices[batch_first_index:batch_last_index]
15841580
batch_solutions = self.population[batch_indices, :]
15851581

@@ -1660,17 +1656,15 @@ def cal_pop_fitness(self):
16601656
# Reaching this block means that batch processing is used. The fitness values are calculated in batches.
16611657

16621658
# Number of batches.
1663-
num_batches = int(numpy.ceil(
1664-
len(solutions_to_submit_indices) / self.fitness_batch_size))
1659+
num_batches = int(numpy.ceil(len(solutions_to_submit_indices) / self.fitness_batch_size))
16651660
# Each element of the `batches_solutions` list represents the solutions in one batch.
16661661
batches_solutions = []
16671662
# Each element of the `batches_indices` list represents the solutions' indices in one batch.
16681663
batches_indices = []
16691664
# For each batch, get its indices and call the fitness function.
16701665
for batch_idx in range(num_batches):
16711666
batch_first_index = batch_idx * self.fitness_batch_size
1672-
batch_last_index = (batch_idx + 1) * \
1673-
self.fitness_batch_size
1667+
batch_last_index = (batch_idx + 1) * self.fitness_batch_size
16741668
batch_indices = solutions_to_submit_indices[batch_first_index:batch_last_index]
16751669
batch_solutions = self.population[batch_indices, :]
16761670

pygad/utils/mutation.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -438,8 +438,39 @@ def adaptive_mutation_population_fitness(self, offspring):
438438

439439
fitness[:self.last_generation_parents.shape[0]] = self.last_generation_fitness[self.last_generation_parents_indices]
440440

441-
for idx in range(len(parents_to_keep), fitness.shape[0]):
442-
fitness[idx] = self.fitness_func(self, temp_population[idx], None)
441+
first_idx = len(parents_to_keep)
442+
last_idx = fitness.shape[0]
443+
fitness[first_idx:last_idx] = [0]*(last_idx - first_idx)
444+
445+
if self.fitness_batch_size in [1, None]:
446+
# Calculate the fitness for each individual solution.
447+
for idx in range(first_idx, last_idx):
448+
fitness[idx] = self.fitness_func(self,
449+
temp_population[idx],
450+
None)
451+
else:
452+
# Calculate the fitness for batch of solutions.
453+
454+
# Number of batches.
455+
num_batches = int(numpy.ceil((last_idx - first_idx) / self.fitness_batch_size))
456+
457+
for batch_idx in range(num_batches):
458+
# The index of the first solution in the current batch.
459+
batch_first_index = first_idx + batch_idx * self.fitness_batch_size
460+
# The index of the last solution in the current batch.
461+
if batch_idx == (num_batches - 1):
462+
batch_last_index = last_idx
463+
else:
464+
batch_last_index = first_idx + (batch_idx + 1) * self.fitness_batch_size
465+
466+
# Calculate the fitness values for the batch.
467+
fitness_temp = self.fitness_func(self,
468+
temp_population[batch_first_index:batch_last_index],
469+
None)
470+
# Insert the fitness of each solution at the proper index.
471+
for idx in range(batch_first_index, batch_last_index):
472+
fitness[idx] = fitness_temp[idx - batch_first_index]
473+
443474
average_fitness = numpy.mean(fitness)
444475

445476
return average_fitness, fitness[len(parents_to_keep):]

0 commit comments

Comments
 (0)