Skip to content

Commit b740c01

Browse files
committed
Update function_optimization.py
1 parent 5d82115 commit b740c01

File tree

1 file changed

+32
-21
lines changed

1 file changed

+32
-21
lines changed

genetic_algorithm/function_optimization.py

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ def parse_function(user_input):
99
user_input (str): The user-defined fitness function in string format.
1010
1111
Returns:
12-
str: The function code as a string.
12+
function: A callable fitness function.
1313
1414
Examples:
1515
>>> parse_function("f(x, y) = x^2 + y^2")
16-
'def fitness(x):\\n return x[0]**2 + x[1]**2'
16+
<function fitness at 0x...>
1717
"""
1818
user_input = user_input.strip()
1919

@@ -23,10 +23,14 @@ def parse_function(user_input):
2323
else:
2424
raise ValueError("Invalid function format. Please use 'f(x, y) = ...'.")
2525

26-
function_code = "def fitness(x):\n"
27-
function_code += f" return {expression.replace('^', '**').replace('x', 'x[0]').replace('y', 'x[1]')}\n"
26+
# Replace variable names and power operator
27+
expression = expression.replace('^', '**').replace('x', 'x[0]').replace('y', 'x[1]')
2828

29-
return function_code
29+
# Create the fitness function
30+
def fitness(x):
31+
return eval(expression)
32+
33+
return fitness
3034

3135

3236
def genetic_algorithm(user_fitness_function) -> None:
@@ -52,6 +56,7 @@ def genetic_algorithm(user_fitness_function) -> None:
5256
best_fitness = np.inf
5357
best_solution = None
5458

59+
# Initialize the population
5560
population = rng.random((population_size, chromosome_length))
5661

5762
for generation in range(num_generations):
@@ -60,9 +65,10 @@ def genetic_algorithm(user_fitness_function) -> None:
6065
for individual in population:
6166
fitness_value = user_fitness_function(individual)
6267

63-
if fitness_value is None:
68+
if fitness_value is None or not isinstance(fitness_value, (int, float)):
6469
print(
65-
f"Warning: Fitness function returned None for individual {individual}."
70+
f"Warning: Fitness function returned an invalid value "
71+
f"for individual {individual}."
6672
)
6773
fitness_value = np.inf
6874
else:
@@ -74,26 +80,35 @@ def genetic_algorithm(user_fitness_function) -> None:
7480

7581
fitness_values = np.array(fitness_values)
7682

83+
# Update the best solution
7784
best_idx = np.argmin(fitness_values)
7885
if fitness_values[best_idx] < best_fitness:
7986
best_fitness = fitness_values[best_idx]
8087
best_solution = population[best_idx]
8188

8289
print(f"Generation {generation + 1}, Best Fitness: {best_fitness:.6f}")
8390

91+
# Selection
8492
selected_parents = population[rng.choice(population_size, population_size)]
85-
93+
94+
# Crossover
8695
offspring = []
87-
for i in range(0, population_size, 2):
96+
for i in range(0, population_size - 1, 2): # Ensure even number of parents
8897
parent1, parent2 = selected_parents[i], selected_parents[i + 1]
8998
cross_point = rng.integers(1, chromosome_length)
9099
child1 = np.concatenate((parent1[:cross_point], parent2[cross_point:]))
91100
child2 = np.concatenate((parent2[:cross_point], parent1[cross_point:]))
92101
offspring.append(child1)
93102
offspring.append(child2)
94103

104+
# Handle odd population size if necessary
105+
if population_size % 2 == 1:
106+
offspring.append(selected_parents[-1]) # Include last parent if odd
107+
95108
offspring = np.array(offspring)
96-
mutation_mask = rng.random((population_size, chromosome_length)) < mutation_rate
109+
110+
# Mutation
111+
mutation_mask = rng.random(offspring.shape) < mutation_rate
97112
offspring[mutation_mask] = rng.random(np.sum(mutation_mask))
98113

99114
population = offspring
@@ -102,12 +117,14 @@ def genetic_algorithm(user_fitness_function) -> None:
102117
print(f"User-defined function: f(x, y) = {user_input.split('=')[1].strip()}")
103118
print(f"Best Fitness Value (Minimum): {best_fitness:.6f}")
104119
print(
105-
f"Optimal Solution Found: x = {best_solution[0]:.6f}, y = {best_solution[1]:.6f}"
120+
f"Optimal Solution Found: x = {best_solution[0]:.6f}, "
121+
f"y = {best_solution[1]:.6f}"
106122
)
107123

108124
function_value = best_fitness
109125
print(
110-
f"Function Value at Optimal Solution: f({best_solution[0]:.6f}, {best_solution[1]:.6f}) = {function_value:.6f}"
126+
f"Function Value at Optimal Solution: f({best_solution[0]:.6f}, "
127+
f"{best_solution[1]:.6f}) = {function_value:.6f}"
111128
)
112129

113130

@@ -117,15 +134,9 @@ def genetic_algorithm(user_fitness_function) -> None:
117134
)
118135

119136
try:
120-
fitness_function_code = parse_function(user_input)
121-
exec(fitness_function_code, globals())
137+
fitness_function = parse_function(user_input)
138+
genetic_algorithm(fitness_function)
122139
except (SyntaxError, ValueError) as e:
123140
print(f"Error: {e}")
124141
except NameError as e:
125-
print(f"Error: {e}")
126-
127-
if "fitness" in globals():
128-
if "fitness" in globals():
129-
genetic_algorithm(globals()["fitness"])
130-
else:
131-
print("No valid fitness function provided.")
142+
print(f"Error: {e}")

0 commit comments

Comments
 (0)