ULP-ActivitySupport – blob

You can use Git to clone the repository via the web URL. Download snapshot (zip)
Add batch simulation code with instructions
[ULP-ActivitySupport] / batch-simulation
1 #!/usr/bin/env python3\r
2 \r
3 import copy\r
4 import json\r
5 import math\r
6 import random\r
7 \r
8 from data import Position\r
9 \r
10 \r
11 class RoutingEngine:\r
12     def __init__(self, context, network):\r
13         self.context = context\r
14         self.network = network\r
15         for edge_id in self.network['edges']:\r
16             nodeA = self.network['edges'][edge_id]['nodes'][0]\r
17             nodeB = self.network['edges'][edge_id]['nodes'][1]\r
18             distance = self.get_node_distance(nodeA, nodeB)\r
19             self.network['edges'][edge_id]['length'] = distance\r
20         self.hops = self.calculate_hops(self.network)\r
21 \r
22     def calculate_hops(self, network):\r
23         result = {}\r
24         for source_node in network['nodes']:\r
25             result[source_node] = {}\r
26             for edge_id in network['edges']:\r
27                 edge = network['edges'][edge_id]\r
28                 target_node = None\r
29                 if edge['nodes'][0] == source_node:\r
30                     target_node = edge['nodes'][1]\r
31                 if edge['nodes'][1] == source_node:\r
32                     target_node = edge['nodes'][0]\r
33                 if target_node is not None:\r
34                     result[source_node][target_node] = edge['length']\r
35             if len(result[source_node].keys()) > 2:\r
36                 self.network['nodes'][source_node]['is_crossroad'] = True\r
37             else:\r
38                 self.network['nodes'][source_node]['is_crossroad'] = False\r
39         return result\r
40 \r
41     def shuffle_mirs(self, density):\r
42         crossing_nodes = [node for node in self.network['nodes'] if self.network['nodes'][node]['is_crossroad']]\r
43         targets = random.sample(crossing_nodes, round(density * len(crossing_nodes)))\r
44         for node in self.network['nodes']:\r
45             self.network['nodes'][node]['has_mir'] = node in targets\r
46 \r
47     def is_confusing(self, node):\r
48         return self.network['nodes'][node]['is_crossroad'] and not self.network['nodes'][node]['has_mir']\r
49 \r
50     def get_network(self):\r
51         return self.network\r
52 \r
53     def get_connected_nodes(self, node):\r
54         return list(self.hops[node].keys())\r
55 \r
56     def get_node_distance(self, nodeA, nodeB):\r
57         coordsA = self.network['nodes'][nodeA]\r
58         coordsB = self.network['nodes'][nodeB]\r
59         return math.sqrt((float(coordsB['x']) - float(coordsA['x'])) ** 2 + (float(coordsB['y']) - float(coordsA['y'])) ** 2)\r
60 \r
61     def get_route_distance(self, nodeA, nodeB):\r
62         route = self.route_between_nodes(nodeA, nodeB)\r
63         distance = 0\r
64         while len(route) >= 2:\r
65             distance += self.get_node_distance(route[0], route[1])\r
66             del route[0]\r
67         return distance\r
68 \r
69     def get_angle(self, x1, y1, x2, y2):\r
70         dotProduct = x1 * x2 + y1 * y2\r
71         lengthProduct = math.sqrt(x1 * x1 + y1 * y1) * math.sqrt(x2 * x2 + y2 * y2)\r
72         cos = dotProduct / lengthProduct\r
73         return math.acos(cos)\r
74 \r
75     def get_next_straight_node(self, previous, current, candidates):\r
76         coordsPrev = self.network['nodes'][previous]\r
77         coordsCur = self.network['nodes'][current]\r
78         direction = [float(coordsCur['x']) - float(coordsPrev['x']), float(coordsCur['y']) - float(coordsPrev['y'])]\r
79         chosen = None\r
80         bestAngle = None\r
81         for candidate in candidates:\r
82             coordsCand = self.network['nodes'][candidate]\r
83             candDir = [float(coordsCand['x']) - float(coordsCur['x']), float(coordsCand['y']) - float(coordsCur['y'])]\r
84             angle = self.get_angle(candDir[0], candDir[1], direction[0], direction[1])\r
85             if bestAngle is None or angle < bestAngle:\r
86                 chosen = candidate\r
87                 bestAngle = angle\r
88         return chosen\r
89 \r
90     def route_between_nodes(self, nodeA, nodeB):\r
91         unvisited = {node: float('inf') for node in self.hops}\r
92         visited = {}\r
93         previous = {}\r
94         current = nodeA\r
95         currentDistance = 0\r
96         unvisited[current] = currentDistance\r
97 \r
98         while True:\r
99             for neighbour, distance in self.hops[current].items():\r
100                 if neighbour not in unvisited:\r
101                     continue\r
102                 newDistance = currentDistance + distance\r
103                 if unvisited[neighbour] is None or unvisited[neighbour] > newDistance:\r
104                     unvisited[neighbour] = newDistance\r
105                     previous[neighbour] = current\r
106             visited[current] = currentDistance\r
107             del unvisited[current]\r
108             if current == nodeB or not unvisited:\r
109                 break\r
110             candidates = [node for node in unvisited.items() if node[1]]\r
111             current, currentDistance = sorted(candidates, key = lambda x: x[1])[0]\r
112 \r
113         result = []\r
114         node = nodeB\r
115         while node != nodeA:\r
116             result.insert(0, node)\r
117             node = previous[node]\r
118         result.insert(0, node)\r
119         return result\r
120 \r