From 6547edc23e194b5b2e33a47c1c8002832dcb0716 Mon Sep 17 00:00:00 2001 From: Ruben-FreddyLoafers Date: Mon, 20 Oct 2025 12:56:15 +0200 Subject: [PATCH] mutate function done? --- 03_euler_gen_alg/main.py | 71 ++++++++++++++++++++++++++++----------- 03_euler_gen_alg/utils.py | 2 +- 2 files changed, 53 insertions(+), 20 deletions(-) diff --git a/03_euler_gen_alg/main.py b/03_euler_gen_alg/main.py index 18dc897..9dbd273 100644 --- a/03_euler_gen_alg/main.py +++ b/03_euler_gen_alg/main.py @@ -18,17 +18,20 @@ import utils POPULATION_SIZE = 10 SELECTION_SIZE = (POPULATION_SIZE * 7) // 10 # 70% of population, rounded down for selection CROSSOVER_PAIR_SIZE = (POPULATION_SIZE - SELECTION_SIZE) // 2 # pairs needed for crossover -XOVER_POINT = 3 +XOVER_POINT = 3 # 4th position +MUTATION_BITS = POPULATION_SIZE * 1 fitness = 0.01 pop_grey = [] -pop_bin = [] +pop_bin = [] # 32 Bit Binary pop_bin_params = [] -pop_new = [] +pop_new = [] # 32 Bit Grey-Code as String e_func = lambda x: np.e**x def generate_random_population(): + """ Puts random 32 Bit binary strings into 4 * 8 Bit long params. """ + # Random population array for i in range(POPULATION_SIZE): pop_grey[i] = format(random.getrandbits(32), '32b') pop_bin[i] = utils.grey_to_bin(pop_grey[i]) @@ -45,7 +48,7 @@ def quadratic_error(original_fn, approx_fn, n): return error def eval_fitness(pop_bin_values): - """ Returns an array with fitness value of every individual in a population.""" + """ Returns an array with fitness value of every individual in a population. """ fitness_arr = [] for params in pop_bin_values: # Convert binary string to parameters for bin_values @@ -61,9 +64,10 @@ def eval_fitness(pop_bin_values): return fitness_arr -def select(fitness_arr): +def select(population, fitness_arr): sum_of_fitness = sum(fitness_arr) - while len(pop_new) < SELECTION_SIZE: + while len(population) < SELECTION_SIZE: + # Roulette logic roulette_num = random.random() is_chosen = False while not is_chosen: @@ -71,8 +75,8 @@ def select(fitness_arr): for i, fitness in enumerate(fitness_arr): cumulative_p += fitness / sum_of_fitness if roulette_num < cumulative_p: - # Add the 32 Bit individual in grey code to pop_new - pop_new.append(pop_grey[i]) + # Add the 32 Bit individual in grey code to population + population.append(pop_grey[i]) # Calc new sum of fitness fitness_arr.pop(i) @@ -81,30 +85,59 @@ def select(fitness_arr): is_chosen = True # break while loop break # break for loop -def xover(): - # calc how many pairs are possible with pop_new - individual_a = pop_new[0] - individual_b = pop_new[1] +def xover(population, xover_rate): + """Performs crossover on pairs of individuals from population.""" + offspring = [] - - # get first three pairs in pop_new - # do the crossover + # Process pairs while we have enough individuals and haven't reached CROSSOVER_PAIR_SIZE + pair_count = 0 + i = 0 + while i < len(population) - 1 and pair_count < xover_rate: + parent_a = population[i] + parent_b = population[i + 1] + + # Create two new offspring by swapping parts at XOVER_POINT + offspring_a = parent_a[:XOVER_POINT] + parent_b[XOVER_POINT:] + offspring_b = parent_b[:XOVER_POINT] + parent_a[XOVER_POINT:] + + offspring.extend([offspring_a, offspring_b]) + pair_count += 1 + i += 2 # Move to next pair + + return offspring + +def mutate(population, mutation_rate): + """Mutate random bits in the population with given mutation rate""" + for _ in range(mutation_rate): + # Select random individual and convert to list for efficient modification + random_num = random.randrange(POPULATION_SIZE) + bits = list(population[random_num]) + + # Flip random bit + bit_pos = random.randrange(32) + bits[bit_pos] = '1' if bits[bit_pos] == '0' else '0' + + # Convert back to string and update population + population[random_num] = ''.join(bits) def main(): pop_bin_values = generate_random_population(10) - while fitness > 0.01: + while fitness > 0.01: # Evaluate fitness fitness_arr = eval_fitness(pop_bin_values) # Selection - select(fitness_arr) # Alters pop_new + select(pop_new, fitness_arr) # Alters pop_new # Crossover + offspring = xover(pop_new, CROSSOVER_PAIR_SIZE) + pop_new.extend(offspring) # .extend needed - # mutation + # Mutation + mutate(pop_new, MUTATION_BITS) - # pop_grey = pop_new + pop_grey = pop_new return 0 if __name__ == "__main__": diff --git a/03_euler_gen_alg/utils.py b/03_euler_gen_alg/utils.py index 669a3e3..b81288a 100644 --- a/03_euler_gen_alg/utils.py +++ b/03_euler_gen_alg/utils.py @@ -14,7 +14,7 @@ def bin_to_grey(binary): return format(gray, f'0{len(binary)}b') # Convert back to binary string with same length def bin_to_param(binary, q_min = 0.0, q_max = 10.0): - """Convert binary string to float parameter in range [q_min, q_max]""" + """Convert one binary string to float parameter in range [q_min, q_max]""" val = int(binary, 2) / 25.5 * 10 # conversion to 0.0 - 10.0 float # Scale to range [q_min, q_max] q = q_min + ((q_max - q_min) / (2**len(binary))) * val