| 1223 | |
| 1224 | def bidirectional_dijkstra(self,x,y): |
| 1225 | r""" |
| 1226 | Returns the shortest path between x and y using |
| 1227 | a bidirectional version of Dijkstra |
| 1228 | |
| 1229 | EXAMPLE:: |
| 1230 | |
| 1231 | sage: G = Graph(graphs.PetersenGraph(), implementation='c_graph') |
| 1232 | sage: for (u,v) in G.edges(labels=None): |
| 1233 | ... G.set_edge_label(u,v,1) |
| 1234 | sage: G.shortest_path(0,1,by_weight=True) |
| 1235 | [0, 1] |
| 1236 | |
| 1237 | TEST: |
| 1238 | |
| 1239 | Bugfix from #7673 :: |
| 1240 | |
| 1241 | sage: G = Graph(implementation="networkx") |
| 1242 | sage: G.add_edges([(0,1,9),(0,2,8),(1,2,7)]) |
| 1243 | sage: Gc = G.copy(implementation='c_graph') |
| 1244 | sage: sp = G.shortest_path_length(0,1,by_weight=True) |
| 1245 | sage: spc = Gc.shortest_path_length(0,1,by_weight=True) |
| 1246 | sage: sp == spc |
| 1247 | True |
| 1248 | """ |
| 1249 | |
| 1250 | if x==y: |
| 1251 | return 0 |
| 1252 | |
| 1253 | # ****************** WARNING ********************** |
| 1254 | # Use Python to maintain a heap... |
| 1255 | # Rewrite this in Cython as soon as possible ! |
| 1256 | # ************************************************* |
| 1257 | from heapq import heappush, heappop |
| 1258 | |
| 1259 | |
| 1260 | # As for shortest_path, the roles of x and y are symmetric, hence we define |
| 1261 | # dictionaries like pred_current and pred_other, which represent alternatively |
| 1262 | # pred_x or pred_y according to the side studied |
| 1263 | cdef int x_int = get_vertex(x, self.vertex_ints, self.vertex_labels, self._cg) |
| 1264 | cdef int y_int = get_vertex(y, self.vertex_ints, self.vertex_labels, self._cg) |
| 1265 | cdef int u = 0 |
| 1266 | cdef int v = 0 |
| 1267 | cdef int w = 0 |
| 1268 | cdef int pred |
| 1269 | cdef float distance |
| 1270 | cdef float edge_label |
| 1271 | cdef int side |
| 1272 | cdef float f_tmp |
| 1273 | |
| 1274 | # Each vertex knows its predecessors in the search, for each side |
| 1275 | cdef dict pred_x = {} |
| 1276 | cdef dict pred_y = {} |
| 1277 | cdef dict pred_current |
| 1278 | cdef dict pred_other |
| 1279 | |
| 1280 | # Stores the distances from x and y |
| 1281 | cdef dict dist_x = {} |
| 1282 | cdef dict dist_y = {} |
| 1283 | cdef dict dist_current |
| 1284 | cdef dict dist_other |
| 1285 | |
| 1286 | # Lists of vertices who are left to be explored |
| 1287 | # they are represented as 4-uples : (distance, side, predecessor ,name) |
| 1288 | # 1 indicates x's side, -1 indicates y's, the distance being |
| 1289 | # defined relatively |
| 1290 | cdef list queue = [(0,1,x_int,x_int),(0,-1,y_int,y_int)] |
| 1291 | |
| 1292 | cdef list shortest_path = [] |
| 1293 | |
| 1294 | # meeting_vertex is a vertex discovered through x and through y |
| 1295 | # which defines ther shortest path found |
| 1296 | # ( of length shortest_path_length ) |
| 1297 | cdef int meeting_vertex = -1 |
| 1298 | cdef float shortest_path_length |
| 1299 | |
| 1300 | # As long as the current side (x or y) is not totally explored ... |
| 1301 | while queue: |
| 1302 | |
| 1303 | (distance, side, pred, v) = heappop(queue) |
| 1304 | if meeting_vertex != -1 and distance > shortest_path_length: |
| 1305 | break |
| 1306 | |
| 1307 | if side == 1: |
| 1308 | dist_current, dist_other = dist_x, dist_y |
| 1309 | pred_current, pred_other = pred_x, pred_y |
| 1310 | else: |
| 1311 | dist_current, dist_other = dist_y, dist_x |
| 1312 | pred_current, pred_other = pred_y, pred_x |
| 1313 | |
| 1314 | if not dist_current.has_key(v): |
| 1315 | pred_current[v] = pred |
| 1316 | dist_current[v] = distance |
| 1317 | |
| 1318 | if dist_other.has_key(v): |
| 1319 | f_tmp = distance + dist_other[v] |
| 1320 | if meeting_vertex == -1 or f_tmp<shortest_path_length: |
| 1321 | meeting_vertex = v |
| 1322 | shortest_path_length = f_tmp |
| 1323 | |
| 1324 | for w in (self._cg.out_neighbors(v) if side == 1 else self._cg.in_neighbors(v)): |
| 1325 | # If the neihgbor is new, adds its non-found neighbors to the queue |
| 1326 | if not dist_current.has_key(w): |
| 1327 | edge_label = self.get_edge_label(v,w) if side == 1 else self.get_edge_label(w,v) |
| 1328 | heappush(queue,(distance + edge_label,side,v,w)) |
| 1329 | |
| 1330 | |
| 1331 | # No meeting point has been found |
| 1332 | if meeting_vertex == -1: |
| 1333 | return [] |
| 1334 | else: |
| 1335 | # build the shortest path and returns it. |
| 1336 | w = meeting_vertex |
| 1337 | |
| 1338 | while w != x_int: |
| 1339 | shortest_path.append(vertex_label(w, self.vertex_ints, self.vertex_labels, self._cg)) |
| 1340 | w = pred_x[w] |
| 1341 | |
| 1342 | shortest_path.append(x) |
| 1343 | shortest_path.reverse() |
| 1344 | |
| 1345 | if meeting_vertex == y_int: |
| 1346 | return shortest_path |
| 1347 | |
| 1348 | w=pred_y[meeting_vertex] |
| 1349 | while w != y_int: |
| 1350 | shortest_path.append(vertex_label(w, self.vertex_ints, self.vertex_labels, self._cg)) |
| 1351 | w = pred_y[w] |
| 1352 | shortest_path.append(y) |
| 1353 | |
| 1354 | return shortest_path |
| 1355 | |
| 1356 | |
| 1357 | |
| 1358 | |
| 1359 | |