1
1
import numpy as np
2
2
3
-
4
3
class GeneticAlgorithmOptimizer :
5
4
def __init__ (
6
5
self ,
@@ -25,6 +24,11 @@ def __init__(
25
24
def initialize_population (self ):
26
25
"""
27
26
Initialize a population of random solutions within the bounds.
27
+
28
+ >>> optimizer = GeneticAlgorithmOptimizer(func=lambda x: x**2, bounds=[(-10, 10)])
29
+ >>> pop = optimizer.initialize_population()
30
+ >>> pop.shape == (optimizer.population_size, optimizer.num_variables)
31
+ True
28
32
"""
29
33
return self .rng .uniform (
30
34
low = self .bounds [:, 0 ],
@@ -36,12 +40,25 @@ def fitness(self, individual):
36
40
"""
37
41
Evaluate the fitness of an individual.
38
42
In minimization problems, we aim to minimize the function value.
43
+
44
+ >>> optimizer = GeneticAlgorithmOptimizer(func=lambda x: x**2, bounds=[(-10, 10)])
45
+ >>> optimizer.fitness([2])
46
+ 4
47
+ >>> optimizer.fitness([0])
48
+ 0
39
49
"""
40
50
return self .func (* individual )
41
51
42
52
def select_parents (self , population , fitness_scores ):
43
53
"""
44
54
Select parents using tournament selection.
55
+
56
+ >>> optimizer = GeneticAlgorithmOptimizer(func=lambda x: x**2, bounds=[(-10, 10)])
57
+ >>> population = optimizer.initialize_population()
58
+ >>> fitness_scores = np.array([optimizer.fitness(ind) for ind in population])
59
+ >>> parent = optimizer.select_parents(population, fitness_scores)
60
+ >>> len(parent) == optimizer.num_variables
61
+ True
45
62
"""
46
63
selected_indices = self .rng .choice (
47
64
range (self .population_size ), size = 2 , replace = False
@@ -50,8 +67,14 @@ def select_parents(self, population, fitness_scores):
50
67
51
68
def crossover (self , parent1 , parent2 ):
52
69
"""
53
- Perform one-point crossover to create offspring.
54
- Skip crossover for single-variable functions.
70
+ Perform one-point crossover to create offspring. Skip crossover for single-variable functions.
71
+
72
+ >>> optimizer = GeneticAlgorithmOptimizer(func=lambda x: x**2, bounds=[(-10, 10)])
73
+ >>> parent1 = [1]
74
+ >>> parent2 = [2]
75
+ >>> child1, child2 = optimizer.crossover(parent1, parent2)
76
+ >>> child1 == parent1 and child2 == parent2
77
+ True
55
78
"""
56
79
if self .num_variables == 1 :
57
80
return parent1 , parent2 # No crossover needed for single-variable functions
@@ -66,6 +89,12 @@ def crossover(self, parent1, parent2):
66
89
def mutate (self , individual ):
67
90
"""
68
91
Apply mutation to an individual with a given mutation probability.
92
+
93
+ >>> optimizer = GeneticAlgorithmOptimizer(func=lambda x: x**2, bounds=[(-10, 10)])
94
+ >>> individual = [1]
95
+ >>> new_individual = optimizer.mutate(individual.copy())
96
+ >>> len(new_individual) == len(individual)
97
+ True
69
98
"""
70
99
if self .rng .random () < self .mutation_prob :
71
100
index = self .rng .integers (0 , self .num_variables )
@@ -108,10 +137,19 @@ def evolve(self):
108
137
109
138
return best_solution , best_fitness
110
139
111
-
112
140
if __name__ == "__main__" :
113
141
# Define the function to optimize
114
142
def func (x , y ):
143
+ """
144
+ Example function to minimize x^2 + y^2
145
+
146
+ >>> func(0, 0)
147
+ 0
148
+ >>> func(3, 4)
149
+ 25
150
+ >>> func(-3, -4)
151
+ 25
152
+ """
115
153
return x ** 2 + y ** 2 # Example: Minimizing x^2 + y^2
116
154
117
155
# Define the bounds for each variable
0 commit comments