1 year ago
#308799
Hermit
Python Temperamentally Accessing Global Object from within a Function (which references that object from within another)
(Edit: Fundamentally my problem is that python is sometimes creating new instances of an object x
,which I accessed by another object y
, accessed by z
instead of editing the original x
directly. x
and y
both belong to a list of global variables, but when I access y
via z
to access x
via y
on a subsequent iteration of my recursive algorithm, its information isn't always correctly updated.)
Introduction
I'm writing a recursive function to emulate this version of Dijkstra's algorithm (Problem 2) with input from a CSV file. I have two globals Branches []
and Nodes []
to store all branch
and node
python objects. (I'll put how everything is initialized below).
When I attempt to change the set
of the destination node of my branch from within my function, python generates a new object. It's not that it cannot access global Branches
, because it does function correctly when the start node of the branch I am accessing is the same as the origin.
Update: I tried searching through the global list for a node with the label matching the one I wanted to change, but while this correctly changed the set of the global none of the branches referencing that node recognized the change
def dijkstra_algorithm(node_being_investigated, origin_node, destination_node):
...
for branch in shortest_route.requisite_branches:
# finding the new branch added to the route and adding it to set I and its destination to set A
if branch not in branches_in_set_I:
print(f"adding the new branch {branch.info()} to set I")
print(f"Adding the new node {branch.destination.info()} to set A")
print(f"The New Node: {branch.destination} ")
branch.set = "I"
branch.destination.set = "A"
# a redundancy I added just in case the for loop was somehow messing with things
shortest_route.requisite_branches[0].destination.set="A"
if destination in obtain_nodes_of_set("A"):
return shortest_route
else:
return dijkstra_algorithm(shortest_route.requisite_branches[0].destination, origin, destination)
NB: There is one other class Routes
which stores a list of branches and their cumulative time. I suspect that since this is the only place some operation is performed on a node
or branch
, the problem is linked to this somehow. However, since I'm not sure how, here's a small table of contents of all the code snippets I've attached. I can send more (or even the whole file) if need be.
The Code Below
- the way I define the
Node
andBranch
classes - the initialization of everything from the CSVs
- the way I define the
Route
class - the
search_to_origin
function which finds the overall length of variousRoute
options - the piece of the
dijkstra_algorithm
function which finds theshortest_route
inputted to this piece of the algorithm
Defining the Node and Branch classes
class Node:
def __init__(self, label, set):
self.label = label
self.set = set and set or "C"
print(f"\n\n!!!creating new node object with label {self.label}!!!\n\n")
def info(self):
return f"Set {self.set}: [[{self.label}]]"
and:
class Branch:
def __init__(self, origin, destination, duration, set):
self.origin = origin
self.destination = destination
self.duration = duration
self.set = set and set or "III"
def info(self):
return f"Set {self.set}:{self.origin.info()} -> {self.destination.info()} ({self.duration})"
Initializing the global Lists from the CSVs
From what I've checked by printing out the object IDs this seems to be working correctly, but since I'm not actually sure where the problem lies, I'm including it just in case
with open('nodes.csv') as csv_file:
csv_reader = csv.DictReader(csv_file)
for row in csv_reader:
Nodes.append(Node(row["LABEL"], 99999, "C"))
# here all the roads are read into the global list of branches
with open('roads.csv') as csv_file:
csv_reader = csv.DictReader(csv_file)
for row in csv_reader:
branch_info = {}
# getting the actual node objects to attach
for node in Nodes:
if node.label == row["ORIGIN"]:
branch_info['origin'] = node
if node.label == row["DESTINATION"]:
branch_info['destination'] = node
Branches.append(Branch(branch_info['origin'], branch_info['destination'], int(row["DURATION"]), "III"))
The Route Class and the Main Function Operating on It
There is a sub function called by the overall algorithm which traces the route from a list of branches
back to a specified origin
node object. Afterwards it returns a list of possible_routes
to the main dijkstra function, for that function to decide which is quickest.
Route Class Initialization
class Route:
def __init__(self, branch_list, duration):
self.requisite_branches = branch_list
self.duration = duration
def extend_route(self, branch):
self.requisite_branches.append(branch)
self.duration += branch.duration
The function determining routes to the origin
Node that this calls a utility function find_attached_branches
which searches for branches with a node
as its origin or destination
from a specific set
.
def search_to_origin(origin, branches, route):
print("\n Searching to origin...")
possible_routes = []
# for each of the branches being investigated
for branch in branches:
# if this branch has not already been investigated in this route
if branch not in route.requisite_branches:
# this is a new individual route being investigated
new_route = copy.deepcopy(route)
new_route.extend_route(branch)
# if the start node has been found this is a possible route
if branch.origin == origin:
print("This branch leads to the origin")
possible_routes.append(new_route)
# if the start node has not been found search for branches preceding this one
else:
branches_to_this_node = find_attached_branches(branch.origin, 'destination, "II")
branches_to_this_node.extend(find_attached_branches(branch.origin, 'destination, "I"))
if len(branches_to_this_node) != 0:
print("this branch does not lead to the origin")
route_to_start = search_to_origin(origin, branches_to_this_node, new_route)
possible_routes.extend(route_to_start)
# return the lengths and requisite branches found
return possible_routes
Finding the Quickest Route to the Origin From a Given Node in B
This portion of the algorithm is done just before the one you see in the introduction section. The way it functions should be independent of whether the shortest route only consists of one branch, but this doesn't seem to be the case. It goes through the following steps:
- Looks for all the nodes now in set B.
- For each of these nodes it finds all the branches attached to each node in set B.
- For all of those branches it looks for routes back to the origin.
- From all of the resulting routes it determines the
shortest_route
global Nodes
# get all the nodes in set B
nodes_in_set_B = obtain_nodes_of_set("B")
# get all branches in sets I or II
global Branches
branches_in_I_or_II = []
for branch in Branches:
if branch.set != "III": branches_in_I_or_II.append(branch)
# the shortest route found from one of the nodes of set B. Initialized as a large empty route
shortest_route = Route([], 99999)
if nodes_in_set_B is not None:
for node in nodes_in_set_B:
# the branches under consideration are only those to this node in set B
branches_under_consideration = []
for branch in branches_in_I_or_II:
if branch.destination == node: branches_under_consideration.append(branch)
possible_routes = search_to_origin(origin, branches_under_consideration, Route([], 0))
# finding the possible route of minimum length
for route in possible_routes:
if route.duration < shortest_route.duration:
shortest_route = route
python
pointers
dijkstra
0 Answers
Your Answer