Skip to content

Commit 7b85f11

Browse files
authored
Update genetic_algorithm_optimization.py
1 parent 19e0461 commit 7b85f11

File tree

1 file changed

+33
-34
lines changed

1 file changed

+33
-34
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import random
21
import numpy as np
2+
import random
3+
from concurrent.futures import ThreadPoolExecutor
34

45
# Parameters
56
N_POPULATION = 100 # Population size
@@ -9,8 +10,9 @@
910
CROSSOVER_RATE = 0.8 # Probability of crossover
1011
SEARCH_SPACE = (-10, 10) # Search space for the variables
1112

13+
# Random number generator
14+
rng = np.random.default_rng()
1215

13-
# Genetic Algorithm for Function Optimization
1416
class GeneticAlgorithm:
1517
def __init__(
1618
self,
@@ -35,11 +37,9 @@ def __init__(
3537
self.population = self.initialize_population()
3638

3739
def initialize_population(self):
38-
# Generate random initial population within the search space
40+
# Generate random initial population within the search space using the generator
3941
return [
40-
np.random.uniform(
41-
low=self.bounds[i][0], high=self.bounds[i][1], size=self.dim
42-
)
42+
rng.uniform(low=self.bounds[i][0], high=self.bounds[i][1], size=self.dim)
4343
for i in range(self.population_size)
4444
]
4545

@@ -48,14 +48,10 @@ def fitness(self, individual):
4848
value = self.function(*individual)
4949
return value if self.maximize else -value # If minimizing, invert the fitness
5050

51-
def select_parents(self):
52-
# Rank individuals based on fitness and select top individuals for mating
53-
scores = [
54-
(individual, self.fitness(individual)) for individual in self.population
55-
]
56-
scores.sort(key=lambda x: x[1], reverse=True)
57-
selected = [ind for ind, _ in scores[:N_SELECTED]]
58-
return selected
51+
def select_parents(self, population_score):
52+
# Select top N_SELECTED parents based on fitness
53+
population_score.sort(key=lambda x: x[1], reverse=True)
54+
return [ind for ind, _ in population_score[:N_SELECTED]]
5955

6056
def crossover(self, parent1, parent2):
6157
# Perform uniform crossover
@@ -67,16 +63,28 @@ def crossover(self, parent1, parent2):
6763
return parent1, parent2
6864

6965
def mutate(self, individual):
70-
# Apply mutation to an individual with some probability
66+
# Apply mutation to an individual using the new random generator
7167
for i in range(self.dim):
7268
if random.random() < self.mutation_prob:
73-
individual[i] = np.random.uniform(self.bounds[i][0], self.bounds[i][1])
69+
individual[i] = rng.uniform(self.bounds[i][0], self.bounds[i][1])
7470
return individual
7571

72+
def evaluate_population(self):
73+
# Multithreaded evaluation of population fitness
74+
with ThreadPoolExecutor() as executor:
75+
return list(executor.map(lambda ind: (ind, self.fitness(ind)), self.population))
76+
7677
def evolve(self):
7778
for generation in range(self.generations):
78-
# Select parents based on fitness
79-
parents = self.select_parents()
79+
# Evaluate population fitness (multithreaded)
80+
population_score = self.evaluate_population()
81+
82+
# Check the best individual
83+
best_individual = max(population_score, key=lambda x: x[1])[0]
84+
best_fitness = self.fitness(best_individual)
85+
86+
# Select parents for next generation
87+
parents = self.select_parents(population_score)
8088
next_generation = []
8189

8290
# Generate offspring using crossover and mutation
@@ -87,42 +95,33 @@ def evolve(self):
8795
next_generation.append(self.mutate(child2))
8896

8997
# Ensure population size remains the same
90-
self.population = next_generation[: self.population_size]
91-
92-
# Track the best solution so far
93-
best_individual = max(self.population, key=self.fitness)
94-
best_fitness = self.fitness(best_individual)
98+
self.population = next_generation[:self.population_size]
9599

96100
if generation % 10 == 0:
97-
print(
98-
f"Generation {generation}: Best Fitness = {best_fitness}, Best Individual = {best_individual}"
99-
)
101+
print(f"Generation {generation}: Best Fitness = {best_fitness}")
100102

101-
# Return the best individual found
102-
return max(self.population, key=self.fitness)
103+
return best_individual
103104

104105

105-
# Define a sample function to optimize (e.g., minimize the sum of squares)
106+
# Example target function for optimization
106107
def target_function(x, y):
107-
return x**2 + y**2 # Example: simple parabolic surface (minimization)
108+
return x**2 + y**2 # Simple parabolic surface (minimization)
108109

109110

110111
# Set bounds for the variables (x, y)
111112
bounds = [(-10, 10), (-10, 10)] # Both x and y range from -10 to 10
112113

113-
# Instantiate the genetic algorithm
114+
# Instantiate and run the genetic algorithm
114115
ga = GeneticAlgorithm(
115116
function=target_function,
116117
bounds=bounds,
117118
population_size=N_POPULATION,
118119
generations=N_GENERATIONS,
119120
mutation_prob=MUTATION_PROBABILITY,
120121
crossover_rate=CROSSOVER_RATE,
121-
maximize=False, # Set to False for minimization
122+
maximize=False # Minimize the function
122123
)
123124

124-
# Run the genetic algorithm and find the optimal solution
125125
best_solution = ga.evolve()
126-
127126
print(f"Best solution found: {best_solution}")
128127
print(f"Best fitness (minimum value of function): {target_function(*best_solution)}")

0 commit comments

Comments
 (0)