12
12
CROSSOVER_RATE = 0.8 # Probability of crossover
13
13
SEARCH_SPACE = (- 10 , 10 ) # Search space for the variables
14
14
15
-
16
15
# Random number generator
17
16
rng = np .random .default_rng ()
18
17
@@ -41,12 +40,7 @@ def __init__(
41
40
self .population = self .initialize_population ()
42
41
43
42
def initialize_population (self ) -> list [np .ndarray ]:
44
- """
45
- Initialize the population with random individuals within the search space.
46
-
47
- Returns:
48
- list[np.ndarray]: A list of individuals represented as numpy arrays.
49
- """
43
+ """Initialize the population with random individuals within the search space."""
50
44
return [
51
45
rng .uniform (
52
46
low = [self .bounds [j ][0 ] for j in range (self .dim )],
@@ -56,18 +50,14 @@ def initialize_population(self) -> list[np.ndarray]:
56
50
]
57
51
58
52
def fitness (self , individual : np .ndarray ) -> float :
59
- """
60
- Calculate the fitness value (function value) for an individual.
61
- """
53
+ """Calculate the fitness value (function value) for an individual."""
62
54
value = float (self .function (* individual )) # Ensure fitness is a float
63
55
return value if self .maximize else - value # If minimizing, invert the fitness
64
56
65
57
def select_parents (
66
58
self , population_score : list [tuple [np .ndarray , float ]]
67
59
) -> list [np .ndarray ]:
68
- """
69
- Select top N_SELECTED parents based on fitness.
70
- """
60
+ """Select top N_SELECTED parents based on fitness."""
71
61
population_score .sort (key = lambda score_tuple : score_tuple [1 ], reverse = True )
72
62
selected_count = min (N_SELECTED , len (population_score ))
73
63
return [ind for ind , _ in population_score [:selected_count ]]
@@ -87,10 +77,10 @@ def crossover(
87
77
88
78
Example:
89
79
>>> ga = GeneticAlgorithm(
90
- lambda x, y: -(x**2 + y**2),
91
- [(-10, 10), (-10, 10)],
92
- 10, 100, 0.1, 0.8, True
93
- )
80
+ ... lambda x, y: -(x**2 + y**2),
81
+ ... [(-10, 10), (-10, 10)],
82
+ ... 10, 100, 0.1, 0.8, True
83
+ ... )
94
84
>>> parent1, parent2 = np.array([1, 2]), np.array([3, 4])
95
85
>>> len(ga.crossover(parent1, parent2)) == 2
96
86
True
@@ -114,10 +104,10 @@ def mutate(self, individual: np.ndarray) -> np.ndarray:
114
104
115
105
Example:
116
106
>>> ga = GeneticAlgorithm(
117
- lambda x, y: -(x**2 + y**2),
118
- [(-10, 10), (-10, 10)],
119
- 10, 100, 0.1, 0.8, True
120
- )
107
+ ... lambda x, y: -(x**2 + y**2),
108
+ ... [(-10, 10), (-10, 10)],
109
+ ... 10, 100, 0.1, 0.8, True
110
+ ... )
121
111
>>> ind = np.array([1.0, 2.0])
122
112
>>> mutated = ga.mutate(ind)
123
113
>>> len(mutated) == 2 # Ensure it still has the correct number of dimensions
@@ -133,22 +123,22 @@ def evaluate_population(self) -> list[tuple[np.ndarray, float]]:
133
123
Evaluate the fitness of the entire population in parallel.
134
124
135
125
Returns:
136
- list[tuple[np.ndarray, float]]: # Trailing whitespace here
126
+ list[tuple[np.ndarray, float]]:
137
127
The population with their respective fitness values.
138
128
139
129
Example:
140
130
>>> ga = GeneticAlgorithm(
141
- lambda x, y: -(x**2 + y**2),
142
- [(-10, 10), (-10, 10)],
143
- 10, 100, 0.1, 0.8, True
144
- )
131
+ ... lambda x, y: -(x**2 + y**2),
132
+ ... [(-10, 10), (-10, 10)],
133
+ ... 10, 100, 0.1, 0.8, True
134
+ ... )
145
135
>>> eval_population = ga.evaluate_population()
146
136
>>> len(eval_population) == ga.population_size # Ensure population size
147
137
True
148
138
>>> all(
149
- isinstance(ind, tuple) and isinstance(ind[1], float)
150
- for ind in eval_population
151
- )
139
+ ... isinstance(ind, tuple) and isinstance(ind[1], float)
140
+ ... for ind in eval_population
141
+ ... )
152
142
True
153
143
"""
154
144
with ThreadPoolExecutor () as executor :
@@ -220,7 +210,6 @@ def target_function(var_x: float, var_y: float) -> float:
220
210
# Set bounds for the variables (var_x, var_y)
221
211
bounds = [(- 10 , 10 ), (- 10 , 10 )] # Both var_x and var_y range from -10 to 10
222
212
223
-
224
213
# Instantiate and run the genetic algorithm
225
214
ga = GeneticAlgorithm (
226
215
function = target_function ,
@@ -232,7 +221,6 @@ def target_function(var_x: float, var_y: float) -> float:
232
221
maximize = False , # Minimize the function
233
222
)
234
223
235
-
236
224
best_solution = ga .evolve ()
237
225
print (f"Best solution found: { best_solution } " )
238
226
print (f"Best fitness (minimum value of function): { target_function (* best_solution )} " )
0 commit comments