This commit is contained in:
Debojit Roy 2024-10-04 18:51:07 +02:00 committed by GitHub
commit fd8b113bc5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -0,0 +1,125 @@
import numpy as np
class GeneticAlgorithmOptimizer:
def __init__(
self,
func,
bounds,
population_size=100,
generations=500,
crossover_prob=0.9,
mutation_prob=0.01,
):
self.func = func
self.bounds = np.array(bounds)
self.population_size = population_size
self.generations = generations
self.crossover_prob = crossover_prob
self.mutation_prob = mutation_prob
self.num_variables = len(bounds)
# Initialize the random number generator
self.rng = np.random.default_rng()
def initialize_population(self):
"""
Initialize a population of random solutions within the bounds.
"""
return self.rng.uniform(
low=self.bounds[:, 0],
high=self.bounds[:, 1],
size=(self.population_size, self.num_variables),
)
def fitness(self, individual):
"""
Evaluate the fitness of an individual.
In minimization problems, we aim to minimize the function value.
"""
return self.func(*individual)
def select_parents(self, population, fitness_scores):
"""
Select parents using tournament selection.
"""
selected_indices = self.rng.choice(
range(self.population_size), size=2, replace=False
)
return population[selected_indices[np.argmin(fitness_scores[selected_indices])]]
def crossover(self, parent1, parent2):
"""
Perform one-point crossover to create offspring.
Skip crossover for single-variable functions.
"""
if self.num_variables == 1:
return parent1, parent2 # No crossover needed for single-variable functions
if self.rng.random() < self.crossover_prob:
point = self.rng.integers(1, self.num_variables)
child1 = np.concatenate((parent1[:point], parent2[point:]))
child2 = np.concatenate((parent2[:point], parent1[point:]))
return child1, child2
return parent1, parent2
def mutate(self, individual):
"""
Apply mutation to an individual with a given mutation probability.
"""
if self.rng.random() < self.mutation_prob:
index = self.rng.integers(0, self.num_variables)
individual[index] = self.rng.uniform(
self.bounds[index, 0], self.bounds[index, 1]
)
return individual
def evolve(self):
"""
Run the genetic algorithm for a number of generations.
"""
population = self.initialize_population()
best_solution = None
best_fitness = float("inf")
for gen in range(self.generations):
fitness_scores = np.array(
[self.fitness(individual) for individual in population]
)
new_population = []
for _ in range(self.population_size // 2):
parent1 = self.select_parents(population, fitness_scores)
parent2 = self.select_parents(population, fitness_scores)
child1, child2 = self.crossover(parent1, parent2)
child1 = self.mutate(child1)
child2 = self.mutate(child2)
new_population.extend([child1, child2])
population = np.array(new_population)
# Track the best solution
min_fitness_index = np.argmin(fitness_scores)
if fitness_scores[min_fitness_index] < best_fitness:
best_fitness = fitness_scores[min_fitness_index]
best_solution = population[min_fitness_index]
print(f"Generation {gen + 1}, Best Fitness: {best_fitness}")
return best_solution, best_fitness
if __name__ == "__main__":
# Define the function to optimize
def func(x, y):
return x**2 + y**2 # Example: Minimizing x^2 + y^2
# Define the bounds for each variable
bounds = [(-10, 10), (-10, 10)]
# Initialize and run the optimizer
optimizer = GeneticAlgorithmOptimizer(func=func, bounds=bounds)
best_solution, best_fitness = optimizer.evolve()
print("Best Solution:", best_solution)
print("Best Fitness:", best_fitness)