278 lines
10 KiB
Python
278 lines
10 KiB
Python
|
import random
|
||
|
|
||
|
class Genetic():
|
||
|
pass
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
def calc_cost(self, mines_list):
|
||
|
self.mined_tile_count = len(mines_list)
|
||
|
total_cost = 0
|
||
|
i = 0
|
||
|
while i < (self.mined_tile_count - 1):
|
||
|
total_cost = total_cost + self.manhattan_cost_counter(mines_list, i)
|
||
|
i = i + 1
|
||
|
|
||
|
return total_cost
|
||
|
|
||
|
def manhattan_cost_counter(self, mines_list, i):
|
||
|
|
||
|
|
||
|
x1, y1 = mines_list[i][0], mines_list[i][1]
|
||
|
x2, y2 = mines_list[i+1][0], mines_list[i+1][1]
|
||
|
|
||
|
|
||
|
return abs(x2 - x1) + abs(y2 - y1)
|
||
|
|
||
|
def population_initialization(self, mines_list, i):
|
||
|
first_mine = mines_list[0]
|
||
|
x = len(mines_list)-1
|
||
|
shuffled_coordinates = []
|
||
|
while x > 0:
|
||
|
shuffled_coordinates.append(mines_list[x])
|
||
|
x = x - 1
|
||
|
|
||
|
mine_chromosome = []
|
||
|
while i > 0:
|
||
|
child = random.sample(shuffled_coordinates, len(shuffled_coordinates))
|
||
|
child.insert(0, first_mine)
|
||
|
#child.insert(x, first_mine)
|
||
|
mine_chromosome.append(child)
|
||
|
i = i - 1
|
||
|
return mine_chromosome
|
||
|
|
||
|
def fitness_function(self, generations):
|
||
|
total_cost = 0
|
||
|
chromosome_count = 0
|
||
|
chromosome_costs = []
|
||
|
y = 0
|
||
|
#problem - wyjście poza liste
|
||
|
if len(generations) == 0:
|
||
|
return
|
||
|
|
||
|
first_cost = self.calc_cost(generations[y])
|
||
|
cheapest_chromosome = generations[y]
|
||
|
lowest_cost = first_cost
|
||
|
highest_cost = first_cost
|
||
|
for i in generations:
|
||
|
chromosome_costs.append(self.calc_cost(i))
|
||
|
total_cost = total_cost + self.calc_cost(i)
|
||
|
chromosome_count = chromosome_count + 1
|
||
|
if self.calc_cost(i) < lowest_cost:
|
||
|
lowest_cost = self.calc_cost(i)
|
||
|
cheapest_chromosome = i
|
||
|
if self.calc_cost(i) > highest_cost:
|
||
|
highest_cost = self.calc_cost(i)
|
||
|
|
||
|
average_fitness = total_cost/chromosome_count
|
||
|
chromosome_fitness = []
|
||
|
total_chromosome_fitness = 0
|
||
|
l = 0
|
||
|
for i in chromosome_costs:
|
||
|
chromosome_fitness.append(round(((average_fitness/chromosome_costs[l])*10), 2))
|
||
|
total_chromosome_fitness += round(((average_fitness/chromosome_costs[l])*10),2)
|
||
|
l = l + 1
|
||
|
|
||
|
return(chromosome_fitness, lowest_cost, highest_cost, average_fitness, cheapest_chromosome)
|
||
|
|
||
|
|
||
|
def fitness_population_selection(self, first_generation, chromosome_fitness):
|
||
|
x = len(chromosome_fitness)
|
||
|
roulette_table = []
|
||
|
average_population = []
|
||
|
i = 0
|
||
|
interval = 0
|
||
|
while x > 0:
|
||
|
interval = interval + chromosome_fitness[i]
|
||
|
roulette_table.append(round(interval, 2))
|
||
|
x = x - 1
|
||
|
i = i + 1
|
||
|
x = len(chromosome_fitness)/2
|
||
|
max = roulette_table[i - 1]
|
||
|
while x > 0:
|
||
|
i = 0
|
||
|
n = random.uniform(0, max)
|
||
|
while n > roulette_table[i]:
|
||
|
i = i + 1
|
||
|
average_population.append(first_generation[i])
|
||
|
x = x - 1
|
||
|
return average_population
|
||
|
|
||
|
def crossover(self, average_population):
|
||
|
post_crossover_population = []
|
||
|
x = len(average_population) - 1
|
||
|
if x <= 0:
|
||
|
print("no enough chromosomes to crossover")
|
||
|
return
|
||
|
while x > 0:
|
||
|
parent_1 = average_population[x]
|
||
|
parent_2 = average_population[x-1]
|
||
|
child_1 = []
|
||
|
child_2 = []
|
||
|
crossover_decision = random.randint(1, 100)
|
||
|
if (crossover_decision < 11) and (parent_1 != parent_2):
|
||
|
crossover_point = random.randint(1, (len(average_population[x])-3))
|
||
|
l = 0
|
||
|
k = crossover_point
|
||
|
while k >= 0:
|
||
|
child_1.append(parent_1[l])
|
||
|
l = l + 1
|
||
|
k = k - 1
|
||
|
k = crossover_point
|
||
|
while k < (len(parent_1) - 1):
|
||
|
for i in parent_2:
|
||
|
if i not in child_1:
|
||
|
child_1.append(i)
|
||
|
k = k + 1
|
||
|
|
||
|
l = 0
|
||
|
k = crossover_point
|
||
|
while k >= 0:
|
||
|
child_2.append(parent_2[l])
|
||
|
l = l + 1
|
||
|
k = k - 1
|
||
|
k = crossover_point
|
||
|
while k >= 0:
|
||
|
child_2.append(parent_2[l])
|
||
|
l = l + 1
|
||
|
k = k - 1
|
||
|
k = crossover_point
|
||
|
while k < (len(parent_1) - 1):
|
||
|
for i in parent_1:
|
||
|
if i not in child_2:
|
||
|
child_2.append(i)
|
||
|
k = k + 1
|
||
|
#child_1.append(0)
|
||
|
#child_2.append(0)
|
||
|
else:
|
||
|
child_1 = parent_1
|
||
|
child_2 = parent_2
|
||
|
post_crossover_population.append(child_1)
|
||
|
post_crossover_population.append(child_2)
|
||
|
x = x - 1
|
||
|
|
||
|
return post_crossover_population
|
||
|
|
||
|
def mutation(self, post_crossover_popualtion):
|
||
|
k = len(post_crossover_popualtion) - 1
|
||
|
while k >= 0:
|
||
|
mutation_decision = random.randint(0, 100)
|
||
|
if mutation_decision < 3:
|
||
|
mutated_chromosome = post_crossover_popualtion[k]
|
||
|
post_crossover_popualtion.remove(mutated_chromosome)
|
||
|
l = len(mutated_chromosome) - 1
|
||
|
|
||
|
x = random.randint(1, l)
|
||
|
y = random.randint(1, l)
|
||
|
while x == y:
|
||
|
y = random.randint(1, l)
|
||
|
replacement = mutated_chromosome[x]
|
||
|
mutated_chromosome[y] = replacement
|
||
|
|
||
|
post_crossover_popualtion.insert(k, mutated_chromosome)
|
||
|
|
||
|
k = k - 1
|
||
|
post_mutation_population = post_crossover_popualtion
|
||
|
|
||
|
return post_mutation_population
|
||
|
|
||
|
def optimize(self, post_mutation_population, mine_list):
|
||
|
post_optimization_population = post_mutation_population
|
||
|
i = len(post_mutation_population)
|
||
|
l = 1
|
||
|
while l < i:
|
||
|
k = 1
|
||
|
while k >= 0:
|
||
|
if post_mutation_population[l] == post_mutation_population[k - 1]:
|
||
|
post_optimization_population.remove(post_mutation_population[k-1])
|
||
|
x = len(mine_list) - 2
|
||
|
shuffled_coordinates = []
|
||
|
while x > 0:
|
||
|
shuffled_coordinates.append(mine_list[x])
|
||
|
x = x - 1
|
||
|
x = len(mine_list) - 1
|
||
|
new_chromosome = random.sample(shuffled_coordinates, len(shuffled_coordinates))
|
||
|
new_chromosome.insert(0, mine_list[0])
|
||
|
new_chromosome.insert(x, mine_list[0])
|
||
|
post_optimization_population.append(new_chromosome)
|
||
|
|
||
|
k = k - 1
|
||
|
l = l + 1
|
||
|
return post_optimization_population
|
||
|
|
||
|
def genetic_algorythm(self, coordinates):
|
||
|
self.full_cost = self.calc_cost(coordinates)
|
||
|
self.first_generation = self.population_initialization(coordinates,10)
|
||
|
self.fitness, self.lowest_cost, self.highest_cost, self.average_fitness_of_first_genetation, self.cheapest_individual = self.fitness_function(self.first_generation)
|
||
|
self.average_population = self.fitness_population_selection(self.first_generation, self.fitness)
|
||
|
self.population_after_crossover = self.crossover(self.average_population)
|
||
|
|
||
|
|
||
|
if self.population_after_crossover == None:
|
||
|
print("Finished in " + str(self.which_generation) + "generations")
|
||
|
return
|
||
|
|
||
|
self.population_after_mutation = self.mutation(self.population_after_crossover)
|
||
|
self.population_after_optimization = self.optimize(self.population_after_mutation, coordinates)
|
||
|
self.max_cost = self.highest_cost
|
||
|
self.min_cost = self.lowest_cost
|
||
|
self.cheapest_route = self.cheapest_individual
|
||
|
i = 2
|
||
|
self.which_generation = 1
|
||
|
while i < 41:
|
||
|
print(" ")
|
||
|
print("***********")
|
||
|
print("Generation " + str(i))
|
||
|
print("***********")
|
||
|
print(" ")
|
||
|
|
||
|
if self.fitness_function(self.population_after_optimization) == None:
|
||
|
return
|
||
|
|
||
|
self.fitness, self.lowest_cost, self.highest_cost, self.average_fitness_of_first_genetation, self.cheapest_individual = self.fitness_function(self.population_after_optimization)
|
||
|
if self.highest_cost > self.max_cost:
|
||
|
self.max_cost = self.highest_cost
|
||
|
if self.lowest_cost < self.min_cost:
|
||
|
self.min_cost = self.lowest_cost
|
||
|
self.cheapest_route = self.cheapest_individual
|
||
|
self.which_generation = i
|
||
|
print("New lowest cost: " + str(self.min_cost))
|
||
|
print("New cheapest route: " + str(self.cheapest_route))
|
||
|
|
||
|
self.average_population = self.fitness_population_selection(self.population_after_mutation, self.fitness)
|
||
|
|
||
|
self.population_after_crossover = self.crossover(self.average_population)
|
||
|
|
||
|
if self.population_after_crossover == None:
|
||
|
print("Finished")
|
||
|
return
|
||
|
|
||
|
self.population_after_mutation = self.mutation(self.population_after_crossover)
|
||
|
self.population_after_optimization = self.optimize(self.population_after_mutation, coordinates)
|
||
|
i = i + 1
|
||
|
if(self.min_cost)/(self.average_fitness_of_first_genetation) < (0.7):
|
||
|
print("Finished after " + str(i)+ " generations")
|
||
|
break
|
||
|
print("Average fitness of first generation: " + str(self.average_fitness_of_first_genetation))
|
||
|
print("Relation of efficiency growth: " + str((self.min_cost)/(self.average_fitness_of_first_genetation)))
|
||
|
print("Lowest cost is " + str(self.min_cost))
|
||
|
print("Cheapest route is: " + str(self.cheapest_route))
|
||
|
|
||
|
def run(self):
|
||
|
Mines = [[1,1],
|
||
|
[2,4],
|
||
|
[3,1],
|
||
|
[4,7],
|
||
|
[5,3],
|
||
|
[7,6]]
|
||
|
|
||
|
self.genetic_algorythm(Mines)
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|