class TestSimulation(unittest.TestCase): def setUp(self): self.test_graph = Graph() self.test_node_0 = Node(0, 0.1, 1, 1, 1, 1, 1, 1) self.test_node_1 = Node(1, 0.2, 2, 2, 2, 2, 2, 2) self.test_node_2 = Node(2, 0.3, 1, 2, 3, 4, 5, 6) self.test_graph.add_vertex(self.test_node_0) self.test_graph.add_vertex(self.test_node_1) self.test_graph.add_vertex(self.test_node_2) self.test_graph.add_edge(self.test_node_0, self.test_node_1, 30) self.test_graph.add_edge(self.test_node_1, self.test_node_2, 50) self.test_sim = Simulation() self.test_sim.load_graph(self.test_graph) def test_spread(self): res1 = min(1, Simulation.sigmoid(30) * 0.15) res2 = min(1, Simulation.sigmoid(60) * 0.25 * 1.2) self.assertAlmostEqual( Simulation.spread(self.test_node_0, self.test_node_1), res1) self.assertAlmostEqual( Simulation.spread(self.test_node_1, self.test_node_2), res2) def test_calc_new_score(self): res = (Simulation.spread(self.test_node_0, self.test_node_1) + Simulation.spread(self.test_node_2, self.test_node_1)) / 2 self.assertAlmostEqual(self.test_sim.calc_new_score(self.test_node_1), res) def test_run_one_timestep(self): print(self.test_sim.graph.get_scores()) self.test_sim.run_one_timestep() print(self.test_sim.graph.get_scores())
def extended_popularity_similarity_optimisation_model(N, m, L=0, beta=1 / 2, T=0): def distance(i, j): r_i, phi_i, r_j, phi_j = r[i], phi[i], r[j], phi[j] r_j = beta * r_i + (1 - beta) * r_j d_phi = pi - abs(pi - abs(phi_i - phi_j)) return cosh(r_i) * cosh(r_j) + sinh(r_i) * sinh(r_j) * cos(d_phi) if beta == 0: def cutoff(r_i): return r_i - 2 * log(T / sin(T * pi) * (1 - exp(-r_i / 2)) / m) elif beta == 1: def cutoff(r_i): return r_i - 2 * log(T / sin(T * pi) * r_i / m) else: def cutoff(r_i): return r_i - 2 * log(T / sin(T * pi) * (1 - exp(-r_i * (1 - beta) / 2)) / m / (1 - beta)) def connection_probability(d_ij, cutoff_i): return 1 / (1 + exp((d_ij - cutoff_i) / 2 / T)) G = Graph() r = [2 * math.log(i + 1) for i in range(N)] phi = [2 * math.pi * random.random() for _ in range(N)] for i in range(N): G.add_vertex(i, r=r[i], phi=phi[i]) #G.add_vertex(i, x=r[i]*math.cos(phi[i]), y=r[i]*math.sin(phi[i])) m += 2 * L * (1 - beta) / (1 - N**(beta - 1))**2 / (2 * beta - 1) * ( (N / i)**(2 * beta - 1) - 1) * (1 - i**(beta - 1)) if i <= m: for j in range(i): G.add_edge(i, j) elif T == 0: neighbours = sorted(range(i), key=lambda j: distance(i, j))[m] for j in neighbours: G.add_edge(i, j) else: cutoff_i = cutoff(r[i]) for j in range(i): d_ij = distance(r[i], phi[i], r[j], phi[j]) if random.random() < connection_probability(d_ij, cutoff_i): G.add_edge(i, j) return G
def popularity_similarity_optimisation_model(N, m, beta=1 / 2, T=0): def distance(i, j): r_i, phi_i, r_j, phi_j = r[i], phi[i], r[j], phi[j] r_j = beta * r_i + (1 - beta) * r_j d_phi = pi - abs(pi - abs(phi_i - phi_j)) return acosh( cosh(r_i) * cosh(r_j) + sinh(r_i) * sinh(r_j) * cos(d_phi)) if beta == 0: def cutoff(r_i): return r_i - 2 * log(T / sin(T * pi) * (1 - exp(-r_i / 2)) / m) elif beta == 1: def cutoff(r_i): return r_i - 2 * log(T / sin(T * pi) * r_i / m) else: def cutoff(r_i): return r_i - 2 * log(T / sin(T * pi) * (1 - exp(-r_i * (1 - beta) / 2)) / m / (1 - beta)) def connection_probability(d_ij, cutoff_i): return 1 / (1 + exp((d_ij - cutoff_i) / 2 / T)) G = Graph() r = [2 * math.log(i) for i in range(1, N + 1)] phi = [2 * math.pi * random.random() for _ in range(N)] for i in range(N): G.add_vertex(i, r=geometry.native_disk_to_hyperboloid(r[i]), phi=phi[i]) if i <= m: for j in range(i): G.add_edge(i, j) elif T == 0: print(i) print(sorted(range(i), key=lambda v: v)) neighbours = sorted(range(i), key=lambda j: distance(i, j))[:m] for j in neighbours: G.add_edge(i, j) else: cutoff_i = cutoff(r[i]) for j in range(i): d_ij = distance(r[i], phi[i], r[j], phi[j]) if random.random() < connection_probability(d_ij, cutoff_i): G.add_edge(i, j) return G
class ZipGraph: def __init__(self): self.g = Graph() self.vehiclesByZip = {} pass #Adds weighted edge to the graph by passing in a ZipDistance object. Adds key to vehicles dictionary. def addDist(self, zipDist: ZipDistance): self.g.add_edge(zipDist.zip1, zipDist.zip2, weight=zipDist.dist) for e in self.g.nodes: self.vehiclesByZip.update({str(e): []}) #Constructs all the edges, weights, and vertices from a ZipDistanceList. def constructFromZDList(self, zList: ZipDistanceList): for d in zList.zList: self.addDist(d) #Dijkstras algorithm utilizing priority queue to find the distances to all other nodes (zips) from the current node. #Returns dictionary in the form of zip:shortestPathFromStart def dijkstras(self, startZip): pq = PriorityQueue() distance = {} for n in self.g.nodes: distance[n] = sys.maxsize pq.put((0, startZip)) distance[startZip] = 0 while not pq.empty(): #loop until no nodes are left u = pq.get()[1] for v in iter(self.g[u]): alt = distance[u] + int(self.g[u][v]['weight']) if alt < distance[v]: distance[v] = alt pq.put((distance[v], v)) return distance #Takes in an EmergencyVehicleList and adds those vehicles to the dictionary of locations in the #current ZipGraph instance. def updateVehicleLocations(self, elist: EmergencyVehicleList): for vehicle in elist: try: zipList = self.vehiclesByZip[str(vehicle.zip)] except: self.vehiclesByZip.update({str(vehicle.zip): []}) zipList = self.vehiclesByZip[str(vehicle.zip)] zipList.append(vehicle) self.vehiclesByZip.update({str(vehicle.zip): zipList}) #Finds the closest vehicle of a requested type to a requested zip. Goes to nearest zip, sees if #vehicle type is there, then continues if not. def closestVehicle(self, startZip, vehicleType): dists = self.dijkstras(startZip) pq = PriorityQueue() for d in dists: pq.put((dists[d], d)) while not pq.empty(): u = pq.get()[1] for e in self.vehiclesByZip[str(u)]: if e.vType == str(vehicleType): return e, dists[u] dists.pop(u) # Takes in request, finds closest available vehicle, updates request # vehicleID and distance, removes vehicle from ZipGraph(no double assignments) def fillReq(self, req: Request): closestV, distance = self.closestVehicle(req.zip, req.vType) req.distance = distance req.vehicle = closestV.id oldZipData = self.vehiclesByZip[closestV.zip] oldZipData.remove(closestV) self.vehiclesByZip[closestV.zip] = oldZipData return req # Takes a RequestList and processes each by calling fillReq() def fillReqList(self, reqL: RequestList): for r in reqL: r = self.fillReq(r) return reqL #Prints the graph of the Zips. Does not include vehicles at each zip. def __str__(self): return str(self.g)
class TestGraph(unittest.TestCase): def setUp(self): self.test_graph = Graph() self.test_node_0 = Node(0, 0.1, 1, 1, 1, 1, 1, 1) self.test_node_1 = Node(1, 0.1, 1, 1, 1, 1, 1, 1) def test_add_vertex(self): # add the two test nodes self.test_graph.add_vertex(self.test_node_0) self.test_graph.add_vertex(self.test_node_1) # see if they are in the graph vertex dictionary self.assertEqual(len(self.test_graph.vertices), 2) self.assertTrue(0 in self.test_graph.vertices) self.assertTrue(1 in self.test_graph.vertices) # if node already in graph, do not allow adding with self.assertRaises(AssertionError): self.test_graph.add_vertex(self.test_node_0) def test_add_edge(self): n0, n1 = self.test_node_0, self.test_node_1 strength: int = 10 self.test_graph.add_vertex(n0) self.test_graph.add_vertex(n1) self.test_graph.add_edge(n0, n1, strength) self.assertTrue(1 in n0.neighbours) self.assertTrue(0 in n1.neighbours) # check bidirectional strength self.assertEqual(n0.neighbours[1], strength) self.assertEqual(n1.neighbours[0], strength) # do not allow adding the same edge with self.assertRaises(AssertionError): self.test_graph.add_edge(n0, n1, strength) with self.assertRaises(AssertionError): self.test_graph.add_edge(n1, n0, strength) def test_remove_vertex(self): n0, n1 = self.test_node_0, self.test_node_1 n2 = Node(2, 0.1, 1, 1, 1, 1, 1, 1) self.test_graph.add_vertex(n0) self.test_graph.add_vertex(n1) self.test_graph.add_vertex(n2) self.test_graph.add_edge(n0, n1, 5) self.test_graph.add_edge(n1, n2, 15) self.test_graph.add_edge(n2, n0, 25) self.test_graph.remove_vertex(0) # test_node_0 no longer in neighbours dicts self.assertFalse(0 in n1.neighbours) self.assertFalse(0 in n2.neighbours) # neighbours edges intact self.assertTrue(2 in n1.neighbours) self.assertTrue(1 in n2.neighbours) self.assertFalse(0 in self.test_graph.vertices) # try to remove something that is removed with self.assertRaises(AssertionError): self.test_graph.remove_vertex(0) self.test_graph.remove_vertex(1) self.assertFalse(1 in n2.neighbours) def test_get_node(self): self.test_graph.add_vertex(self.test_node_0) self.assertEqual(self.test_graph.get_node(0), self.test_node_0) with self.assertRaises(AssertionError): self.test_graph.get_node(1)