Skip to content

Commit

Permalink
Initial Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
python9160 committed Jan 22, 2023
0 parents commit 6ec195c
Show file tree
Hide file tree
Showing 24 changed files with 97,150 additions and 0 deletions.
27,222 changes: 27,222 additions & 0 deletions 1024 copy.csv

Large diffs are not rendered by default.

69,265 changes: 69,265 additions & 0 deletions 1024.csv

Large diffs are not rendered by default.

Binary file added __pycache__/utils.cpython-310.pyc
Binary file not shown.
Binary file added algorithms/__pycache__/aStar.cpython-310.pyc
Binary file not shown.
Binary file added algorithms/__pycache__/aco.cpython-310.pyc
Binary file not shown.
Binary file added algorithms/__pycache__/bfs.cpython-310.pyc
Binary file not shown.
Binary file added algorithms/__pycache__/bidirectional.cpython-310.pyc
Binary file not shown.
Binary file added algorithms/__pycache__/dfs.cpython-310.pyc
Binary file not shown.
Binary file added algorithms/__pycache__/dijkstras.cpython-310.pyc
Binary file not shown.
Binary file added algorithms/__pycache__/greedy.cpython-310.pyc
Binary file not shown.
Binary file added algorithms/__pycache__/idaStar.cpython-310.pyc
Binary file not shown.
51 changes: 51 additions & 0 deletions algorithms/aStar.py
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)
99 changes: 99 additions & 0 deletions algorithms/aco.py
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
14 changes: 14 additions & 0 deletions algorithms/bfs.py
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]))
39 changes: 39 additions & 0 deletions algorithms/bidirectional.py
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)
18 changes: 18 additions & 0 deletions algorithms/dfs.py
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
33 changes: 33 additions & 0 deletions algorithms/dijkstras.py
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
12 changes: 12 additions & 0 deletions algorithms/greedy.py
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
49 changes: 49 additions & 0 deletions algorithms/idaStar.py
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
47 changes: 47 additions & 0 deletions clean.py
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 added data.xlsx
Binary file not shown.
76 changes: 76 additions & 0 deletions graph.ipynb

Large diffs are not rendered by default.

Loading

0 comments on commit 6ec195c

Please sign in to comment.