def MST_PrimJarnik(g): """Compute a minimum spanning tree of weighted graph g. Return a list of edges that comprise the MST (in arbitrary order). """ d = {} # d[v] is bound on distance to tree tree = [] # list of edges in spanning tree pq = AdaptableHeapPriorityQueue() # d[v] maps to value (v, e=(u,v)) pqlocator = {} # map from vertex to its pq locator # for each vertex v of the graph, add an entry to the priority queue, with # the source having distance 0 and all others having infinite distance for v in g.vertices(): if len(d) == 0: # this is the first node d[v] = 0 # make it the root else: d[v] = float('inf') # positive infinity pqlocator[v] = pq.add(d[v], (v, None)) while not pq.is_empty(): key, value = pq.remove_min() u, edge = value # unpack tuple from pq del pqlocator[u] # u is no longer in pq if edge is not None: tree.append(edge) # add edge to tree for link in g.incident_edges(u): v = link.opposite(u) if v in pqlocator: # thus v not yet in tree # see if edge (u, v) better connects v to the growing tree wgt = link.element() if wgt < d[v]: # better edge to v? d[v] = wgt # update the distance pq.update(pqlocator[v], d[v], (v, link)) # update the pq entry return tree
def shortest_path_lengths(g, src): """Compute shortest-path distances from src to reachable vertices of g. Graph g can be undirected or directed, but must be weighted such that e.element() returns a numeric weight for each edge e. Return dictionary mapping each reachable vertex to its distance from src. """ d = {} # d[v] is upper bound from s to v cloud = {} # map reachable v to its d[v] value pq = AdaptableHeapPriorityQueue() # vertex v will have key d[v] pqlocator = {} # map from vertex to its pq locator # for each vertex v of the graph, add an entry to the priority queue, with # the source having distance 0 and all others having infinite distance for v in g.vertices(): if v is src: d[v] = 0 else: d[v] = float('inf') # syntax for positive infinity pqlocator[v] = pq.add(d[v], v) # save locator for future updates while not pq.is_empty(): key, u = pq.remove_min() cloud[u] = key # its correct d[u] value print(pqlocator[u]) # print distance from origin point and current point del pqlocator[u] # u is no longer in pq for e in g.incident_edges(u): # outgoing edges (u,v) v = e.opposite(u) if v not in cloud: # perform relaxation step on edge (u,v) wgt = e.element() if d[u] + wgt < d[v]: # better path to v? d[v] = d[u] + wgt # update the distance pq.update(pqlocator[v], d[v], v) # update the pq entry return cloud # only includes reachable vertices
def shortest_path_lengths(g, src): """Compute shortest-path distances from src to reachable vertices of g. Graph g can be undirected or directed, but must be weighted such that e.element() returns a numeric weight for each edge e. Return dictionary mapping each reachable vertex to its distance from src. """ d = { } # d[v] is upper bound from s to v # map reachable v to its d[v] value cloud = {} pq = AdaptableHeapPriorityQueue() # vertex v will have key d[v] pqlocator = {} # map from vertex to its pq locator # for each vertex v of the graph, add an entry to the priority queue, with # the source having distance 0 and all others having infinite distance for v in g.vertices(): if v is src: d[v] = 0 else: # syntax for positive infinity d[v] = float('inf') # save locator for future updates pqlocator[v] = pq.add(d[v], v) while not pq.is_empty(): key, u = pq.remove_min() cloud[u] = key # its correct d[u] value del pqlocator[u] # u is no longer in pq for e in g.incident_edges(u): # outgoing edges (u,v) v = e.opposite(u) if v not in cloud: # perform relaxation step on edge (u,v) wgt = e.element() if d[u] + wgt < d[v]: # better path to v? d[v] = d[u] + wgt # update the distance pq.update(pqlocator[v], d[v], v) # update the pq entry return cloud # only includes reachable vertices
def dijkstra(g, s): q = AdaptableHeapPriorityQueue() dist = {} locators = {} for v in g.vertices(): if v == s: v.dist = 0 else: v.dist = infinity l = q.add(v.dist, v) v.locator = l while q.__len__() > 0: (key, u) = q.remove_min() print("***", key, u) for e in g.incident_edges(u): w = g.opposite(u, e) print(u.__dict__) if w.dist > u.dist + e.element(): w.dist = u.dist + e.element() q.update(w.locator, w.dist, w)
This is a simple example that demonstrates how to use the heap-based priority queue """ from adaptable_heap_priority_queue import AdaptableHeapPriorityQueue if __name__ == '__main__': """ Note: it is a min-heap: highest priority means lowest priority key""" AH = AdaptableHeapPriorityQueue() # create new queue loc1 = AH.add(3, "event 1") # add some events in the queue loc2 = AH.add(1, "event 2") loc3 = AH.add(5, "event 3") loc4 = AH.add(4, "event 4") print("This is the current highest priority event: {0}".format( AH.min())) # only check, does not return the value print(AH.__len__()) # check length of queue print("Dequeue next event: {0}".format( AH.remove_min())) # removes and returns the highest priority event print(AH.__len__()) # check length of queue print("This is the current highest priority event: {0}".format( AH.min())) # only check, does not return the value AH.update(loc3, 0, "event 3") # updates the priority of one event print("This is the current highest priority event: {0}".format( AH.min())) # only check, does not return the value print("Dequeue next event: {0}".format(AH.remove_min())) print("Dequeue next event: {0}".format(AH.remove_min())) print("Dequeue next event: {0}".format(AH.remove_min())) print(AH.__len__()) # check length of queue
class FlightLandingControl(): def __init__(self, event_file): """ This function initialises the simulator. :param event_file: the file containing the "events" received by flight control """ self._queue = AdaptableHeapPriorityQueue() self._locator = {} self._event_file = event_file def _add_flight(self, priority, flight_no): """ This function adds a flight to the queue. :param priority: the priority level of the flight :param flight_no: the flight :return: """ loc = self._queue.add(priority, flight_no) self._locator[flight_no] = [loc, priority] def _update(self, new_priority, flight_no): """ This function updates the level of priority of a flight in the queue :param new_priority: the new level of priority :param flight_no: the flight """ loc = self._locator[flight_no] self._queue.update(loc[0], new_priority, flight_no) def _land(self): """ This function simulates the landing of a flight by printing a message e.g.: "Flight AZ1100 landed!" """ print("Flight {0} landed!".format(self._queue.remove_min())) def _process_event(self, line): """ This function should process one event contained in one "line" of the events file. :param line: a string representing the event, e.g. KK8989,sick passenger; flight,land; AZ1012,national etc. """ values = list(line.split(',')) flight_no = values[0] event = values[1] if event == "short": self._add_flight(2, flight_no) elif event == "long": self._add_flight(4, flight_no) elif event == "national": self._add_flight(6, flight_no) elif event == "land": self._land() elif event == "sick passenger": self._update(1, flight_no) elif event == "fuel low": self._update(1, flight_no) elif len(values) == 3: if values[2] == 'start': for loc in self._locator: if loc[0] == 'A' and loc[1] == 'Z': dat = self._locator[loc] self._queue.update(dat[0], dat[1] - 2, flight_no) if values[2] == 'stop': for loc in self._locator: if loc[0] == 'A' and loc[1] == 'Z': dat = self._locator[loc] self._queue.update(dat[0], dat[1] + 2, flight_no) def process_event_file(self): # open event file for reading file = open(self._event_file, "r") # each line is a new event for line in file.readlines(): print( "******************** Processing new event: {0}".format(line)) self._process_event(line) time.sleep(0.5)