tsp v4.1a, getting distance from astar not from pythagoras

This commit is contained in:
trzmielewskiR 2022-06-10 04:21:42 +02:00
parent 75746f077e
commit 65f469465a
6 changed files with 95 additions and 73 deletions

View File

@ -4,12 +4,12 @@
| | | |--- class: 0 | | | |--- class: 0
| | |--- feature_0 > 1.50 | | |--- feature_0 > 1.50
| | | |--- feature_3 <= 3.50 | | | |--- feature_3 <= 3.50
| | | | |--- feature_4 <= 2.50 | | | | |--- feature_2 <= 2.50
| | | | | |--- class: 1 | | | | | |--- class: 1
| | | | |--- feature_4 > 2.50 | | | | |--- feature_2 > 2.50
| | | | | |--- feature_2 <= 2.50 | | | | | |--- feature_4 <= 2.50
| | | | | | |--- class: 1 | | | | | | |--- class: 1
| | | | | |--- feature_2 > 2.50 | | | | | |--- feature_4 > 2.50
| | | | | | |--- class: 0 | | | | | | |--- class: 0
| | | |--- feature_3 > 3.50 | | | |--- feature_3 > 3.50
| | | | |--- feature_3 <= 4.50 | | | | |--- feature_3 <= 4.50
@ -26,18 +26,18 @@
| | | | | | | |--- feature_1 > 1.50 | | | | | | | |--- feature_1 > 1.50
| | | | | | | | |--- class: 0 | | | | | | | | |--- class: 0
| | | | | | |--- feature_0 > 2.50 | | | | | | |--- feature_0 > 2.50
| | | | | | | |--- feature_2 <= 2.50 | | | | | | | |--- feature_4 <= 2.50
| | | | | | | | |--- class: 1 | | | | | | | | |--- class: 1
| | | | | | | |--- feature_2 > 2.50 | | | | | | | |--- feature_4 > 2.50
| | | | | | | | |--- feature_4 <= 2.50 | | | | | | | | |--- feature_2 <= 2.50
| | | | | | | | | |--- class: 1 | | | | | | | | | |--- class: 1
| | | | | | | | |--- feature_4 > 2.50 | | | | | | | | |--- feature_2 > 2.50
| | | | | | | | | |--- class: 0 | | | | | | | | | |--- class: 0
| | | | | |--- feature_1 > 2.50 | | | | | |--- feature_1 > 2.50
| | | | | | |--- feature_1 <= 3.50 | | | | | | |--- feature_0 <= 3.50
| | | | | | | |--- feature_0 <= 3.50 | | | | | | | |--- class: 0
| | | | | | | | |--- class: 0 | | | | | | |--- feature_0 > 3.50
| | | | | | | |--- feature_0 > 3.50 | | | | | | | |--- feature_1 <= 3.50
| | | | | | | | |--- feature_2 <= 2.50 | | | | | | | | |--- feature_2 <= 2.50
| | | | | | | | | |--- class: 1 | | | | | | | | | |--- class: 1
| | | | | | | | |--- feature_2 > 2.50 | | | | | | | | |--- feature_2 > 2.50
@ -45,8 +45,8 @@
| | | | | | | | | | |--- class: 1 | | | | | | | | | | |--- class: 1
| | | | | | | | | |--- feature_4 > 2.00 | | | | | | | | | |--- feature_4 > 2.00
| | | | | | | | | | |--- class: 0 | | | | | | | | | | |--- class: 0
| | | | | | |--- feature_1 > 3.50 | | | | | | | |--- feature_1 > 3.50
| | | | | | | |--- class: 0 | | | | | | | | |--- class: 0
| | | | |--- feature_3 > 4.50 | | | | |--- feature_3 > 4.50
| | | | | |--- class: 0 | | | | | |--- class: 0
| |--- feature_4 > 3.50 | |--- feature_4 > 3.50
@ -59,13 +59,13 @@
| | | | | | |--- class: 1 | | | | | | |--- class: 1
| | | | |--- feature_3 > 3.50 | | | | |--- feature_3 > 3.50
| | | | | |--- feature_1 <= 2.50 | | | | | |--- feature_1 <= 2.50
| | | | | | |--- feature_3 <= 4.50 | | | | | | |--- feature_0 <= 2.50
| | | | | | | |--- feature_0 <= 2.50
| | | | | | | | |--- class: 0
| | | | | | | |--- feature_0 > 2.50
| | | | | | | | |--- class: 1
| | | | | | |--- feature_3 > 4.50
| | | | | | | |--- class: 0 | | | | | | | |--- class: 0
| | | | | | |--- feature_0 > 2.50
| | | | | | | |--- feature_3 <= 4.50
| | | | | | | | |--- class: 1
| | | | | | | |--- feature_3 > 4.50
| | | | | | | | |--- class: 0
| | | | | |--- feature_1 > 2.50 | | | | | |--- feature_1 > 2.50
| | | | | | |--- class: 0 | | | | | | |--- class: 0
| | | |--- feature_4 > 4.50 | | | |--- feature_4 > 4.50
@ -73,19 +73,19 @@
| | |--- feature_2 > 1.50 | | |--- feature_2 > 1.50
| | | |--- class: 0 | | | |--- class: 0
|--- feature_2 > 3.50 |--- feature_2 > 3.50
| |--- feature_1 <= 1.50 | |--- feature_4 <= 1.50
| | |--- feature_4 <= 1.50 | | |--- feature_1 <= 1.50
| | | |--- feature_2 <= 4.50 | | | |--- feature_2 <= 4.50
| | | | |--- feature_3 <= 4.50 | | | | |--- feature_0 <= 1.50
| | | | | |--- feature_0 <= 1.50
| | | | | | |--- class: 0
| | | | | |--- feature_0 > 1.50
| | | | | | |--- class: 1
| | | | |--- feature_3 > 4.50
| | | | | |--- class: 0 | | | | | |--- class: 0
| | | | |--- feature_0 > 1.50
| | | | | |--- feature_3 <= 4.50
| | | | | | |--- class: 1
| | | | | |--- feature_3 > 4.50
| | | | | | |--- class: 0
| | | |--- feature_2 > 4.50 | | | |--- feature_2 > 4.50
| | | | |--- class: 0 | | | | |--- class: 0
| | |--- feature_4 > 1.50 | | |--- feature_1 > 1.50
| | | |--- class: 0 | | | |--- class: 0
| |--- feature_1 > 1.50 | |--- feature_4 > 1.50
| | |--- class: 0 | | |--- class: 0

Binary file not shown.

View File

@ -1,23 +1,31 @@
import numpy as np, random, operator, pandas as pd, matplotlib.pyplot as plt import numpy as np, random, operator, pandas as pd, matplotlib.pyplot as plt
from path_search_algorthms import a_star from path_search_algorthms.a_star import get_cost
from decision_tree import decisionTree from decision_tree import decisionTree
from settings import *
import math
# klasa tworząca miasta czy też śmietniki # klasa tworząca miasta czy też śmietniki
class City: class City:
def __init__(self, x, y): def __init__(self, x, y):
self.x = x self.x = x
self.y = y self.y = y
#self.array = array
# self.dist = distance # self.dist = distance
#dystans to d = sqrt(x^2 + y^2)
def distance(self, city): def distance(self, city):
#getting distance by astar gives wrong final distance (intial = final)
#return get_cost(math.floor(self.x / TILESIZE), math.floor(self.y / TILESIZE), math.floor(city.x / TILESIZE), math.floor(city.y / TILESIZE), self.array)
xDis = abs(self.x - city.x) xDis = abs(self.x - city.x)
yDis = abs(self.y - city.y) yDis = abs(self.y - city.y)
distance = np.sqrt((xDis ** 2) + (yDis ** 2)) distance = np.sqrt((xDis ** 2) + (yDis ** 2))
return distance return distance
def __repr__(self): def __repr__(self):
return "(" + str(self.x) + "," + str(self.y) + ")" return "(" + str(self.x) + "," + str(self.y) + ")"
# fitness function, # fitness function,
# inverse of route distance # inverse of route distance
# we want to minimize distance so the larger the fitness the better # we want to minimize distance so the larger the fitness the better
@ -25,32 +33,34 @@ class Fitness:
def __init__(self, route): def __init__(self, route):
self.route = route self.route = route
self.distance = 0 self.distance = 0
self.fitness= 0.0 self.fitness = 0.0
def routeDistance(self): def routeDistance(self):
if self.distance ==0: if self.distance == 0:
pathDistance = 0 pathDistance = 0
for i in range(0, len(self.route)): for i in range(0, len(self.route)):
fromCity = self.route[i] fromCity = self.route[i]
toCity = None toCity = None
if i + 1 < len(self.route): # for returning to point 0? if i + 1 < len(self.route): # for returning to point 0?
toCity = self.route[i + 1] toCity = self.route[i + 1]
else: else:
toCity = self.route[0] toCity = self.route[0]
pathDistance += fromCity.distance(toCity) pathDistance += fromCity.distance(toCity)
self.distance = pathDistance self.distance = pathDistance
return self.distance return self.distance
def routeFitness(self): def routeFitness(self):
if self.fitness == 0: if self.fitness == 0:
self.fitness = 1 / float(self.routeDistance()) self.fitness = 1 / float(self.routeDistance())
return self.fitness return self.fitness
# creating one individual - single route from city to city (trash to trash) # creating one individual - single route from city to city (trash to trash)
def createRoute(cityList): def createRoute(cityList):
route = random.sample(cityList, len(cityList)) route = random.sample(cityList, len(cityList))
return route return route
# creating initial population of given size # creating initial population of given size
def initialPopulation(popSize, cityList): def initialPopulation(popSize, cityList):
population = [] population = []
@ -59,12 +69,14 @@ def initialPopulation(popSize, cityList):
population.append(createRoute(cityList)) population.append(createRoute(cityList))
return population return population
# ranking fitness of given route, output is ordered list with route id and its fitness score # ranking fitness of given route, output is ordered list with route id and its fitness score
def rankRoutes(population): def rankRoutes(population):
fitnessResults = {} fitnessResults = {}
for i in range(0,len(population)): for i in range(0, len(population)):
fitnessResults[i] = Fitness(population[i]).routeFitness() fitnessResults[i] = Fitness(population[i]).routeFitness()
return sorted(fitnessResults.items(), key = operator.itemgetter(1), reverse = True) return sorted(fitnessResults.items(), key=operator.itemgetter(1), reverse=True)
# selecting "mating pool" # selecting "mating pool"
# we are using here "Firness proportionate selection", its fitness-weighted probability of being selected # we are using here "Firness proportionate selection", its fitness-weighted probability of being selected
@ -73,19 +85,21 @@ def rankRoutes(population):
def selection(popRanked, eliteSize): def selection(popRanked, eliteSize):
selectionResults = [] selectionResults = []
# roulette wheel # roulette wheel
df = pd.DataFrame(np.array(popRanked), columns=["Index","Fitness"]) df = pd.DataFrame(np.array(popRanked), columns=["Index", "Fitness"])
df['cum_sum'] = df.Fitness.cumsum() df['cum_sum'] = df.Fitness.cumsum()
df['cum_perc'] = 100*df.cum_sum/df.Fitness.sum() df['cum_perc'] = 100 * df.cum_sum / df.Fitness.sum()
for i in range(0, eliteSize): # elitism for i in range(0, eliteSize): # elitism
selectionResults.append(popRanked[i][0]) selectionResults.append(popRanked[i][0])
for i in range(0, len(popRanked) - eliteSize): # comparing randomly drawn number to weights for selection for mating pool for i in range(0,
pick = 100*random.random() len(popRanked) - eliteSize): # comparing randomly drawn number to weights for selection for mating pool
pick = 100 * random.random()
for i in range(0, len(popRanked)): for i in range(0, len(popRanked)):
if pick <= df.iat[i,3]: if pick <= df.iat[i, 3]:
selectionResults.append(popRanked[i][0]) selectionResults.append(popRanked[i][0])
break break
return selectionResults # returns list of route IDs return selectionResults # returns list of route IDs
# creating mating pool from list of routes IDs from "selection" # creating mating pool from list of routes IDs from "selection"
def matingPool(population, selectionResults): def matingPool(population, selectionResults):
@ -95,6 +109,7 @@ def matingPool(population, selectionResults):
matingpool.append(population[index]) matingpool.append(population[index])
return matingpool return matingpool
# creating new generation # creating new generation
# ordered crossover bc we need to include all locations exactly one time # ordered crossover bc we need to include all locations exactly one time
# randomly selecting a subset of the first parent string and then filling the remainder of route # randomly selecting a subset of the first parent string and then filling the remainder of route
@ -103,94 +118,98 @@ def breed(parent1, parent2):
child = [] child = []
childP1 = [] childP1 = []
childP2 = [] childP2 = []
geneA = int(random.random() * len(parent1)) geneA = int(random.random() * len(parent1))
geneB = int(random.random() * len(parent1)) geneB = int(random.random() * len(parent1))
startGene = min(geneA, geneB) startGene = min(geneA, geneB)
endGene = max(geneA, geneB) endGene = max(geneA, geneB)
for i in range(startGene, endGene): # ordered crossover for i in range(startGene, endGene): # ordered crossover
childP1.append(parent1[i]) childP1.append(parent1[i])
childP2 = [item for item in parent2 if item not in childP1] childP2 = [item for item in parent2 if item not in childP1]
child = childP1 + childP2 child = childP1 + childP2
return child return child
# creating whole offspring population # creating whole offspring population
def breedPopulation(matingpool, eliteSize): def breedPopulation(matingpool, eliteSize):
children = [] children = []
length = len(matingpool) - eliteSize length = len(matingpool) - eliteSize
pool = random.sample(matingpool, len(matingpool)) pool = random.sample(matingpool, len(matingpool))
# using elitism to retain best genes (routes) # using elitism to retain best genes (routes)
for i in range(0,eliteSize): for i in range(0, eliteSize):
children.append(matingpool[i]) children.append(matingpool[i])
# filling rest generation # filling rest generation
for i in range(0, length): for i in range(0, length):
child = breed(pool[i], pool[len(matingpool)-i-1]) child = breed(pool[i], pool[len(matingpool) - i - 1])
children.append(child) children.append(child)
return children return children
# using swap mutation # using swap mutation
# with specified low prob we swap two cities in route # with specified low prob we swap two cities in route
def mutate(individual, mutationRate): def mutate(individual, mutationRate):
for swapped in range(len(individual)): for swapped in range(len(individual)):
if(random.random() < mutationRate): if (random.random() < mutationRate):
swapWith = int(random.random() * len(individual)) swapWith = int(random.random() * len(individual))
city1 = individual[swapped] city1 = individual[swapped]
city2 = individual[swapWith] city2 = individual[swapWith]
individual[swapped] = city2 individual[swapped] = city2
individual[swapWith] = city1 individual[swapWith] = city1
return individual return individual
# extending mutate function to run through new pop # extending mutate function to run through new pop
def mutatePopulation(population, mutationRate): def mutatePopulation(population, mutationRate):
mutatedPop = [] mutatedPop = []
for ind in range(0, len(population)): for ind in range(0, len(population)):
mutatedInd = mutate(population[ind], mutationRate) mutatedInd = mutate(population[ind], mutationRate)
mutatedPop.append(mutatedInd) mutatedPop.append(mutatedInd)
return mutatedPop return mutatedPop
# creating new generation
# creating new generation
def nextGeneration(currentGen, eliteSize, mutationRate): def nextGeneration(currentGen, eliteSize, mutationRate):
popRanked = rankRoutes(currentGen) # rank routes in current gen popRanked = rankRoutes(currentGen) # rank routes in current gen
selectionResults = selection(popRanked, eliteSize) # determining potential parents selectionResults = selection(popRanked, eliteSize) # determining potential parents
matingpool = matingPool(currentGen, selectionResults) # creating mating pool matingpool = matingPool(currentGen, selectionResults) # creating mating pool
children = breedPopulation(matingpool, eliteSize) # creating new gen children = breedPopulation(matingpool, eliteSize) # creating new gen
nextGeneration = mutatePopulation(children, mutationRate) # applying mutation to new gen nextGeneration = mutatePopulation(children, mutationRate) # applying mutation to new gen
return nextGeneration return nextGeneration
def geneticAlgorithm(population, popSize, eliteSize, mutationRate, generations): def geneticAlgorithm(population, popSize, eliteSize, mutationRate, generations):
pop = initialPopulation(popSize, population) pop = initialPopulation(popSize, population)
print("Initial distance: " + str(1 / rankRoutes(pop)[0][1])) print("Initial distance: " + str(1 / rankRoutes(pop)[0][1]))
for i in range(0, generations): for i in range(0, generations):
pop = nextGeneration(pop, eliteSize, mutationRate) pop = nextGeneration(pop, eliteSize, mutationRate)
print("Final distance: " + str(1 / rankRoutes(pop)[0][1])) print("Final distance: " + str(1 / rankRoutes(pop)[0][1]))
bestRouteIndex = rankRoutes(pop)[0][0] bestRouteIndex = rankRoutes(pop)[0][0]
bestRoute = pop[bestRouteIndex] bestRoute = pop[bestRouteIndex]
return bestRoute return bestRoute
# tutaj ma być lista kordów potencjalnych śmietników z drzewa decyzyjnego # tutaj ma być lista kordów potencjalnych śmietników z drzewa decyzyjnego
cityList = [] cityList = []
# for i in range(0,25): # for i in range(0,25):
# cityList.append(City(x=int(random.random() * 200), y=int(random.random() * 200))) # cityList.append(City(x=int(random.random() * 200), y=int(random.random() * 200)))
# geneticAlgorithm(population=cityList, popSize=100, eliteSize=20, mutationRate=0.01, generations=1000) # geneticAlgorithm(population=cityList, popSize=100, eliteSize=20, mutationRate=0.01, generations=1000)
# plotting the progress # plotting the progress
def geneticAlgorithmPlot(population, popSize, eliteSize, mutationRate, generations): def geneticAlgorithmPlot(population, popSize, eliteSize, mutationRate, generations):
@ -202,7 +221,7 @@ def geneticAlgorithmPlot(population, popSize, eliteSize, mutationRate, generatio
for i in range(0, generations): for i in range(0, generations):
pop = nextGeneration(pop, eliteSize, mutationRate) pop = nextGeneration(pop, eliteSize, mutationRate)
progress.append(1 / rankRoutes(pop)[0][1]) progress.append(1 / rankRoutes(pop)[0][1])
print("Final distance: " + str(1 / rankRoutes(pop)[0][1])) print("Final distance: " + str(1 / rankRoutes(pop)[0][1]))
bestRouteIndex = rankRoutes(pop)[0][0] bestRouteIndex = rankRoutes(pop)[0][0]
bestRoute = pop[bestRouteIndex] bestRoute = pop[bestRouteIndex]
@ -213,4 +232,4 @@ def geneticAlgorithmPlot(population, popSize, eliteSize, mutationRate, generatio
plt.show() plt.show()
return bestRoute return bestRoute
# geneticAlgorithmPlot(population=cityList, popSize=100, eliteSize=20, mutationRate=0.01, generations=1000) # geneticAlgorithmPlot(population=cityList, popSize=100, eliteSize=20, mutationRate=0.01, generations=1000)

Binary file not shown.

View File

@ -166,6 +166,7 @@ class Game():
for i in self.positive_decision: for i in self.positive_decision:
trash_x, trash_y = i.get_coords() trash_x, trash_y = i.get_coords()
# city_list.append(TSP.City(x=int(trash_x), y=int(trash_y), array=self.mapArray))
city_list.append(TSP.City(x=int(trash_x), y=int(trash_y))) city_list.append(TSP.City(x=int(trash_x), y=int(trash_y)))

View File

@ -4,6 +4,8 @@ from path_search_algorthms import a_star_utils as utils
def get_cost(start_x: int, start_y: int, target_x: int, target_y: int, array): def get_cost(start_x: int, start_y: int, target_x: int, target_y: int, array):
actions = search_path(start_x, start_y, utils.Rotation.NONE, target_x, target_y, array) actions = search_path(start_x, start_y, utils.Rotation.NONE, target_x, target_y, array)
if actions is None:
return 1
return len(actions) return len(actions)