Skip to content

Commit ffa8751

Browse files
author
Release Manager
committed
gh-37260: extend `all_paths_iterator` and `all_simple_paths` to Graph This answer a question from https://ask.sagemath.org/question/75715/all_simple_paths-generates- attributeerror-for-graphs/ We make methods `all_paths_iterator` and `all_simple_paths` work for both `Graph` and `DiGraph`. ### 📝 Checklist <!-- Put an `x` in all the boxes that apply. --> <!-- If your change requires a documentation PR, please link it appropriately --> <!-- If you're unsure about any of these, don't hesitate to ask. We're here to help! --> <!-- Feel free to remove irrelevant items. --> - [x] The title is concise, informative, and self-explanatory. - [x] The description explains in detail what this PR is about. - [x] I have linked a relevant issue or discussion. - [x] I have created tests covering the changes. - [x] I have updated the documentation accordingly. ### ⌛ Dependencies <!-- List all open PRs that this PR logically depends on - #12345: short description why this is a dependency - #34567: ... --> <!-- If you're unsure about any of these, don't hesitate to ask. We're here to help! --> URL: #37260 Reported by: David Coudert Reviewer(s): John H. Palmieri
2 parents d4075f1 + df2af39 commit ffa8751

File tree

3 files changed

+69
-7
lines changed

3 files changed

+69
-7
lines changed

src/sage/graphs/digraph.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@
5757
:widths: 30, 70
5858
:delim: |
5959
60-
:meth:`~DiGraph.all_paths_iterator` | Return an iterator over the paths of ``self``.
61-
:meth:`~DiGraph.all_simple_paths` | Return a list of all the simple paths of ``self`` starting with one of the given vertices.
6260
:meth:`~DiGraph.all_cycles_iterator` | Return an iterator over all the cycles of ``self`` starting with one of the given vertices.
6361
:meth:`~DiGraph.all_simple_cycles` | Return a list of all simple cycles of ``self``.
6462
@@ -4379,6 +4377,3 @@ def _singleton_in_branching():
43794377
from sage.graphs.connectivity import strongly_connected_components_subgraphs
43804378
from sage.graphs.connectivity import strongly_connected_component_containing_vertex
43814379
from sage.graphs.connectivity import strong_articulation_points
4382-
from sage.graphs.path_enumeration import _all_paths_iterator
4383-
from sage.graphs.path_enumeration import all_paths_iterator
4384-
from sage.graphs.path_enumeration import all_simple_paths

src/sage/graphs/generic_graph.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@
122122
:meth:`~GenericGraph.minimum_cycle_basis` | Return a minimum weight cycle basis of the graph.
123123
:meth:`~GenericGraph.cycle_basis` | Return a list of cycles which form a basis of the cycle space of ``self``.
124124
:meth:`~GenericGraph.all_paths` | Return a list of all paths (also lists) between a pair of vertices in the (di)graph.
125+
:meth:`~GenericGraph.all_paths_iterator` | Return an iterator over the paths of ``self``.
126+
:meth:`~GenericGraph.all_simple_paths` | Return a list of all the simple paths of ``self`` starting with one of the given vertices.
125127
:meth:`~GenericGraph.triangles_count` | Return the number of triangles in the (di)graph.
126128
:meth:`~GenericGraph.shortest_simple_paths` | Return an iterator over the simple paths between a pair of vertices.
127129

@@ -24863,6 +24865,9 @@ def is_self_complementary(self):
2486324865
rooted_product = LazyImport('sage.graphs.graph_decompositions.graph_products', 'rooted_product')
2486424866
from sage.graphs.path_enumeration import shortest_simple_paths
2486524867
from sage.graphs.path_enumeration import all_paths
24868+
from sage.graphs.path_enumeration import _all_paths_iterator
24869+
from sage.graphs.path_enumeration import all_paths_iterator
24870+
from sage.graphs.path_enumeration import all_simple_paths
2486624871
from sage.graphs.traversals import lex_BFS
2486724872
from sage.graphs.traversals import lex_UP
2486824873
from sage.graphs.traversals import lex_DFS

src/sage/graphs/path_enumeration.pyx

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,6 +1439,21 @@ def _all_paths_iterator(self, vertex, ending_vertices=None,
14391439
14401440
EXAMPLES::
14411441
1442+
sage: G = graphs.CompleteGraph(4)
1443+
sage: list(G._all_paths_iterator(1, ending_vertices=[3], simple=True))
1444+
[[1, 3], [1, 0, 3], [1, 2, 3], [1, 0, 2, 3], [1, 2, 0, 3]]
1445+
sage: list(G.shortest_simple_paths(1, 3))
1446+
[[1, 3], [1, 0, 3], [1, 2, 3], [1, 2, 0, 3], [1, 0, 2, 3]]
1447+
sage: pi = G._all_paths_iterator(1, ending_vertices=[3])
1448+
sage: for _ in range(6):
1449+
....: print(next(pi))
1450+
[1, 3]
1451+
[1, 0, 3]
1452+
[1, 2, 3]
1453+
[1, 0, 1, 3]
1454+
[1, 0, 2, 3]
1455+
[1, 2, 0, 3]
1456+
14421457
sage: g = DiGraph({'a': ['a', 'b'], 'b': ['c'], 'c': ['d'], 'd': ['c']}, loops=True)
14431458
sage: pi = g._all_paths_iterator('a', ending_vertices=['d'], report_edges=True, simple=True)
14441459
sage: list(pi)
@@ -1536,6 +1551,11 @@ def _all_paths_iterator(self, vertex, ending_vertices=None,
15361551
if max_length < 1:
15371552
return
15381553

1554+
if self.is_directed():
1555+
neighbor_iterator = self.neighbor_out_iterator
1556+
else:
1557+
neighbor_iterator = self.neighbor_iterator
1558+
15391559
cdef dict my_dict = {}
15401560
cdef dict edge_multiplicity
15411561
if not data:
@@ -1579,7 +1599,7 @@ def _all_paths_iterator(self, vertex, ending_vertices=None,
15791599
# for further extension, but just yield it immediately. See
15801600
# trac #12385.
15811601
frozen_path = frozenset(path)
1582-
for neighbor in self.neighbor_out_iterator(path[-1]):
1602+
for neighbor in neighbor_iterator(path[-1]):
15831603
if neighbor not in frozen_path:
15841604
queue.append(path + [neighbor])
15851605
elif (neighbor == path[0] and
@@ -1600,7 +1620,7 @@ def _all_paths_iterator(self, vertex, ending_vertices=None,
16001620
yield newpath
16011621
else:
16021622
# Non-simple paths requested: we add all of them
1603-
for neighbor in self.neighbor_out_iterator(path[-1]):
1623+
for neighbor in neighbor_iterator(path[-1]):
16041624
queue.append(path + [neighbor])
16051625

16061626
if not queue:
@@ -1686,6 +1706,21 @@ def all_paths_iterator(self, starting_vertices=None, ending_vertices=None,
16861706
16871707
EXAMPLES::
16881708
1709+
sage: G = graphs.CompleteGraph(4)
1710+
sage: list(G.all_paths_iterator(starting_vertices=[1], ending_vertices=[3], simple=True))
1711+
[[1, 3], [1, 0, 3], [1, 2, 3], [1, 0, 2, 3], [1, 2, 0, 3]]
1712+
sage: list(G.shortest_simple_paths(1, 3))
1713+
[[1, 3], [1, 0, 3], [1, 2, 3], [1, 2, 0, 3], [1, 0, 2, 3]]
1714+
sage: pi = G.all_paths_iterator(starting_vertices=[1], ending_vertices=[3])
1715+
sage: for _ in range(6):
1716+
....: print(next(pi))
1717+
[1, 3]
1718+
[1, 0, 3]
1719+
[1, 2, 3]
1720+
[1, 0, 1, 3]
1721+
[1, 0, 2, 3]
1722+
[1, 2, 0, 3]
1723+
16891724
sage: g = DiGraph({'a': ['a', 'b'], 'b': ['c'], 'c': ['d'], 'd': ['c']}, loops=True)
16901725
sage: pi = g.all_paths_iterator(starting_vertices=['a'], ending_vertices=['d'], report_edges=True, simple=True)
16911726
sage: list(pi)
@@ -1909,6 +1944,33 @@ def all_simple_paths(self, starting_vertices=None, ending_vertices=None,
19091944
19101945
EXAMPLES::
19111946
1947+
sage: G = graphs.CompleteGraph(4)
1948+
sage: G.all_simple_paths([1], [3])
1949+
[[1, 3], [1, 0, 3], [1, 2, 3], [1, 0, 2, 3], [1, 2, 0, 3]]
1950+
sage: list(G.shortest_simple_paths(1, 3))
1951+
[[1, 3], [1, 0, 3], [1, 2, 3], [1, 2, 0, 3], [1, 0, 2, 3]]
1952+
sage: G.all_simple_paths([0, 1], [2, 3])
1953+
[[1, 2],
1954+
[1, 3],
1955+
[0, 2],
1956+
[0, 3],
1957+
[0, 1, 2],
1958+
[0, 1, 3],
1959+
[0, 2, 3],
1960+
[0, 3, 2],
1961+
[1, 0, 2],
1962+
[1, 0, 3],
1963+
[1, 2, 3],
1964+
[1, 3, 2],
1965+
[1, 0, 2, 3],
1966+
[1, 0, 3, 2],
1967+
[1, 2, 0, 3],
1968+
[1, 3, 0, 2],
1969+
[0, 1, 2, 3],
1970+
[0, 1, 3, 2],
1971+
[0, 2, 1, 3],
1972+
[0, 3, 1, 2]]
1973+
19121974
sage: g = DiGraph({0: [0, 1], 1: [2], 2: [3], 3: [2]}, loops=True)
19131975
sage: g.all_simple_paths()
19141976
[[3, 2],

0 commit comments

Comments
 (0)