|
17 | 17 | 'minimum_spanning_tree',
|
18 | 18 | 'minimum_spanning_tree_parallel',
|
19 | 19 | 'strongly_connected_components',
|
20 |
| - 'depth_first_search' |
| 20 | + 'depth_first_search', |
| 21 | + 'shortest_paths' |
21 | 22 | ]
|
22 | 23 |
|
23 | 24 | Stack = Queue = deque
|
@@ -637,3 +638,90 @@ def _depth_first_search_adjacency_list(
|
637 | 638 | return None
|
638 | 639 |
|
639 | 640 | _depth_first_search_adjacency_matrix = _depth_first_search_adjacency_list
|
| 641 | + |
| 642 | +def shortest_paths(graph: Graph, algorithm: str, |
| 643 | + source: str, target: str="") -> tuple: |
| 644 | + """ |
| 645 | + Finds shortest paths in the given graph from a given source. |
| 646 | +
|
| 647 | + Parameters |
| 648 | + ========== |
| 649 | +
|
| 650 | + graph: Graph |
| 651 | + The graph under consideration. |
| 652 | + algorithm: str |
| 653 | + The algorithm to be used. Currently, the following algorithms |
| 654 | + are implemented, |
| 655 | + 'bellman_ford' -> Bellman-Ford algorithm as given in [1]. |
| 656 | + source: str |
| 657 | + The name of the source the node. |
| 658 | + target: str |
| 659 | + The name of the target node. |
| 660 | + Optional, by default, all pair shortest paths |
| 661 | + are returned. |
| 662 | +
|
| 663 | + Returns |
| 664 | + ======= |
| 665 | +
|
| 666 | + (distances, predecessors): (dict, dict) |
| 667 | + If target is not provided and algorithm used |
| 668 | + is 'bellman_ford'. |
| 669 | + (distances[target], predecessors): (float, dict) |
| 670 | + If target is provided and algorithm used is |
| 671 | + 'bellman_ford'. |
| 672 | +
|
| 673 | + Examples |
| 674 | + ======== |
| 675 | +
|
| 676 | + >>> from pydatastructs import Graph, AdjacencyListGraphNode |
| 677 | + >>> from pydatastructs import shortest_paths |
| 678 | + >>> V1 = AdjacencyListGraphNode("V1") |
| 679 | + >>> V2 = AdjacencyListGraphNode("V2") |
| 680 | + >>> V3 = AdjacencyListGraphNode("V3") |
| 681 | + >>> G = Graph(V1, V2, V3) |
| 682 | + >>> G.add_edge('V2', 'V3', 10) |
| 683 | + >>> G.add_edge('V1', 'V2', 11) |
| 684 | + >>> shortest_paths(G, 'bellman_ford', 'V1') |
| 685 | + ({'V1': 0, 'V2': 11, 'V3': 21}, {'V1': None, 'V2': 'V1', 'V3': 'V2'}) |
| 686 | +
|
| 687 | + References |
| 688 | + ========== |
| 689 | +
|
| 690 | + .. [1] https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm |
| 691 | + """ |
| 692 | + import pydatastructs.graphs.algorithms as algorithms |
| 693 | + func = "_" + algorithm + "_" + graph._impl |
| 694 | + if not hasattr(algorithms, func): |
| 695 | + raise NotImplementedError( |
| 696 | + "Currently %s algorithm isn't implemented for " |
| 697 | + "finding shortest paths in graphs."%(algorithm)) |
| 698 | + return getattr(algorithms, func)(graph, source, target) |
| 699 | + |
| 700 | +def _bellman_ford_adjacency_list(graph: Graph, source: str, target: str) -> tuple: |
| 701 | + distances, predecessor = dict(), dict() |
| 702 | + |
| 703 | + for v in graph.vertices: |
| 704 | + distances[v] = float('inf') |
| 705 | + predecessor[v] = None |
| 706 | + distances[source] = 0 |
| 707 | + |
| 708 | + edges = graph.edge_weights.values() |
| 709 | + for _ in range(len(graph.vertices) - 1): |
| 710 | + for edge in edges: |
| 711 | + u, v = edge.source.name, edge.target.name |
| 712 | + w = edge.value |
| 713 | + if distances[u] + edge.value < distances[v]: |
| 714 | + distances[v] = distances[u] + w |
| 715 | + predecessor[v] = u |
| 716 | + |
| 717 | + for edge in edges: |
| 718 | + u, v = edge.source.name, edge.target.name |
| 719 | + w = edge.value |
| 720 | + if distances[u] + w < distances[v]: |
| 721 | + raise ValueError("Graph contains a negative weight cycle.") |
| 722 | + |
| 723 | + if target != "": |
| 724 | + return (distances[target], predecessor) |
| 725 | + return (distances, predecessor) |
| 726 | + |
| 727 | +_bellman_ford_adjacency_matrix = _bellman_ford_adjacency_list |
0 commit comments