-
Notifications
You must be signed in to change notification settings - Fork 0
/
Mutations.py
103 lines (77 loc) · 3.57 KB
/
Mutations.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import random
import statistics
# Mutation Functions
def swap_mutation(gene, probability):
mutated_gene = list(gene)
for i in range(len(mutated_gene)):
if random.random() < probability:
# Choose a random position in the string to swap with
swap_pos = random.randint(0, len(mutated_gene) - 1)
mutated_gene[i], mutated_gene[swap_pos] = mutated_gene[swap_pos], mutated_gene[i]
return ''.join(mutated_gene)
def scramble_mutation(gene, probability):
mutated_gene = list(gene)
for i in range(len(mutated_gene)):
if random.random() < probability:
# Choose a random slice of the string to scramble
start_pos = random.randint(0, len(mutated_gene) - 1)
end_pos = random.randint(start_pos + 1, len(mutated_gene))
scrambled_slice = list(mutated_gene[start_pos:end_pos])
random.shuffle(scrambled_slice)
mutated_gene[start_pos:end_pos] = scrambled_slice
return ''.join(mutated_gene)
def inversion_mutation(gene, probability):
gene = list(gene)
for i in range(len(gene)):
if random.random() < probability:
pos1 = random.randint(0, len(gene) - 1)
pos2 = random.randint(0, len(gene) - 1)
if pos1 > pos2:
pos1, pos2 = pos2, pos1
gene[pos1:pos2 + 1] = reversed(gene[pos1:pos2 + 1])
return ''.join(gene)
def no_mutation(gene, probability):
return gene
# Mutation control functions
def constant(mut_p, fitness_values=None, ind_fitness=None, best_history=None, current_generation=None):
return mut_p
def non_uniform_mutation_rate(mut_p, fitness_values, ind_fitness, best_history, current_generation, decay_factor=0.99):
avg_fitness = sum(fitness_values) / len(fitness_values)
stdev_fitness = statistics.stdev(fitness_values)
if stdev_fitness == 0:
adjusted_mutation_prob = mut_p
else:
adjusted_mutation_prob = mut_p * (1 + (avg_fitness / stdev_fitness))
mutation_rate = adjusted_mutation_prob * (decay_factor ** current_generation)
return mutation_rate
def adaptive_mutation_prob_population(mut_p, fitness_values, ind_fitness, best_history, current_generation=None):
avg_fitness = sum(fitness_values) / len(fitness_values)
stdev_fitness = statistics.stdev(fitness_values)
if stdev_fitness == 0:
adjusted_mutation_prob = mut_p
else:
adjusted_mutation_prob = mut_p * (1 + (avg_fitness / stdev_fitness))
return adjusted_mutation_prob
def triggered_hyper_mutation(mut_p, fitness_values, ind_fitness, best_history, current_generation=None,
stagnation_threshold=10,
increase_factor=1.2):
if len(best_history) < stagnation_threshold:
return mut_p
stagnation_count = 0
for i in range(1, len(best_history)):
if abs(best_history[i] - best_history[i - 1]) <= best_history[i] * 0.01:
stagnation_count += 1
else:
stagnation_count = 0
if stagnation_count >= stagnation_threshold - 1:
new_mut_p = mut_p * increase_factor
return min(new_mut_p, 1) # Ensure the new probability is not greater than 1
return mut_p
def adaptive_mutation_prob_individual(mut_p, fitness_values, ind_fitness, best_history=None, current_generation=None):
max_fitness = max(fitness_values)
min_fitness = min(fitness_values)
if max_fitness == min_fitness:
rel_fitness = 1
else:
rel_fitness = (ind_fitness - min_fitness) / (max_fitness - min_fitness)
return mut_p * (1 - rel_fitness)