-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 6ec195c
Showing
24 changed files
with
97,150 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
def aStar(adjList, getDistance, points, source, destination): | ||
def h(n): | ||
return getDistance(points, n, destination) | ||
|
||
frontier = set([source]) | ||
explored = set() | ||
g = {} # saves cost of path to start node, g(n) | ||
parent = {} | ||
|
||
g[source] = 0 | ||
parent[source] = source | ||
|
||
while len(frontier) > 0: | ||
current = None | ||
|
||
# find lowest f() successor | ||
for oNode in frontier: | ||
if current is None or g[oNode] + h(oNode) < g[current] + h(current): | ||
current = oNode # assign to current | ||
|
||
if current != destination: | ||
for successor in adjList[current]: | ||
cost = getDistance(points, current, successor) | ||
if successor not in frontier and successor not in explored: | ||
# add to openSet | ||
frontier.add(successor) | ||
parent[successor] = current | ||
g[successor] = g[current] + cost | ||
|
||
else: # successor is in frontier or has been explored | ||
if g[successor] > g[current] + cost: # existing path is suboptimal | ||
# replace with better path | ||
g[successor] = g[current] + cost | ||
parent[successor] = current | ||
|
||
if current in explored: | ||
# recheck | ||
explored.remove(current) | ||
frontier.add(current) | ||
else: | ||
path = [] | ||
while parent[current] != current: # this is only false for start node | ||
path.append(current) | ||
current = parent[current] # move up hierarchy | ||
path.append(source) | ||
path.reverse() | ||
return path | ||
|
||
# move current from frontier to explored | ||
frontier.remove(current) | ||
explored.add(current) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
from collections import defaultdict | ||
import random | ||
|
||
α = 0.5 # pheromone level importance | ||
Q = 1 # pheromone deposit amount | ||
ρ = 0.2 # evaporation rate | ||
bonus = 1 # pheromone deposited on path to destination | ||
iterations = 100 | ||
antCount = 100 | ||
|
||
# ant colony optimization algorithm | ||
def aco(adjList, getDistance, points, source, destination): | ||
# intialize pheromone levels | ||
# use functions to get and set pheromone levels | ||
|
||
# defaultdict with defaultvalue .1 | ||
pheromoneLevels = defaultdict(lambda: 0.1) | ||
|
||
def getPheromoneLevel(node1, node2): | ||
return pheromoneLevels[(node1, node2)] | ||
|
||
def setPheromoneLevel(node1, node2, value): | ||
# do both so order doesn't matter | ||
pheromoneLevels[(node1, node2)] = value | ||
pheromoneLevels[(node2, node1)] = value | ||
|
||
# initialize ants | ||
ants = [[source]] * antCount | ||
|
||
# run iterations | ||
for _ in range(iterations): | ||
destPaths = [] | ||
pheromoneDeposited = [] | ||
# move ants | ||
for antI, ant in enumerate(ants): | ||
current = ant[-1] | ||
if current == destination: | ||
destPaths.append(ant) | ||
# move ant to source | ||
ants[antI] = [source] | ||
continue | ||
|
||
probablities = [] | ||
possible = [node for node in adjList[current] if node not in ant] | ||
for node in possible: | ||
probablities.append( | ||
(getPheromoneLevel(current, node) ** α) * (getDistance(points, current, node) ** (1 - α)) | ||
) | ||
|
||
if len(possible) == 0: | ||
# move ant to source | ||
ants[antI] = [source] | ||
continue | ||
|
||
# choose next node | ||
nextNode = random.choices(possible, probablities)[0] | ||
|
||
# deposit pheromone | ||
pheromoneDeposited.append((current, nextNode)) | ||
|
||
# move ant | ||
ant.append(nextNode) | ||
|
||
# update pheromone levels | ||
for node1 in adjList.keys(): | ||
for node2 in adjList[node1]: | ||
# check if pheromone was deposited | ||
Δτ = 0 | ||
if (node1, node2) in pheromoneDeposited or (node2, node1) in pheromoneDeposited: | ||
Δτ = Q / getDistance(points, node1, node2) | ||
|
||
# evaporate pheromone | ||
τ = (1-ρ) * getPheromoneLevel(node1, node2) + Δτ | ||
setPheromoneLevel(node1, node2, τ) | ||
for path in destPaths: | ||
# deposit pheromone | ||
for i in range(len(path) - 1): | ||
node1 = path[i] | ||
node2 = path[i + 1] | ||
setPheromoneLevel(node1, node2, getPheromoneLevel(node1, node2) + bonus) | ||
|
||
|
||
# find path with highest pheromone level | ||
path = [source] | ||
current = source | ||
while current != destination: | ||
# find next node in path | ||
nextNode = None | ||
maxPheromoneLevel = 0 | ||
|
||
for node in [node for node in adjList[current] if node not in path]: | ||
if (new := getPheromoneLevel(current, node)) > maxPheromoneLevel: | ||
nextNode = node | ||
maxPheromoneLevel = new | ||
|
||
current = nextNode | ||
path.append(current) | ||
|
||
return path |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
def bfs(adjList, getDistance, points, source, destination,): | ||
queue = [(source,[source])] | ||
visited = set() | ||
|
||
while queue: | ||
vertex, path = queue.pop(0) | ||
visited.add(vertex) | ||
for node in adjList[vertex]: | ||
if node == destination: | ||
return path + [destination] | ||
else: | ||
if node not in visited: | ||
visited.add(node) | ||
queue.append((node, path + [node])) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
def bidirectional(adjList, getDistance, points, source, destination): | ||
# Get dictionary of currently active vertices with their corresponding paths. | ||
frontier = {source: [source], destination: [destination]} | ||
# Vertices we have already examined. | ||
explored = set() | ||
|
||
while len(frontier) > 0: | ||
|
||
# Make a copy of active vertices so we can modify the original dictionary as we go. | ||
active_vertices = list(frontier.keys()) | ||
for vertex in active_vertices: | ||
# Get the path to where we are. | ||
current_path = frontier[vertex] | ||
# Record whether we started at start or goal. | ||
origin = current_path[0] | ||
# Check for new neighbours. | ||
current_neighbours = set(adjList[vertex]) - explored | ||
# Check if our neighbours hit an active vertex | ||
if len(current_neighbours.intersection(active_vertices)) > 0: | ||
for meeting_vertex in current_neighbours.intersection(active_vertices): | ||
# Check the two paths didn't start at same place. If not, then we've got a path from start to goal. | ||
if origin != frontier[meeting_vertex][0]: | ||
# Reverse one of the paths. | ||
frontier[meeting_vertex].reverse() | ||
# return the combined results | ||
return frontier[vertex] + frontier[meeting_vertex] | ||
|
||
# No hits, so check for new neighbours to extend our paths. | ||
if len(set(current_neighbours) - explored - set(active_vertices)) == 0: | ||
# If none, then remove the current path and record the endpoint as inactive. | ||
frontier.pop(vertex, None) | ||
explored.add(vertex) | ||
else: | ||
# Otherwise extend the paths, remove the previous one and update the inactive vertices. | ||
for neighbour_vertex in current_neighbours - explored - set(active_vertices): | ||
frontier[neighbour_vertex] = current_path + [neighbour_vertex] | ||
active_vertices.append(neighbour_vertex) | ||
frontier.pop(vertex, None) | ||
explored.add(vertex) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
def dfs(adjList, getDistance, points, source, destination): | ||
def _dfs(adjList, node, destination, currentPath): | ||
if node == destination: | ||
# found path | ||
currentPath.append(node) | ||
return True | ||
visited.add(node) | ||
for successor in adjList[node]: | ||
if successor not in visited: | ||
currentPath.append(node) | ||
if _dfs(adjList, successor, destination, currentPath): | ||
return True | ||
currentPath.pop(-1) | ||
|
||
visited = set() # to make sure it doesn't loop on itself | ||
currentPath = [] | ||
_dfs(adjList, source, destination, currentPath) | ||
return currentPath |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
from collections import defaultdict | ||
import heapq as heap | ||
|
||
def dijkstras(adjList, getDistance, points, source, destination): | ||
visited = set() | ||
parent = {source: source} | ||
pQ = [] | ||
heap.heappush(pQ, (0, source)) | ||
g = defaultdict(lambda: float('inf')) # f() = g() (h(n) is 0, as there is no heuristic) | ||
g[source] = 0 | ||
|
||
while pQ: | ||
# greedy | ||
_, node = heap.heappop(pQ) | ||
if node == destination: | ||
break | ||
visited.add(node) | ||
|
||
for successor in adjList[node]: | ||
if successor not in visited: | ||
if g[successor] > (new := g[node] + getDistance(points, node, successor)): | ||
parent[successor] = node | ||
g[successor] = new | ||
heap.heappush(pQ, (new, successor)) | ||
|
||
path = [] | ||
current = destination | ||
while parent[current] != current: # this is only false for start node | ||
path.append(current) | ||
current = parent[current] # move up hierarchy | ||
path.append(source) | ||
path.reverse() | ||
return path |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
MAX = 1000 | ||
def greedy(adjList, getDistance, points, source, destination): | ||
current = source | ||
path = [source] | ||
i = 0 | ||
while current != destination and i < MAX: | ||
current = min(adjList[current], key=lambda x: getDistance(points, x, destination)) | ||
path.append(current) | ||
i += 1 | ||
if i >= MAX: | ||
return -1 | ||
return path |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
def idaStar(adjList, getDistance, points, source, destination): | ||
FOUND = -1 # -1 does not mean error | ||
NOT_FOUND = -2 | ||
|
||
def h(n): | ||
return getDistance(points, n, destination) | ||
|
||
def search(path, g, bound): | ||
node = path[-1] | ||
f = g + h(node) | ||
if f > bound: return f | ||
if node == destination: return FOUND | ||
minimum = float("inf") | ||
for successor in adjList[node]: | ||
path.append(successor) | ||
t = search(path, g + getDistance(points, node, successor), bound) | ||
if t == FOUND: return FOUND | ||
if t < minimum: minimum = t | ||
path.pop(-1) | ||
return minimum | ||
|
||
bound = h(source) | ||
path = [source] | ||
|
||
while True: | ||
t = search(path, 0, bound) | ||
if t == FOUND: return path | ||
if t == float("inf"): return NOT_FOUND | ||
bound = t | ||
|
||
def idaStar_iterative(adjList, getDistance, points, source, destination): | ||
NOT_FOUND = -1 | ||
|
||
def h(n): | ||
return getDistance(points, n, destination) | ||
|
||
stack = [(source, 0, h(source))] | ||
while stack: | ||
node, g, bound = stack.pop() | ||
if node == destination: | ||
return [node] | ||
f = g + h(node) | ||
if f > bound: | ||
continue | ||
for successor in adjList[node]: | ||
cost = g + getDistance(points, node, successor) | ||
stack.append((successor, cost, bound)) | ||
|
||
return NOT_FOUND |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# fixes the csv file for incomplete runs | ||
import csv | ||
|
||
AFTER = { | ||
"bfs": "dfs", | ||
"dfs": "dijkstras", | ||
"dijkstras": "aStar", | ||
"aStar": "bidirectional", | ||
"bidirectional": "greedy", | ||
"greedy": "bfs" | ||
} | ||
|
||
# steps | ||
# 1. start on first row of csv file | ||
# 2. if some rows do not have all algorithms, delete them | ||
|
||
# read csv file | ||
with open('1024 copy.csv', 'r') as file: | ||
reader = csv.reader(file) | ||
data = list(reader) | ||
|
||
deleteIndices = [] # saves indices of rows to be deleted | ||
currentTrial = [] | ||
for i, row in enumerate(data): | ||
# if row is header, skip or first row | ||
if row[0] == "Algorithm" or i == 1: | ||
continue | ||
|
||
currentTrial.append(i) | ||
# check row after, unless it is the last row | ||
if i < len(data) - 1: | ||
if data[i + 1][0] == AFTER[row[0]]: | ||
continue | ||
else: | ||
# delete all rows in current trial | ||
deleteIndices += currentTrial | ||
currentTrial = [] | ||
|
||
# delete rows | ||
for i in sorted(deleteIndices, reverse=True): | ||
del data[i] | ||
|
||
|
||
# write to csv file | ||
with open('1024 copy.csv', 'w', newline='') as file: | ||
writer = csv.writer(file) | ||
writer.writerows(data) |
Binary file not shown.
Large diffs are not rendered by default.
Oops, something went wrong.
Oops, something went wrong.