GA combine SA
unknown
python
3 years ago
6.4 kB
12
Indexable
import numpy as np
import matplotlib.pyplot as plt
from math import exp, cos, sin
import matplotlib
import random
from typing import List, Dict
from random import randint
from graycode import gray_code_to_tc
def f(x1, x2):
# f = f1 + f2 + f3
f1 = 4 * ((2 - x1) ** 2) * exp(-(x1 ** 2) - (x2 - 1)**2)
f2 = 10 * (x1 / 4 - x1 ** 3 - x2 ** 5) * exp(-(x1 ** 2) - (x2 ** 2))
f3 = 0.5 * exp(-(x1 + 2) ** 2 - x2 ** 2)
return f1 + f2 + f3
def binary_to_int_in_range(bits: List[int], range: int):
string_bits = "0b"
for bit in bits:
string_bits += f"{bit}"
num_out_of_range = gray_code_to_tc(int(string_bits, 2))
return (num_out_of_range - 128) * range / 128
def f_binary(bits: List[int]):
# separate x1 and x2 bits
x1_bits = bits[0:8]
x2_bits = bits[8:16]
# generate x1 , x2 from graycode to int to float
x1 = binary_to_int_in_range(x1_bits, 3)
x2 = binary_to_int_in_range(x2_bits, 4)
return f(x1, x2)
def get_x1_and_x2(pop: List[List[int]]):
x1 = []
x2 = []
for ind_bit in pop:
x1_bits = ind_bit[0:8]
x2_bits = ind_bit[8:16]
x1.append(binary_to_int_in_range(x1_bits, 3))
x2.append(binary_to_int_in_range(x2_bits, 4))
return x1, x2
def crossover(p1, p2, generations_number, temperature):
# crossover two parents to create two children
# select crossover point that is not on the end of the string
pt = randint(1, len(p1)-2)
# perform crossover
c1 = p1[:pt] + p2[pt:]
c2 = p2[:pt] + p1[pt:]
# calculate sum of parent fitness
curr_eval = f_binary(p1) + f_binary(p2)
# calculate sum of childeren fitness
candidate_eval = f_binary(c1) + f_binary(c2)
# difference between candidate and current point evaluation
diff = candidate_eval - curr_eval
# calculate temperature for current epoch
t = temperature / float(generations_number + 1)
# calculate metropolis acceptance criterion
metropolis = exp(-diff / t)
# check if we should keep the new point
if diff < 0 or np.random.rand() < metropolis:
# retrun the new current point
return [c1, c2]
else:
return [p1, p2]
# mutation operator
def mutation(bitstring, generations_number, temperature):
i = randint(0, len(bitstring) - 1)
# calculate bitstring fitness
curr_eval = f_binary(bitstring)
# flip the bit
bitstring[i] = 1 - bitstring[i]
# calculate new bitstring fitness
candidate_eval = f_binary(bitstring)
# difference between candidate and current point evaluation
diff = candidate_eval - curr_eval
# calculate temperature for current epoch
t = temperature / float(generations_number + 1)
# calculate metropolis acceptance criterion
metropolis = exp(-diff / t)
# check if we should keep the new point
if not (diff < 0 or np.random.rand() < metropolis):
# flip back the bit
bitstring[i] = 1 - bitstring[i]
def selection(pop, scores, k=3):
# first random selection
selection_ix = randint(0, len(pop) - 1)
for ix in [randint(0, len(pop) - 1) for _ in range(k)]:
# check if better (e.g. perform a tournament)
if scores[ix] > scores[selection_ix]:
selection_ix = ix
return pop[selection_ix]
def genetic_algorithm(generations, population_size, crossover_temperature, mutation_temperature, n_bits=16):
average_fitness = []
best_fitness = []
worst_fitness = []
# initial population of random bitstring
pop = [[randint(0, 1)for bit in range(n_bits)]
for _ in range(population_size)]
ind_max_f, max_f = 0, f_binary(pop[0])
# enumerate generations
for gen in range(generations + 1):
# plot pop if gen == 0 , 5 ,10 , 50
if gen in [0, 5, 10, 50]:
x1, x2 = get_x1_and_x2(pop)
plot_fx_and_points_gen(x1, x2, gen)
scores = [f_binary(c) for c in pop]
average_fitness.append(sum(scores) / len(scores))
best_fitness.append(max(scores))
worst_fitness.append(min(scores))
# check for new best solution
for i in range(population_size):
if scores[i] > max_f:
ind_max_f, max_f = pop[i], scores[i]
# select parents
selected = [selection(pop, scores)
for _ in range(population_size)]
# create the next generation
children = list()
for i in range(0, population_size, 2):
# get selected parents in pairs
p1, p2 = selected[i], selected[i+1]
# crossover and mutation
for c in crossover(p1, p2, i, crossover_temperature):
# mutation
mutation(c, i, mutation_temperature)
# store for next generation
children.append(c)
# replace population
pop = children
fig, ax = plt.subplots()
gen_list = [i for i in range(generations + 1)]
plt.plot(gen_list, best_fitness, color='green', marker="*")
plt.plot(gen_list, worst_fitness, color='red', marker="o")
plt.plot(gen_list, average_fitness, color='blue', marker="+")
plt.legend(["best_fitness", "worst_fitness", "average_fitness"])
ax.set_xlabel('generation number', fontsize=16)
ax.set_xlabel('fitness', fontsize=16)
plt.show()
# print(best_fitness, worst_fitness, average_fitness)
return [ind_max_f, max_f]
def plot_fx_and_points_gen(x1, x2, gen):
x1_list = np.arange(-3, 3.2, 0.2)
x2_list = np.arange(-4, 4.2, 0.2)
X1, X2 = np.meshgrid(x1_list, x2_list)
F = np.vectorize(f)
Z = F(X1, X2)
fig, ax = plt.subplots()
cnt = ax.contour(Z, cmap=matplotlib.cm.jet, vmin=abs(
Z).min(), vmax=abs(Z).max(), extent=[-3, 3, -4, 4], alpha=0.5)
ax.set_xlabel('x1', labelpad=20, fontsize=16)
ax.set_ylabel('x2', labelpad=20, fontsize=16)
ax.set_title(f'Generation number {gen}', fontsize=20)
im = ax.imshow(Z, cmap=matplotlib.cm.jet, vmin=abs(
Z).min(), vmax=abs(Z).max(), extent=[-3, 3, 4, -4], alpha=0.4)
im.set_interpolation('bilinear')
plt.plot(x1, x2, 'bo', color="black")
plt.show()
population_size = 20
generations = 50
temperature = 10
mutation_temperature = 10
crossover_temperature = 1
print(genetic_algorithm(
generations, population_size, crossover_temperature, mutation_temperature))
Editor is loading...