Path enumeration¶
This module is meant for all functions related to path enumeration in graphs.
Return the list of all paths between a pair of vertices. |
|
Return an iterator over the simple paths between a pair of vertices in increasing order of weights. |
|
Return an iterator over the simple paths between a pair of vertices in increasing order of weights. |
|
Return an iterator over the paths of |
|
Return a list of all the simple paths of |
|
Return an iterator over the simple paths between a pair of vertices. |
Functions¶
- sage.graphs.path_enumeration.all_paths(G, start, end, use_multiedges=False, report_edges=False, labels=False)[source]¶
Return the list of all paths between a pair of vertices.
If
startis the same vertex asend, then[[start]]is returned – a list containing the 1-vertex, 0-edge path “start”.If
Ghas multiple edges, a path will be returned as many times as the product of the multiplicity of the edges along that path depending on the value of the flaguse_multiedges.INPUT:
start– a vertex of a graph, where to startend– a vertex of a graph, where to enduse_multiedges– boolean (default:False); this parameter is used only if the graph has multiple edgesIf
False, the graph is considered as simple and an edge label is arbitrarily selected for each edge as insage.graphs.generic_graph.GenericGraph.to_simple()ifreport_edgesisTrueIf
True, a path will be reported as many times as the edges multiplicities along that path (whenreport_edges = Falseorlabels = False), or with all possible combinations of edge labels (whenreport_edges = Trueandlabels = True)
report_edges– boolean (default:False); whether to report paths as list of vertices (default) or list of edges, ifFalsethenlabelsparameter is ignoredlabels– boolean (default:False); ifFalse, each edge is simply a pair(u, v)of vertices. Otherwise a list of edges along with its edge labels are used to represent the path.
EXAMPLES:
sage: eg1 = Graph({0:[1, 2], 1:[4], 2:[3, 4], 4:[5], 5:[6]}) sage: eg1.all_paths(0, 6) [[0, 1, 4, 5, 6], [0, 2, 4, 5, 6]] sage: eg2 = graphs.PetersenGraph() sage: sorted(eg2.all_paths(1, 4)) [[1, 0, 4], [1, 0, 5, 7, 2, 3, 4], [1, 0, 5, 7, 2, 3, 8, 6, 9, 4], [1, 0, 5, 7, 9, 4], [1, 0, 5, 7, 9, 6, 8, 3, 4], [1, 0, 5, 8, 3, 2, 7, 9, 4], [1, 0, 5, 8, 3, 4], [1, 0, 5, 8, 6, 9, 4], [1, 0, 5, 8, 6, 9, 7, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 8, 5, 0, 4], [1, 2, 3, 8, 5, 7, 9, 4], [1, 2, 3, 8, 6, 9, 4], [1, 2, 3, 8, 6, 9, 7, 5, 0, 4], [1, 2, 7, 5, 0, 4], [1, 2, 7, 5, 8, 3, 4], [1, 2, 7, 5, 8, 6, 9, 4], [1, 2, 7, 9, 4], [1, 2, 7, 9, 6, 8, 3, 4], [1, 2, 7, 9, 6, 8, 5, 0, 4], [1, 6, 8, 3, 2, 7, 5, 0, 4], [1, 6, 8, 3, 2, 7, 9, 4], [1, 6, 8, 3, 4], [1, 6, 8, 5, 0, 4], [1, 6, 8, 5, 7, 2, 3, 4], [1, 6, 8, 5, 7, 9, 4], [1, 6, 9, 4], [1, 6, 9, 7, 2, 3, 4], [1, 6, 9, 7, 2, 3, 8, 5, 0, 4], [1, 6, 9, 7, 5, 0, 4], [1, 6, 9, 7, 5, 8, 3, 4]] sage: dg = DiGraph({0:[1, 3], 1:[3], 2:[0, 3]}) sage: sorted(dg.all_paths(0, 3)) [[0, 1, 3], [0, 3]] sage: ug = dg.to_undirected() sage: sorted(ug.all_paths(0, 3)) [[0, 1, 3], [0, 2, 3], [0, 3]] sage: g = Graph([(0, 1), (0, 1), (1, 2), (1, 2)], multiedges=True) sage: g.all_paths(0, 2, use_multiedges=True) [[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]] sage: dg = DiGraph({0:[1, 2, 1], 3:[0, 0]}, multiedges=True) sage: dg.all_paths(3, 1, use_multiedges=True) [[3, 0, 1], [3, 0, 1], [3, 0, 1], [3, 0, 1]] sage: g = Graph([(0, 1, 'a'), (0, 1, 'b'), (1, 2, 'c'), (1, 2, 'd')], multiedges=True) sage: g.all_paths(0, 2, use_multiedges=False) [[0, 1, 2]] sage: g.all_paths(0, 2, use_multiedges=True) [[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]] sage: g.all_paths(0, 2, use_multiedges=True, report_edges=True) [[(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)]] sage: g.all_paths(0, 2, use_multiedges=True, report_edges=True, labels=True) [((0, 1, 'b'), (1, 2, 'd')), ((0, 1, 'b'), (1, 2, 'c')), ((0, 1, 'a'), (1, 2, 'd')), ((0, 1, 'a'), (1, 2, 'c'))] sage: g.all_paths(0, 2, use_multiedges=False, report_edges=True, labels=True) [((0, 1, 'b'), (1, 2, 'd'))] sage: g.all_paths(0, 2, use_multiedges=False, report_edges=False, labels=True) [[0, 1, 2]] sage: g.all_paths(0, 2, use_multiedges=True, report_edges=False, labels=True) [[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]
>>> from sage.all import * >>> eg1 = Graph({Integer(0):[Integer(1), Integer(2)], Integer(1):[Integer(4)], Integer(2):[Integer(3), Integer(4)], Integer(4):[Integer(5)], Integer(5):[Integer(6)]}) >>> eg1.all_paths(Integer(0), Integer(6)) [[0, 1, 4, 5, 6], [0, 2, 4, 5, 6]] >>> eg2 = graphs.PetersenGraph() >>> sorted(eg2.all_paths(Integer(1), Integer(4))) [[1, 0, 4], [1, 0, 5, 7, 2, 3, 4], [1, 0, 5, 7, 2, 3, 8, 6, 9, 4], [1, 0, 5, 7, 9, 4], [1, 0, 5, 7, 9, 6, 8, 3, 4], [1, 0, 5, 8, 3, 2, 7, 9, 4], [1, 0, 5, 8, 3, 4], [1, 0, 5, 8, 6, 9, 4], [1, 0, 5, 8, 6, 9, 7, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 8, 5, 0, 4], [1, 2, 3, 8, 5, 7, 9, 4], [1, 2, 3, 8, 6, 9, 4], [1, 2, 3, 8, 6, 9, 7, 5, 0, 4], [1, 2, 7, 5, 0, 4], [1, 2, 7, 5, 8, 3, 4], [1, 2, 7, 5, 8, 6, 9, 4], [1, 2, 7, 9, 4], [1, 2, 7, 9, 6, 8, 3, 4], [1, 2, 7, 9, 6, 8, 5, 0, 4], [1, 6, 8, 3, 2, 7, 5, 0, 4], [1, 6, 8, 3, 2, 7, 9, 4], [1, 6, 8, 3, 4], [1, 6, 8, 5, 0, 4], [1, 6, 8, 5, 7, 2, 3, 4], [1, 6, 8, 5, 7, 9, 4], [1, 6, 9, 4], [1, 6, 9, 7, 2, 3, 4], [1, 6, 9, 7, 2, 3, 8, 5, 0, 4], [1, 6, 9, 7, 5, 0, 4], [1, 6, 9, 7, 5, 8, 3, 4]] >>> dg = DiGraph({Integer(0):[Integer(1), Integer(3)], Integer(1):[Integer(3)], Integer(2):[Integer(0), Integer(3)]}) >>> sorted(dg.all_paths(Integer(0), Integer(3))) [[0, 1, 3], [0, 3]] >>> ug = dg.to_undirected() >>> sorted(ug.all_paths(Integer(0), Integer(3))) [[0, 1, 3], [0, 2, 3], [0, 3]] >>> g = Graph([(Integer(0), Integer(1)), (Integer(0), Integer(1)), (Integer(1), Integer(2)), (Integer(1), Integer(2))], multiedges=True) >>> g.all_paths(Integer(0), Integer(2), use_multiedges=True) [[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]] >>> dg = DiGraph({Integer(0):[Integer(1), Integer(2), Integer(1)], Integer(3):[Integer(0), Integer(0)]}, multiedges=True) >>> dg.all_paths(Integer(3), Integer(1), use_multiedges=True) [[3, 0, 1], [3, 0, 1], [3, 0, 1], [3, 0, 1]] >>> g = Graph([(Integer(0), Integer(1), 'a'), (Integer(0), Integer(1), 'b'), (Integer(1), Integer(2), 'c'), (Integer(1), Integer(2), 'd')], multiedges=True) >>> g.all_paths(Integer(0), Integer(2), use_multiedges=False) [[0, 1, 2]] >>> g.all_paths(Integer(0), Integer(2), use_multiedges=True) [[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]] >>> g.all_paths(Integer(0), Integer(2), use_multiedges=True, report_edges=True) [[(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)]] >>> g.all_paths(Integer(0), Integer(2), use_multiedges=True, report_edges=True, labels=True) [((0, 1, 'b'), (1, 2, 'd')), ((0, 1, 'b'), (1, 2, 'c')), ((0, 1, 'a'), (1, 2, 'd')), ((0, 1, 'a'), (1, 2, 'c'))] >>> g.all_paths(Integer(0), Integer(2), use_multiedges=False, report_edges=True, labels=True) [((0, 1, 'b'), (1, 2, 'd'))] >>> g.all_paths(Integer(0), Integer(2), use_multiedges=False, report_edges=False, labels=True) [[0, 1, 2]] >>> g.all_paths(Integer(0), Integer(2), use_multiedges=True, report_edges=False, labels=True) [[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]]
- sage.graphs.path_enumeration.all_paths_iterator(self, starting_vertices=None, ending_vertices=None, simple=False, max_length=None, trivial=False, use_multiedges=False, report_edges=False, labels=False)[source]¶
Return an iterator over the paths of
self.The paths are enumerated in increasing length order.
INPUT:
starting_vertices– iterable (default:None); vertices from which the paths must start. IfNone, then all vertices of the graph can be starting points.ending_vertices– iterable (default:None); allowed ending vertices of the paths. IfNone, then all vertices are allowed.simple– boolean (default:False); if set toTrue, then only simple paths are considered. Simple paths are paths in which no two arcs share a head or share a tail, i.e. every vertex in the path is entered at most once and exited at most once.max_length– nonnegative integer (default:None); the maximum length of the enumerated paths. If set toNone, then all lengths are allowed.trivial– boolean (default:False); if set toTrue, then the empty paths are also enumerateduse_multiedges– boolean (default:False); this parameter is used only if the graph has multiple edgesIf
False, the graph is considered as simple and an edge label is arbitrarily selected for each edge as insage.graphs.generic_graph.GenericGraph.to_simple()ifreport_edgesisTrueIf
True, a path will be reported as many times as the edges multiplicities along that path (whenreport_edges = Falseorlabels = False), or with all possible combinations of edge labels (whenreport_edges = Trueandlabels = True)
report_edges– boolean (default:False); whether to report paths as list of vertices (default) or list of edges, ifFalsethenlabelsparameter is ignoredlabels– boolean (default:False); ifFalse, each edge is simply a pair(u, v)of vertices. Otherwise a list of edges along with its edge labels are used to represent the path.
OUTPUT: iterator
AUTHOR:
Alexandre Blondin Masse
EXAMPLES:
sage: G = graphs.CompleteGraph(4) sage: list(G.all_paths_iterator(starting_vertices=[1], ending_vertices=[3], simple=True)) [[1, 3], [1, 0, 3], [1, 2, 3], [1, 0, 2, 3], [1, 2, 0, 3]] sage: list(G.shortest_simple_paths(1, 3)) [[1, 3], [1, 0, 3], [1, 2, 3], [1, 2, 0, 3], [1, 0, 2, 3]] sage: pi = G.all_paths_iterator(starting_vertices=[1], ending_vertices=[3]) sage: for _ in range(6): ....: print(next(pi)) [1, 3] [1, 0, 3] [1, 2, 3] [1, 0, 1, 3] [1, 0, 2, 3] [1, 2, 0, 3] sage: g = DiGraph({'a': ['a', 'b'], 'b': ['c'], 'c': ['d'], 'd': ['c']}, loops=True) sage: pi = g.all_paths_iterator(starting_vertices=['a'], ending_vertices=['d'], report_edges=True, simple=True) sage: list(pi) [[('a', 'b'), ('b', 'c'), ('c', 'd')]] sage: g = DiGraph([(0, 1, 'a'), (0, 1, 'b'), (1, 2,'c'), (1, 2,'d')], multiedges=True) sage: pi = g.all_paths_iterator(starting_vertices=[0], use_multiedges=True) sage: for _ in range(6): ....: print(next(pi)) [0, 1] [0, 1] [0, 1, 2] [0, 1, 2] [0, 1, 2] [0, 1, 2] sage: pi = g.all_paths_iterator(starting_vertices=[0], use_multiedges=True, report_edges=True, labels=True) sage: for _ in range(6): ....: print(next(pi)) [(0, 1, 'b')] [(0, 1, 'a')] [(0, 1, 'b'), (1, 2, 'd')] [(0, 1, 'b'), (1, 2, 'c')] [(0, 1, 'a'), (1, 2, 'd')] [(0, 1, 'a'), (1, 2, 'c')] sage: list(g.all_paths_iterator(starting_vertices=[0, 1], ending_vertices=[2], use_multiedges=False, report_edges=True, labels=True, simple=True)) [[(1, 2, 'd')], [(0, 1, 'b'), (1, 2, 'd')]] sage: list(g.all_paths_iterator(starting_vertices=[0, 1], ending_vertices=[2], use_multiedges=False, report_edges=False, labels=True)) [[1, 2], [0, 1, 2]] sage: list(g.all_paths_iterator(use_multiedges=True, report_edges=False, labels=True, max_length=1)) [[1, 2], [1, 2], [0, 1], [0, 1]] sage: list(g.all_paths_iterator(use_multiedges=True, report_edges=True, labels=True, max_length=1)) [[(1, 2, 'd')], [(1, 2, 'c')], [(0, 1, 'b')], [(0, 1, 'a')]] sage: g = DiGraph({'a': ['a', 'b'], 'b': ['c'], 'c': ['d'], 'd': ['c']}, loops=True) sage: pi = g.all_paths_iterator() sage: [len(next(pi)) - 1 for _ in range(7)] [1, 1, 1, 1, 1, 2, 2]
>>> from sage.all import * >>> G = graphs.CompleteGraph(Integer(4)) >>> list(G.all_paths_iterator(starting_vertices=[Integer(1)], ending_vertices=[Integer(3)], simple=True)) [[1, 3], [1, 0, 3], [1, 2, 3], [1, 0, 2, 3], [1, 2, 0, 3]] >>> list(G.shortest_simple_paths(Integer(1), Integer(3))) [[1, 3], [1, 0, 3], [1, 2, 3], [1, 2, 0, 3], [1, 0, 2, 3]] >>> pi = G.all_paths_iterator(starting_vertices=[Integer(1)], ending_vertices=[Integer(3)]) >>> for _ in range(Integer(6)): ... print(next(pi)) [1, 3] [1, 0, 3] [1, 2, 3] [1, 0, 1, 3] [1, 0, 2, 3] [1, 2, 0, 3] >>> g = DiGraph({'a': ['a', 'b'], 'b': ['c'], 'c': ['d'], 'd': ['c']}, loops=True) >>> pi = g.all_paths_iterator(starting_vertices=['a'], ending_vertices=['d'], report_edges=True, simple=True) >>> list(pi) [[('a', 'b'), ('b', 'c'), ('c', 'd')]] >>> g = DiGraph([(Integer(0), Integer(1), 'a'), (Integer(0), Integer(1), 'b'), (Integer(1), Integer(2),'c'), (Integer(1), Integer(2),'d')], multiedges=True) >>> pi = g.all_paths_iterator(starting_vertices=[Integer(0)], use_multiedges=True) >>> for _ in range(Integer(6)): ... print(next(pi)) [0, 1] [0, 1] [0, 1, 2] [0, 1, 2] [0, 1, 2] [0, 1, 2] >>> pi = g.all_paths_iterator(starting_vertices=[Integer(0)], use_multiedges=True, report_edges=True, labels=True) >>> for _ in range(Integer(6)): ... print(next(pi)) [(0, 1, 'b')] [(0, 1, 'a')] [(0, 1, 'b'), (1, 2, 'd')] [(0, 1, 'b'), (1, 2, 'c')] [(0, 1, 'a'), (1, 2, 'd')] [(0, 1, 'a'), (1, 2, 'c')] >>> list(g.all_paths_iterator(starting_vertices=[Integer(0), Integer(1)], ending_vertices=[Integer(2)], use_multiedges=False, report_edges=True, labels=True, simple=True)) [[(1, 2, 'd')], [(0, 1, 'b'), (1, 2, 'd')]] >>> list(g.all_paths_iterator(starting_vertices=[Integer(0), Integer(1)], ending_vertices=[Integer(2)], use_multiedges=False, report_edges=False, labels=True)) [[1, 2], [0, 1, 2]] >>> list(g.all_paths_iterator(use_multiedges=True, report_edges=False, labels=True, max_length=Integer(1))) [[1, 2], [1, 2], [0, 1], [0, 1]] >>> list(g.all_paths_iterator(use_multiedges=True, report_edges=True, labels=True, max_length=Integer(1))) [[(1, 2, 'd')], [(1, 2, 'c')], [(0, 1, 'b')], [(0, 1, 'a')]] >>> g = DiGraph({'a': ['a', 'b'], 'b': ['c'], 'c': ['d'], 'd': ['c']}, loops=True) >>> pi = g.all_paths_iterator() >>> [len(next(pi)) - Integer(1) for _ in range(Integer(7))] [1, 1, 1, 1, 1, 2, 2]
It is possible to precise the allowed starting and/or ending vertices:
sage: pi = g.all_paths_iterator(starting_vertices=['a']) sage: [len(next(pi)) - 1 for _ in range(5)] [1, 1, 2, 2, 2] sage: pi = g.all_paths_iterator(starting_vertices=['a'], ending_vertices=['b']) sage: for _ in range(5): ....: print(next(pi)) ['a', 'b'] ['a', 'a', 'b'] ['a', 'a', 'a', 'b'] ['a', 'a', 'a', 'a', 'b'] ['a', 'a', 'a', 'a', 'a', 'b']
>>> from sage.all import * >>> pi = g.all_paths_iterator(starting_vertices=['a']) >>> [len(next(pi)) - Integer(1) for _ in range(Integer(5))] [1, 1, 2, 2, 2] >>> pi = g.all_paths_iterator(starting_vertices=['a'], ending_vertices=['b']) >>> for _ in range(Integer(5)): ... print(next(pi)) ['a', 'b'] ['a', 'a', 'b'] ['a', 'a', 'a', 'b'] ['a', 'a', 'a', 'a', 'b'] ['a', 'a', 'a', 'a', 'a', 'b']
One may prefer to enumerate only simple paths (see
all_simple_paths()):sage: pi = g.all_paths_iterator(simple=True) sage: sorted(list(pi), key=lambda x:(len(x), x)) [['a', 'a'], ['a', 'b'], ['b', 'c'], ['c', 'd'], ['d', 'c'], ['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'c'], ['d', 'c', 'd'], ['a', 'b', 'c', 'd']] sage: pi = g.all_paths_iterator(simple=True) sage: [len(p) - 1 for p in pi] [1, 1, 1, 1, 1, 2, 2, 2, 2, 3]
>>> from sage.all import * >>> pi = g.all_paths_iterator(simple=True) >>> sorted(list(pi), key=lambda x:(len(x), x)) [['a', 'a'], ['a', 'b'], ['b', 'c'], ['c', 'd'], ['d', 'c'], ['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'c'], ['d', 'c', 'd'], ['a', 'b', 'c', 'd']] >>> pi = g.all_paths_iterator(simple=True) >>> [len(p) - Integer(1) for p in pi] [1, 1, 1, 1, 1, 2, 2, 2, 2, 3]
Or simply bound the length of the enumerated paths:
sage: pi = g.all_paths_iterator(starting_vertices=['a'], ending_vertices=['b', 'c'], max_length=6) sage: sorted(list(pi), key=lambda x:(len(x), x)) [['a', 'b'], ['a', 'a', 'b'], ['a', 'b', 'c'], ['a', 'a', 'a', 'b'], ['a', 'a', 'b', 'c'], ['a', 'a', 'a', 'a', 'b'], ['a', 'a', 'a', 'b', 'c'], ['a', 'b', 'c', 'd', 'c'], ['a', 'a', 'a', 'a', 'a', 'b'], ['a', 'a', 'a', 'a', 'b', 'c'], ['a', 'a', 'b', 'c', 'd', 'c'], ['a', 'a', 'a', 'a', 'a', 'a', 'b'], ['a', 'a', 'a', 'a', 'a', 'b', 'c'], ['a', 'a', 'a', 'b', 'c', 'd', 'c'], ['a', 'b', 'c', 'd', 'c', 'd', 'c']] sage: pi = g.all_paths_iterator(starting_vertices=['a'], ending_vertices=['b', 'c'], max_length=6) sage: [len(p) - 1 for p in pi] [1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6]
>>> from sage.all import * >>> pi = g.all_paths_iterator(starting_vertices=['a'], ending_vertices=['b', 'c'], max_length=Integer(6)) >>> sorted(list(pi), key=lambda x:(len(x), x)) [['a', 'b'], ['a', 'a', 'b'], ['a', 'b', 'c'], ['a', 'a', 'a', 'b'], ['a', 'a', 'b', 'c'], ['a', 'a', 'a', 'a', 'b'], ['a', 'a', 'a', 'b', 'c'], ['a', 'b', 'c', 'd', 'c'], ['a', 'a', 'a', 'a', 'a', 'b'], ['a', 'a', 'a', 'a', 'b', 'c'], ['a', 'a', 'b', 'c', 'd', 'c'], ['a', 'a', 'a', 'a', 'a', 'a', 'b'], ['a', 'a', 'a', 'a', 'a', 'b', 'c'], ['a', 'a', 'a', 'b', 'c', 'd', 'c'], ['a', 'b', 'c', 'd', 'c', 'd', 'c']] >>> pi = g.all_paths_iterator(starting_vertices=['a'], ending_vertices=['b', 'c'], max_length=Integer(6)) >>> [len(p) - Integer(1) for p in pi] [1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6]
By default, empty paths are not enumerated, but it may be parametrized:
sage: pi = g.all_paths_iterator(simple=True, trivial=True) sage: sorted(list(pi), key=lambda x:(len(x), x)) [['a'], ['b'], ['c'], ['d'], ['a', 'a'], ['a', 'b'], ['b', 'c'], ['c', 'd'], ['d', 'c'], ['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'c'], ['d', 'c', 'd'], ['a', 'b', 'c', 'd']] sage: pi = g.all_paths_iterator(simple=True, trivial=True) sage: [len(p) - 1 for p in pi] [0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3] sage: pi = g.all_paths_iterator(simple=True, trivial=False) sage: sorted(list(pi), key=lambda x:(len(x), x)) [['a', 'a'], ['a', 'b'], ['b', 'c'], ['c', 'd'], ['d', 'c'], ['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'c'], ['d', 'c', 'd'], ['a', 'b', 'c', 'd']] sage: pi = g.all_paths_iterator(simple=True, trivial=False) sage: [len(p) - 1 for p in pi] [1, 1, 1, 1, 1, 2, 2, 2, 2, 3]
>>> from sage.all import * >>> pi = g.all_paths_iterator(simple=True, trivial=True) >>> sorted(list(pi), key=lambda x:(len(x), x)) [['a'], ['b'], ['c'], ['d'], ['a', 'a'], ['a', 'b'], ['b', 'c'], ['c', 'd'], ['d', 'c'], ['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'c'], ['d', 'c', 'd'], ['a', 'b', 'c', 'd']] >>> pi = g.all_paths_iterator(simple=True, trivial=True) >>> [len(p) - Integer(1) for p in pi] [0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3] >>> pi = g.all_paths_iterator(simple=True, trivial=False) >>> sorted(list(pi), key=lambda x:(len(x), x)) [['a', 'a'], ['a', 'b'], ['b', 'c'], ['c', 'd'], ['d', 'c'], ['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'c'], ['d', 'c', 'd'], ['a', 'b', 'c', 'd']] >>> pi = g.all_paths_iterator(simple=True, trivial=False) >>> [len(p) - Integer(1) for p in pi] [1, 1, 1, 1, 1, 2, 2, 2, 2, 3]
- sage.graphs.path_enumeration.all_simple_paths(self, starting_vertices=None, ending_vertices=None, max_length=None, trivial=False, use_multiedges=False, report_edges=False, labels=False)[source]¶
Return a list of all the simple paths of
selfstarting with one of the given vertices.Simple paths are paths in which no two arcs share a head or share a tail, i.e. every vertex in the path is entered at most once and exited at most once.
INPUT:
starting_vertices– list (default:None); vertices from which the paths must start. IfNone, then all vertices of the graph can be starting points.ending_vertices– iterable (default:None); allowed ending vertices of the paths. IfNone, then all vertices are allowed.max_length– nonnegative integer (default:None); the maximum length of the enumerated paths. If set toNone, then all lengths are allowed.trivial– boolean (default:False); if set toTrue, then the empty paths are also enumerateduse_multiedges– boolean (default:False); this parameter is used only if the graph has multiple edgesIf
False, the graph is considered as simple and an edge label is arbitrarily selected for each edge as insage.graphs.generic_graph.GenericGraph.to_simple()ifreport_edgesisTrueIf
True, a path will be reported as many times as the edges multiplicities along that path (whenreport_edges = Falseorlabels = False), or with all possible combinations of edge labels (whenreport_edges = Trueandlabels = True)
report_edges– boolean (default:False); whether to report paths as list of vertices (default) or list of edges, ifFalsethenlabelsparameter is ignoredlabels– boolean (default:False); ifFalse, each edge is simply a pair(u, v)of vertices. Otherwise a list of edges along with its edge labels are used to represent the path.
OUTPUT: list
Note
Although the number of simple paths of a finite graph is always finite, computing all its paths may take a very long time.
EXAMPLES:
sage: G = graphs.CompleteGraph(4) sage: G.all_simple_paths([1], [3]) [[1, 3], [1, 0, 3], [1, 2, 3], [1, 0, 2, 3], [1, 2, 0, 3]] sage: list(G.shortest_simple_paths(1, 3)) [[1, 3], [1, 0, 3], [1, 2, 3], [1, 2, 0, 3], [1, 0, 2, 3]] sage: G.all_simple_paths([0, 1], [2, 3]) [[1, 2], [1, 3], [0, 2], [0, 3], [0, 1, 2], [0, 1, 3], [0, 2, 3], [0, 3, 2], [1, 0, 2], [1, 0, 3], [1, 2, 3], [1, 3, 2], [1, 0, 2, 3], [1, 0, 3, 2], [1, 2, 0, 3], [1, 3, 0, 2], [0, 1, 2, 3], [0, 1, 3, 2], [0, 2, 1, 3], [0, 3, 1, 2]] sage: g = DiGraph({0: [0, 1], 1: [2], 2: [3], 3: [2]}, loops=True) sage: g.all_simple_paths() [[3, 2], [2, 3], [1, 2], [0, 0], [0, 1], [0, 1, 2], [1, 2, 3], [2, 3, 2], [3, 2, 3], [0, 1, 2, 3]] sage: g = DiGraph([(0, 1, 'a'), (0, 1, 'b'), (1, 2,'c'), (1, 2,'d')], multiedges=True) sage: g.all_simple_paths(starting_vertices=[0], ending_vertices=[2], use_multiedges=False) [[0, 1, 2]] sage: g.all_simple_paths(starting_vertices=[0], ending_vertices=[2], use_multiedges=True) [[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]] sage: g.all_simple_paths(starting_vertices=[0], ending_vertices=[2], use_multiedges=True, report_edges=True) [[(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)]] sage: g.all_simple_paths(starting_vertices=[0], ending_vertices=[2], use_multiedges=True, report_edges=True, labels=True) [[(0, 1, 'b'), (1, 2, 'd')], [(0, 1, 'b'), (1, 2, 'c')], [(0, 1, 'a'), (1, 2, 'd')], [(0, 1, 'a'), (1, 2, 'c')]] sage: g.all_simple_paths(starting_vertices=[0, 1], ending_vertices=[2], use_multiedges=False, report_edges=True, labels=True) [[(1, 2, 'd')], [(0, 1, 'b'), (1, 2, 'd')]] sage: g.all_simple_paths(starting_vertices=[0, 1], ending_vertices=[2], use_multiedges=False, report_edges=False, labels=True) [[1, 2], [0, 1, 2]] sage: g.all_simple_paths(use_multiedges=True, report_edges=False, labels=True) [[1, 2], [1, 2], [0, 1], [0, 1], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]] sage: g.all_simple_paths(starting_vertices=[0, 1], ending_vertices=[2], use_multiedges=False, report_edges=True, labels=True, trivial=True) [[(1, 2, 'd')], [(0, 1, 'b'), (1, 2, 'd')]]
>>> from sage.all import * >>> G = graphs.CompleteGraph(Integer(4)) >>> G.all_simple_paths([Integer(1)], [Integer(3)]) [[1, 3], [1, 0, 3], [1, 2, 3], [1, 0, 2, 3], [1, 2, 0, 3]] >>> list(G.shortest_simple_paths(Integer(1), Integer(3))) [[1, 3], [1, 0, 3], [1, 2, 3], [1, 2, 0, 3], [1, 0, 2, 3]] >>> G.all_simple_paths([Integer(0), Integer(1)], [Integer(2), Integer(3)]) [[1, 2], [1, 3], [0, 2], [0, 3], [0, 1, 2], [0, 1, 3], [0, 2, 3], [0, 3, 2], [1, 0, 2], [1, 0, 3], [1, 2, 3], [1, 3, 2], [1, 0, 2, 3], [1, 0, 3, 2], [1, 2, 0, 3], [1, 3, 0, 2], [0, 1, 2, 3], [0, 1, 3, 2], [0, 2, 1, 3], [0, 3, 1, 2]] >>> g = DiGraph({Integer(0): [Integer(0), Integer(1)], Integer(1): [Integer(2)], Integer(2): [Integer(3)], Integer(3): [Integer(2)]}, loops=True) >>> g.all_simple_paths() [[3, 2], [2, 3], [1, 2], [0, 0], [0, 1], [0, 1, 2], [1, 2, 3], [2, 3, 2], [3, 2, 3], [0, 1, 2, 3]] >>> g = DiGraph([(Integer(0), Integer(1), 'a'), (Integer(0), Integer(1), 'b'), (Integer(1), Integer(2),'c'), (Integer(1), Integer(2),'d')], multiedges=True) >>> g.all_simple_paths(starting_vertices=[Integer(0)], ending_vertices=[Integer(2)], use_multiedges=False) [[0, 1, 2]] >>> g.all_simple_paths(starting_vertices=[Integer(0)], ending_vertices=[Integer(2)], use_multiedges=True) [[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]] >>> g.all_simple_paths(starting_vertices=[Integer(0)], ending_vertices=[Integer(2)], use_multiedges=True, report_edges=True) [[(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)], [(0, 1), (1, 2)]] >>> g.all_simple_paths(starting_vertices=[Integer(0)], ending_vertices=[Integer(2)], use_multiedges=True, report_edges=True, labels=True) [[(0, 1, 'b'), (1, 2, 'd')], [(0, 1, 'b'), (1, 2, 'c')], [(0, 1, 'a'), (1, 2, 'd')], [(0, 1, 'a'), (1, 2, 'c')]] >>> g.all_simple_paths(starting_vertices=[Integer(0), Integer(1)], ending_vertices=[Integer(2)], use_multiedges=False, report_edges=True, labels=True) [[(1, 2, 'd')], [(0, 1, 'b'), (1, 2, 'd')]] >>> g.all_simple_paths(starting_vertices=[Integer(0), Integer(1)], ending_vertices=[Integer(2)], use_multiedges=False, report_edges=False, labels=True) [[1, 2], [0, 1, 2]] >>> g.all_simple_paths(use_multiedges=True, report_edges=False, labels=True) [[1, 2], [1, 2], [0, 1], [0, 1], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]] >>> g.all_simple_paths(starting_vertices=[Integer(0), Integer(1)], ending_vertices=[Integer(2)], use_multiedges=False, report_edges=True, labels=True, trivial=True) [[(1, 2, 'd')], [(0, 1, 'b'), (1, 2, 'd')]]
One may compute all paths having specific starting and/or ending vertices:
sage: g = DiGraph({'a': ['a', 'b'], 'b': ['c'], 'c': ['d'], 'd': ['c']}, loops=True) sage: g.all_simple_paths(starting_vertices=['a']) [['a', 'a'], ['a', 'b'], ['a', 'b', 'c'], ['a', 'b', 'c', 'd']] sage: g.all_simple_paths(starting_vertices=['a'], ending_vertices=['c']) [['a', 'b', 'c']] sage: g.all_simple_paths(starting_vertices=['a'], ending_vertices=['b', 'c']) [['a', 'b'], ['a', 'b', 'c']]
>>> from sage.all import * >>> g = DiGraph({'a': ['a', 'b'], 'b': ['c'], 'c': ['d'], 'd': ['c']}, loops=True) >>> g.all_simple_paths(starting_vertices=['a']) [['a', 'a'], ['a', 'b'], ['a', 'b', 'c'], ['a', 'b', 'c', 'd']] >>> g.all_simple_paths(starting_vertices=['a'], ending_vertices=['c']) [['a', 'b', 'c']] >>> g.all_simple_paths(starting_vertices=['a'], ending_vertices=['b', 'c']) [['a', 'b'], ['a', 'b', 'c']]
It is also possible to bound the length of the paths:
sage: g = DiGraph({0: [0, 1], 1: [2], 2: [3], 3: [2]}, loops=True) sage: g.all_simple_paths(max_length=2) [[3, 2], [2, 3], [1, 2], [0, 0], [0, 1], [0, 1, 2], [1, 2, 3], [2, 3, 2], [3, 2, 3]]
>>> from sage.all import * >>> g = DiGraph({Integer(0): [Integer(0), Integer(1)], Integer(1): [Integer(2)], Integer(2): [Integer(3)], Integer(3): [Integer(2)]}, loops=True) >>> g.all_simple_paths(max_length=Integer(2)) [[3, 2], [2, 3], [1, 2], [0, 0], [0, 1], [0, 1, 2], [1, 2, 3], [2, 3, 2], [3, 2, 3]]
By default, empty paths are not enumerated, but this can be parametrized:
sage: g = DiGraph({'a': ['a', 'b'], 'b': ['c'], 'c': ['d'], 'd': ['c']}, loops=True) sage: g.all_simple_paths(starting_vertices=['a'], trivial=True) [['a'], ['a', 'a'], ['a', 'b'], ['a', 'b', 'c'], ['a', 'b', 'c', 'd']] sage: g.all_simple_paths(starting_vertices=['a'], trivial=False) [['a', 'a'], ['a', 'b'], ['a', 'b', 'c'], ['a', 'b', 'c', 'd']]
>>> from sage.all import * >>> g = DiGraph({'a': ['a', 'b'], 'b': ['c'], 'c': ['d'], 'd': ['c']}, loops=True) >>> g.all_simple_paths(starting_vertices=['a'], trivial=True) [['a'], ['a', 'a'], ['a', 'b'], ['a', 'b', 'c'], ['a', 'b', 'c', 'd']] >>> g.all_simple_paths(starting_vertices=['a'], trivial=False) [['a', 'a'], ['a', 'b'], ['a', 'b', 'c'], ['a', 'b', 'c', 'd']]
- sage.graphs.path_enumeration.feng_k_shortest_simple_paths(self, source, target, weight_function=None, by_weight=False, check_weight=True, report_edges=False, labels=False, report_weight=False)[source]¶
Return an iterator over the simple paths between a pair of vertices in increasing order of weights.
Works only for directed graphs.
For unweighted graphs, paths are returned in order of increasing number of edges.
In case of weighted graphs, negative weights are not allowed.
If
sourceis the same vertex astarget, then[[source]]is returned – a list containing the 1-vertex, 0-edge pathsource.The loops and the multiedges if present in the given graph are ignored and only minimum of the edge labels is kept in case of multiedges.
INPUT:
source– a vertex of the graph, where to starttarget– a vertex of the graph, where to endweight_function– function (default:None); a function that takes as input an edge(u, v, l)and outputs its weight. If notNone,by_weightis automatically set toTrue. IfNoneandby_weightisTrue, we use the edge labellas a weight.by_weight– boolean (default:False); ifTrue, the edges in the graph are weighted, otherwise all edges have weight 1check_weight– boolean (default:True); whether to check that theweight_functionoutputs a number for each edgereport_edges– boolean (default:False); whether to report paths as list of vertices (default) or list of edges, ifFalsethenlabelsparameter is ignoredlabels– boolean (default:False); ifFalse, each edge is simply a pair(u, v)of vertices. Otherwise a list of edges along with its edge labels are used to represent the path.report_weight– boolean (default:False); ifFalse, just the path betweensourceandtargetis returned. Otherwise a tuple of path length and path is returned.
ALGORITHM:
This algorithm can be divided into two parts. Firstly, it determines the shortest path from
sourcetotarget. Then, it determines all the other \(k\)-shortest paths. This algorithm finds the deviations of previous shortest paths to determine the next shortest paths. This algorithm finds the candidate paths more efficiently using a node classification technique. At first the candidate path is separated by its deviation node as prefix and suffix. Then the algorithm classify the nodes as red, yellow and green. A node on the prefix is assigned a red color, a node that can reach t (the destination node) through a shortest path without visiting a red node is assigned a green color, and all other nodes are assigned a yellow color. When searching for the suffix of a candidate path, all green nodes are bypassed, andDijkstra’s algorithmis applied to find an all-yellow-node subpath. Since on average the number of yellow nodes is much smaller than n, this algorithm has a much lower average-case running time.Time complexity is \(O(kn(m+n\log{n}))\) where \(n\) is the number of vertices and \(m\) is the number of edges and \(k\) is the number of shortest paths needed to find. Its average running time is much smaller as compared to \(Yen's\) algorithm.
See [Feng2014] for more details on this algorithm.
EXAMPLES:
sage: from sage.graphs.path_enumeration import feng_k_shortest_simple_paths sage: g = DiGraph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20), (3, 5, 10), (4, 5, 30)]) sage: list(feng_k_shortest_simple_paths(g, 1, 5, by_weight=True)) [[1, 3, 5], [1, 2, 5], [1, 4, 5]] sage: list(feng_k_shortest_simple_paths(g, 1, 5)) [[1, 2, 5], [1, 3, 5], [1, 4, 5]] sage: list(feng_k_shortest_simple_paths(g, 1, 1)) [[1]] sage: list(feng_k_shortest_simple_paths(g, 1, 5, report_edges=True, labels=True)) [[(1, 2, 20), (2, 5, 20)], [(1, 3, 10), (3, 5, 10)], [(1, 4, 30), (4, 5, 30)]] sage: list(feng_k_shortest_simple_paths(g, 1, 5, report_edges=True, labels=True, by_weight=True)) [[(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)], [(1, 4, 30), (4, 5, 30)]] sage: list(feng_k_shortest_simple_paths(g, 1, 5, report_edges=True, labels=True, by_weight=True, report_weight=True)) [(20, [(1, 3, 10), (3, 5, 10)]), (40, [(1, 2, 20), (2, 5, 20)]), (60, [(1, 4, 30), (4, 5, 30)])] sage: from sage.graphs.path_enumeration import feng_k_shortest_simple_paths sage: g = DiGraph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20), (3, 5, 10), (4, 5, 30), (1, 6, 100), (5, 6, 5)]) sage: list(feng_k_shortest_simple_paths(g, 1, 6, by_weight = True)) [[1, 3, 5, 6], [1, 2, 5, 6], [1, 4, 5, 6], [1, 6]] sage: list(feng_k_shortest_simple_paths(g, 1, 6)) [[1, 6], [1, 2, 5, 6], [1, 3, 5, 6], [1, 4, 5, 6]] sage: list(feng_k_shortest_simple_paths(g, 1, 6, report_edges=True, labels=True, by_weight=True, report_weight=True)) [(25, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]), (45, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]), (65, [(1, 4, 30), (4, 5, 30), (5, 6, 5)]), (100, [(1, 6, 100)])] sage: list(feng_k_shortest_simple_paths(g, 1, 6, report_edges=True, labels=True, report_weight=True)) [(1, [(1, 6, 100)]), (3, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]), (3, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]), (3, [(1, 4, 30), (4, 5, 30), (5, 6, 5)])] sage: from sage.graphs.path_enumeration import feng_k_shortest_simple_paths sage: g = DiGraph([(1, 2, 5), (2, 3, 0), (1, 4, 2), (4, 5, 1), (5, 3, 0)]) sage: list(feng_k_shortest_simple_paths(g, 1, 3, by_weight=True)) [[1, 4, 5, 3], [1, 2, 3]] sage: list(feng_k_shortest_simple_paths(g, 1, 3)) [[1, 2, 3], [1, 4, 5, 3]] sage: list(feng_k_shortest_simple_paths(g, 1, 3, report_weight=True)) [(2, [1, 2, 3]), (3, [1, 4, 5, 3])] sage: list(feng_k_shortest_simple_paths(g, 1, 3, report_weight=True, report_edges=True)) [(2, [(1, 2), (2, 3)]), (3, [(1, 4), (4, 5), (5, 3)])] sage: list(feng_k_shortest_simple_paths(g, 1, 3, report_weight=True, report_edges=True, by_weight=True)) [(3, [(1, 4), (4, 5), (5, 3)]), (5, [(1, 2), (2, 3)])] sage: list(feng_k_shortest_simple_paths(g, 1, 3, report_weight=True, report_edges=True, by_weight=True, labels=True)) [(3, [(1, 4, 2), (4, 5, 1), (5, 3, 0)]), (5, [(1, 2, 5), (2, 3, 0)])]
>>> from sage.all import * >>> from sage.graphs.path_enumeration import feng_k_shortest_simple_paths >>> g = DiGraph([(Integer(1), Integer(2), Integer(20)), (Integer(1), Integer(3), Integer(10)), (Integer(1), Integer(4), Integer(30)), (Integer(2), Integer(5), Integer(20)), (Integer(3), Integer(5), Integer(10)), (Integer(4), Integer(5), Integer(30))]) >>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(5), by_weight=True)) [[1, 3, 5], [1, 2, 5], [1, 4, 5]] >>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(5))) [[1, 2, 5], [1, 3, 5], [1, 4, 5]] >>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(1))) [[1]] >>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(5), report_edges=True, labels=True)) [[(1, 2, 20), (2, 5, 20)], [(1, 3, 10), (3, 5, 10)], [(1, 4, 30), (4, 5, 30)]] >>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(5), report_edges=True, labels=True, by_weight=True)) [[(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)], [(1, 4, 30), (4, 5, 30)]] >>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(5), report_edges=True, labels=True, by_weight=True, report_weight=True)) [(20, [(1, 3, 10), (3, 5, 10)]), (40, [(1, 2, 20), (2, 5, 20)]), (60, [(1, 4, 30), (4, 5, 30)])] >>> from sage.graphs.path_enumeration import feng_k_shortest_simple_paths >>> g = DiGraph([(Integer(1), Integer(2), Integer(20)), (Integer(1), Integer(3), Integer(10)), (Integer(1), Integer(4), Integer(30)), (Integer(2), Integer(5), Integer(20)), (Integer(3), Integer(5), Integer(10)), (Integer(4), Integer(5), Integer(30)), (Integer(1), Integer(6), Integer(100)), (Integer(5), Integer(6), Integer(5))]) >>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(6), by_weight = True)) [[1, 3, 5, 6], [1, 2, 5, 6], [1, 4, 5, 6], [1, 6]] >>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(6))) [[1, 6], [1, 2, 5, 6], [1, 3, 5, 6], [1, 4, 5, 6]] >>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(6), report_edges=True, labels=True, by_weight=True, report_weight=True)) [(25, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]), (45, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]), (65, [(1, 4, 30), (4, 5, 30), (5, 6, 5)]), (100, [(1, 6, 100)])] >>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(6), report_edges=True, labels=True, report_weight=True)) [(1, [(1, 6, 100)]), (3, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]), (3, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]), (3, [(1, 4, 30), (4, 5, 30), (5, 6, 5)])] >>> from sage.graphs.path_enumeration import feng_k_shortest_simple_paths >>> g = DiGraph([(Integer(1), Integer(2), Integer(5)), (Integer(2), Integer(3), Integer(0)), (Integer(1), Integer(4), Integer(2)), (Integer(4), Integer(5), Integer(1)), (Integer(5), Integer(3), Integer(0))]) >>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(3), by_weight=True)) [[1, 4, 5, 3], [1, 2, 3]] >>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(3))) [[1, 2, 3], [1, 4, 5, 3]] >>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(3), report_weight=True)) [(2, [1, 2, 3]), (3, [1, 4, 5, 3])] >>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(3), report_weight=True, report_edges=True)) [(2, [(1, 2), (2, 3)]), (3, [(1, 4), (4, 5), (5, 3)])] >>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(3), report_weight=True, report_edges=True, by_weight=True)) [(3, [(1, 4), (4, 5), (5, 3)]), (5, [(1, 2), (2, 3)])] >>> list(feng_k_shortest_simple_paths(g, Integer(1), Integer(3), report_weight=True, report_edges=True, by_weight=True, labels=True)) [(3, [(1, 4, 2), (4, 5, 1), (5, 3, 0)]), (5, [(1, 2, 5), (2, 3, 0)])]
- sage.graphs.path_enumeration.shortest_simple_paths(self, source, target, weight_function=None, by_weight=False, check_weight=True, algorithm=None, report_edges=False, labels=False, report_weight=False)[source]¶
Return an iterator over the simple paths between a pair of vertices.
This method returns an iterator over the simple paths (i.e., without repetition) from
sourcetotarget. By default (by_weightisFalse), the paths are reported by increasing number of edges. Whenby_weightisTrue, the paths are reported by increasing weights.In case of weighted graphs negative weights are not allowed.
If
sourceis the same vertex astarget, then[[source]]is returned – a list containing the 1-vertex, 0-edge pathsource.By default
Yen'salgorithm [Yen1970] is used for undirected graphs andFeng'salgorithm is used for directed graphs [Feng2014].The loops and the multiedges if present in the given graph are ignored and only minimum of the edge labels is kept in case of multiedges.
INPUT:
source– a vertex of the graph, where to starttarget– a vertex of the graph, where to endweight_function– function (default:None); a function that takes as input an edge(u, v, l)and outputs its weight. If notNone,by_weightis automatically set toTrue. IfNoneandby_weightisTrue, we use the edge labellas a weight.by_weight– boolean (default:False); ifTrue, the edges in the graph are weighted, otherwise all edges have weight 1check_weight– boolean (default:True); whether to check that theweight_functionoutputs a number for each edgealgorithm– string (default:None); the algorithm to use in computingkshortest paths ofself. The following algorithms are supported:'Yen'– Yen’s algorithm [Yen1970]'Feng'– an improved version of Yen’s algorithm but that works only for directed graphs [Feng2014]
report_edges– boolean (default:False); whether to report paths as list of vertices (default) or list of edges. When set toFalse, thelabelsparameter is ignored.labels– boolean (default:False); ifFalse, each edge is simply a pair(u, v)of vertices. Otherwise a list of edges along with its edge labels are used to represent the path.report_weight– boolean (default:False); ifFalse, just the path betweensourceandtargetis returned. Otherwise a tuple of path length and path is returned.
EXAMPLES:
sage: g = DiGraph([(1, 2, 20), (1, 3, 10), (1, 4, 30), ....: (2, 5, 20), (3, 5, 10), (4, 5, 30)]) sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm='Yen')) [[1, 3, 5], [1, 2, 5], [1, 4, 5]] sage: list(g.shortest_simple_paths(1, 5, algorithm='Yen')) [[1, 2, 5], [1, 3, 5], [1, 4, 5]] sage: list(g.shortest_simple_paths(1, 1)) [[1]] sage: list(g.shortest_simple_paths(1, 5, by_weight=True, ....: report_edges=True, report_weight=True, labels=True)) [(20, [(1, 3, 10), (3, 5, 10)]), (40, [(1, 2, 20), (2, 5, 20)]), (60, [(1, 4, 30), (4, 5, 30)])] sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm='Feng', ....: report_edges=True, report_weight=True)) [(20, [(1, 3), (3, 5)]), (40, [(1, 2), (2, 5)]), (60, [(1, 4), (4, 5)])] sage: list(g.shortest_simple_paths(1, 5, report_edges=True, report_weight=True)) [(2, [(1, 2), (2, 5)]), (2, [(1, 3), (3, 5)]), (2, [(1, 4), (4, 5)])] sage: list(g.shortest_simple_paths(1, 5, by_weight=True, report_edges=True)) [[(1, 3), (3, 5)], [(1, 2), (2, 5)], [(1, 4), (4, 5)]] sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm='Feng', ....: report_edges=True, labels=True)) [[(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)], [(1, 4, 30), (4, 5, 30)]] sage: g = Graph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20), ....: (3, 5, 10), (4, 5, 30), (1, 6, 100), (5, 6, 5)]) sage: list(g.shortest_simple_paths(1, 6, by_weight = True)) [[1, 3, 5, 6], [1, 2, 5, 6], [1, 4, 5, 6], [1, 6]] sage: list(g.shortest_simple_paths(1, 6, algorithm='Yen')) [[1, 6], [1, 2, 5, 6], [1, 3, 5, 6], [1, 4, 5, 6]] sage: list(g.shortest_simple_paths(1, 6, ....: report_edges=True, report_weight=True, labels=True)) [(1, [(1, 6, 100)]), (3, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]), (3, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]), (3, [(1, 4, 30), (4, 5, 30), (5, 6, 5)])] sage: list(g.shortest_simple_paths(1, 6, by_weight=True, ....: report_edges=True, report_weight=True, labels=True)) [(25, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]), (45, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]), (65, [(1, 4, 30), (4, 5, 30), (5, 6, 5)]), (100, [(1, 6, 100)])] sage: list(g.shortest_simple_paths(1, 6, by_weight=True, ....: report_edges=True, labels=True)) [[(1, 3, 10), (3, 5, 10), (5, 6, 5)], [(1, 2, 20), (2, 5, 20), (5, 6, 5)], [(1, 4, 30), (4, 5, 30), (5, 6, 5)], [(1, 6, 100)]] sage: list(g.shortest_simple_paths(1, 6, report_edges=True, labels=True)) [[(1, 6, 100)], [(1, 2, 20), (2, 5, 20), (5, 6, 5)], [(1, 3, 10), (3, 5, 10), (5, 6, 5)], [(1, 4, 30), (4, 5, 30), (5, 6, 5)]]
>>> from sage.all import * >>> g = DiGraph([(Integer(1), Integer(2), Integer(20)), (Integer(1), Integer(3), Integer(10)), (Integer(1), Integer(4), Integer(30)), ... (Integer(2), Integer(5), Integer(20)), (Integer(3), Integer(5), Integer(10)), (Integer(4), Integer(5), Integer(30))]) >>> list(g.shortest_simple_paths(Integer(1), Integer(5), by_weight=True, algorithm='Yen')) [[1, 3, 5], [1, 2, 5], [1, 4, 5]] >>> list(g.shortest_simple_paths(Integer(1), Integer(5), algorithm='Yen')) [[1, 2, 5], [1, 3, 5], [1, 4, 5]] >>> list(g.shortest_simple_paths(Integer(1), Integer(1))) [[1]] >>> list(g.shortest_simple_paths(Integer(1), Integer(5), by_weight=True, ... report_edges=True, report_weight=True, labels=True)) [(20, [(1, 3, 10), (3, 5, 10)]), (40, [(1, 2, 20), (2, 5, 20)]), (60, [(1, 4, 30), (4, 5, 30)])] >>> list(g.shortest_simple_paths(Integer(1), Integer(5), by_weight=True, algorithm='Feng', ... report_edges=True, report_weight=True)) [(20, [(1, 3), (3, 5)]), (40, [(1, 2), (2, 5)]), (60, [(1, 4), (4, 5)])] >>> list(g.shortest_simple_paths(Integer(1), Integer(5), report_edges=True, report_weight=True)) [(2, [(1, 2), (2, 5)]), (2, [(1, 3), (3, 5)]), (2, [(1, 4), (4, 5)])] >>> list(g.shortest_simple_paths(Integer(1), Integer(5), by_weight=True, report_edges=True)) [[(1, 3), (3, 5)], [(1, 2), (2, 5)], [(1, 4), (4, 5)]] >>> list(g.shortest_simple_paths(Integer(1), Integer(5), by_weight=True, algorithm='Feng', ... report_edges=True, labels=True)) [[(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)], [(1, 4, 30), (4, 5, 30)]] >>> g = Graph([(Integer(1), Integer(2), Integer(20)), (Integer(1), Integer(3), Integer(10)), (Integer(1), Integer(4), Integer(30)), (Integer(2), Integer(5), Integer(20)), ... (Integer(3), Integer(5), Integer(10)), (Integer(4), Integer(5), Integer(30)), (Integer(1), Integer(6), Integer(100)), (Integer(5), Integer(6), Integer(5))]) >>> list(g.shortest_simple_paths(Integer(1), Integer(6), by_weight = True)) [[1, 3, 5, 6], [1, 2, 5, 6], [1, 4, 5, 6], [1, 6]] >>> list(g.shortest_simple_paths(Integer(1), Integer(6), algorithm='Yen')) [[1, 6], [1, 2, 5, 6], [1, 3, 5, 6], [1, 4, 5, 6]] >>> list(g.shortest_simple_paths(Integer(1), Integer(6), ... report_edges=True, report_weight=True, labels=True)) [(1, [(1, 6, 100)]), (3, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]), (3, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]), (3, [(1, 4, 30), (4, 5, 30), (5, 6, 5)])] >>> list(g.shortest_simple_paths(Integer(1), Integer(6), by_weight=True, ... report_edges=True, report_weight=True, labels=True)) [(25, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]), (45, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]), (65, [(1, 4, 30), (4, 5, 30), (5, 6, 5)]), (100, [(1, 6, 100)])] >>> list(g.shortest_simple_paths(Integer(1), Integer(6), by_weight=True, ... report_edges=True, labels=True)) [[(1, 3, 10), (3, 5, 10), (5, 6, 5)], [(1, 2, 20), (2, 5, 20), (5, 6, 5)], [(1, 4, 30), (4, 5, 30), (5, 6, 5)], [(1, 6, 100)]] >>> list(g.shortest_simple_paths(Integer(1), Integer(6), report_edges=True, labels=True)) [[(1, 6, 100)], [(1, 2, 20), (2, 5, 20), (5, 6, 5)], [(1, 3, 10), (3, 5, 10), (5, 6, 5)], [(1, 4, 30), (4, 5, 30), (5, 6, 5)]]
- sage.graphs.path_enumeration.yen_k_shortest_simple_paths(self, source, target, weight_function=None, by_weight=False, check_weight=True, report_edges=False, labels=False, report_weight=False)[source]¶
Return an iterator over the simple paths between a pair of vertices in increasing order of weights.
For unweighted graphs paths are returned in order of increasing number of edges.
In case of weighted graphs negative weights are not allowed.
If
sourceis the same vertex astarget, then[[source]]is returned – a list containing the 1-vertex, 0-edge pathsource.The loops and the multiedges if present in the given graph are ignored and only minimum of the edge labels is kept in case of multiedges.
INPUT:
source– a vertex of the graph, where to starttarget– a vertex of the graph, where to endweight_function– function (default:None); a function that takes as input an edge(u, v, l)and outputs its weight. If notNone,by_weightis automatically set toTrue. IfNoneandby_weightisTrue, we use the edge labellas a weight.by_weight– boolean (default:False); ifTrue, the edges in the graph are weighted, otherwise all edges have weight 1check_weight– boolean (default:True); whether to check that theweight_functionoutputs a number for each edgereport_edges– boolean (default:False); whether to report paths as list of vertices (default) or list of edges, ifFalsethenlabelsparameter is ignoredlabels– boolean (default:False); ifFalse, each edge is simply a pair(u, v)of vertices. Otherwise a list of edges along with its edge labels are used to represent the path.report_weight– boolean (default:False); ifFalse, just the path betweensourceandtargetis returned. Otherwise a tuple of path length and path is returned.
ALGORITHM:
This algorithm can be divided into two parts. Firstly, it determines a shortest path from
sourcetotarget. Then, it determines all the other \(k\)-shortest paths. This algorithm finds the deviations of previous shortest paths to determine the next shortest paths.Time complexity is \(O(kn(m+n\log{n}))\) where \(n\) is the number of vertices and \(m\) is the number of edges and \(k\) is the number of shortest paths needed to find.
See [Yen1970] and the Wikipedia article Yen%27s_algorithm for more details on the algorithm.
EXAMPLES:
sage: from sage.graphs.path_enumeration import yen_k_shortest_simple_paths sage: g = DiGraph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20), (3, 5, 10), (4, 5, 30)]) sage: list(yen_k_shortest_simple_paths(g, 1, 5, by_weight=True)) [[1, 3, 5], [1, 2, 5], [1, 4, 5]] sage: list(yen_k_shortest_simple_paths(g, 1, 5)) [[1, 2, 5], [1, 3, 5], [1, 4, 5]] sage: list(yen_k_shortest_simple_paths(g, 1, 1)) [[1]] sage: list(yen_k_shortest_simple_paths(g, 1, 5, by_weight=True, report_edges=True, report_weight=True, labels=True)) [(20, [(1, 3, 10), (3, 5, 10)]), (40, [(1, 2, 20), (2, 5, 20)]), (60, [(1, 4, 30), (4, 5, 30)])] sage: list(yen_k_shortest_simple_paths(g, 1, 5, by_weight=True, report_edges=True, report_weight=True)) [(20, [(1, 3), (3, 5)]), (40, [(1, 2), (2, 5)]), (60, [(1, 4), (4, 5)])] sage: list(yen_k_shortest_simple_paths(g, 1, 5, report_edges=True, report_weight=True)) [(2, [(1, 2), (2, 5)]), (2, [(1, 3), (3, 5)]), (2, [(1, 4), (4, 5)])] sage: list(yen_k_shortest_simple_paths(g, 1, 5, by_weight=True, report_edges=True)) [[(1, 3), (3, 5)], [(1, 2), (2, 5)], [(1, 4), (4, 5)]] sage: list(yen_k_shortest_simple_paths(g, 1, 5, by_weight=True, report_edges=True, labels=True)) [[(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)], [(1, 4, 30), (4, 5, 30)]] sage: from sage.graphs.path_enumeration import yen_k_shortest_simple_paths sage: g = Graph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20), (3, 5, 10), (4, 5, 30), (1, 6, 100), (5, 6, 5)]) sage: list(yen_k_shortest_simple_paths(g, 1, 6, by_weight = True)) [[1, 3, 5, 6], [1, 2, 5, 6], [1, 4, 5, 6], [1, 6]] sage: list(yen_k_shortest_simple_paths(g, 1, 6)) [[1, 6], [1, 2, 5, 6], [1, 3, 5, 6], [1, 4, 5, 6]] sage: list(yen_k_shortest_simple_paths(g, 1, 6, report_edges=True, report_weight=True, labels=True)) [(1, [(1, 6, 100)]), (3, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]), (3, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]), (3, [(1, 4, 30), (4, 5, 30), (5, 6, 5)])] sage: list(yen_k_shortest_simple_paths(g, 1, 6, report_edges=True, report_weight=True, labels=True, by_weight=True)) [(25, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]), (45, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]), (65, [(1, 4, 30), (4, 5, 30), (5, 6, 5)]), (100, [(1, 6, 100)])] sage: list(yen_k_shortest_simple_paths(g, 1, 6, report_edges=True, labels=True, by_weight=True)) [[(1, 3, 10), (3, 5, 10), (5, 6, 5)], [(1, 2, 20), (2, 5, 20), (5, 6, 5)], [(1, 4, 30), (4, 5, 30), (5, 6, 5)], [(1, 6, 100)]] sage: list(yen_k_shortest_simple_paths(g, 1, 6, report_edges=True, labels=True)) [[(1, 6, 100)], [(1, 2, 20), (2, 5, 20), (5, 6, 5)], [(1, 3, 10), (3, 5, 10), (5, 6, 5)], [(1, 4, 30), (4, 5, 30), (5, 6, 5)]]
>>> from sage.all import * >>> from sage.graphs.path_enumeration import yen_k_shortest_simple_paths >>> g = DiGraph([(Integer(1), Integer(2), Integer(20)), (Integer(1), Integer(3), Integer(10)), (Integer(1), Integer(4), Integer(30)), (Integer(2), Integer(5), Integer(20)), (Integer(3), Integer(5), Integer(10)), (Integer(4), Integer(5), Integer(30))]) >>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(5), by_weight=True)) [[1, 3, 5], [1, 2, 5], [1, 4, 5]] >>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(5))) [[1, 2, 5], [1, 3, 5], [1, 4, 5]] >>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(1))) [[1]] >>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(5), by_weight=True, report_edges=True, report_weight=True, labels=True)) [(20, [(1, 3, 10), (3, 5, 10)]), (40, [(1, 2, 20), (2, 5, 20)]), (60, [(1, 4, 30), (4, 5, 30)])] >>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(5), by_weight=True, report_edges=True, report_weight=True)) [(20, [(1, 3), (3, 5)]), (40, [(1, 2), (2, 5)]), (60, [(1, 4), (4, 5)])] >>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(5), report_edges=True, report_weight=True)) [(2, [(1, 2), (2, 5)]), (2, [(1, 3), (3, 5)]), (2, [(1, 4), (4, 5)])] >>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(5), by_weight=True, report_edges=True)) [[(1, 3), (3, 5)], [(1, 2), (2, 5)], [(1, 4), (4, 5)]] >>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(5), by_weight=True, report_edges=True, labels=True)) [[(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)], [(1, 4, 30), (4, 5, 30)]] >>> from sage.graphs.path_enumeration import yen_k_shortest_simple_paths >>> g = Graph([(Integer(1), Integer(2), Integer(20)), (Integer(1), Integer(3), Integer(10)), (Integer(1), Integer(4), Integer(30)), (Integer(2), Integer(5), Integer(20)), (Integer(3), Integer(5), Integer(10)), (Integer(4), Integer(5), Integer(30)), (Integer(1), Integer(6), Integer(100)), (Integer(5), Integer(6), Integer(5))]) >>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(6), by_weight = True)) [[1, 3, 5, 6], [1, 2, 5, 6], [1, 4, 5, 6], [1, 6]] >>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(6))) [[1, 6], [1, 2, 5, 6], [1, 3, 5, 6], [1, 4, 5, 6]] >>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(6), report_edges=True, report_weight=True, labels=True)) [(1, [(1, 6, 100)]), (3, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]), (3, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]), (3, [(1, 4, 30), (4, 5, 30), (5, 6, 5)])] >>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(6), report_edges=True, report_weight=True, labels=True, by_weight=True)) [(25, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]), (45, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]), (65, [(1, 4, 30), (4, 5, 30), (5, 6, 5)]), (100, [(1, 6, 100)])] >>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(6), report_edges=True, labels=True, by_weight=True)) [[(1, 3, 10), (3, 5, 10), (5, 6, 5)], [(1, 2, 20), (2, 5, 20), (5, 6, 5)], [(1, 4, 30), (4, 5, 30), (5, 6, 5)], [(1, 6, 100)]] >>> list(yen_k_shortest_simple_paths(g, Integer(1), Integer(6), report_edges=True, labels=True)) [[(1, 6, 100)], [(1, 2, 20), (2, 5, 20), (5, 6, 5)], [(1, 3, 10), (3, 5, 10), (5, 6, 5)], [(1, 4, 30), (4, 5, 30), (5, 6, 5)]]