Skip to content

Commit

Permalink
sagemathgh-37260: extend all_paths_iterator and all_simple_paths
Browse files Browse the repository at this point in the history
…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
- sagemath#12345: short description why this is a dependency
- sagemath#34567: ...
-->

<!-- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->
    
URL: sagemath#37260
Reported by: David Coudert
Reviewer(s): John H. Palmieri
  • Loading branch information
Release Manager committed Feb 19, 2024
2 parents 66b3fad + df2af39 commit 35e7445
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 7 deletions.
5 changes: 0 additions & 5 deletions src/sage/graphs/digraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,6 @@
:widths: 30, 70
:delim: |
:meth:`~DiGraph.all_paths_iterator` | Return an iterator over the paths of ``self``.
:meth:`~DiGraph.all_simple_paths` | Return a list of all the simple paths of ``self`` starting with one of the given vertices.
:meth:`~DiGraph.all_cycles_iterator` | Return an iterator over all the cycles of ``self`` starting with one of the given vertices.
:meth:`~DiGraph.all_simple_cycles` | Return a list of all simple cycles of ``self``.
Expand Down Expand Up @@ -4379,6 +4377,3 @@ def _singleton_in_branching():
from sage.graphs.connectivity import strongly_connected_components_subgraphs
from sage.graphs.connectivity import strongly_connected_component_containing_vertex
from sage.graphs.connectivity import strong_articulation_points
from sage.graphs.path_enumeration import _all_paths_iterator
from sage.graphs.path_enumeration import all_paths_iterator
from sage.graphs.path_enumeration import all_simple_paths
5 changes: 5 additions & 0 deletions src/sage/graphs/generic_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@
:meth:`~GenericGraph.minimum_cycle_basis` | Return a minimum weight cycle basis of the graph.
:meth:`~GenericGraph.cycle_basis` | Return a list of cycles which form a basis of the cycle space of ``self``.
:meth:`~GenericGraph.all_paths` | Return a list of all paths (also lists) between a pair of vertices in the (di)graph.
:meth:`~GenericGraph.all_paths_iterator` | Return an iterator over the paths of ``self``.
:meth:`~GenericGraph.all_simple_paths` | Return a list of all the simple paths of ``self`` starting with one of the given vertices.
:meth:`~GenericGraph.triangles_count` | Return the number of triangles in the (di)graph.
:meth:`~GenericGraph.shortest_simple_paths` | Return an iterator over the simple paths between a pair of vertices.

Expand Down Expand Up @@ -24863,6 +24865,9 @@ def is_self_complementary(self):
rooted_product = LazyImport('sage.graphs.graph_decompositions.graph_products', 'rooted_product')
from sage.graphs.path_enumeration import shortest_simple_paths
from sage.graphs.path_enumeration import all_paths
from sage.graphs.path_enumeration import _all_paths_iterator
from sage.graphs.path_enumeration import all_paths_iterator
from sage.graphs.path_enumeration import all_simple_paths
from sage.graphs.traversals import lex_BFS
from sage.graphs.traversals import lex_UP
from sage.graphs.traversals import lex_DFS
Expand Down
66 changes: 64 additions & 2 deletions src/sage/graphs/path_enumeration.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -1439,6 +1439,21 @@ def _all_paths_iterator(self, vertex, ending_vertices=None,
EXAMPLES::
sage: G = graphs.CompleteGraph(4)
sage: list(G._all_paths_iterator(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(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('a', ending_vertices=['d'], report_edges=True, simple=True)
sage: list(pi)
Expand Down Expand Up @@ -1536,6 +1551,11 @@ def _all_paths_iterator(self, vertex, ending_vertices=None,
if max_length < 1:
return

if self.is_directed():
neighbor_iterator = self.neighbor_out_iterator
else:
neighbor_iterator = self.neighbor_iterator

cdef dict my_dict = {}
cdef dict edge_multiplicity
if not data:
Expand Down Expand Up @@ -1579,7 +1599,7 @@ def _all_paths_iterator(self, vertex, ending_vertices=None,
# for further extension, but just yield it immediately. See
# trac #12385.
frozen_path = frozenset(path)
for neighbor in self.neighbor_out_iterator(path[-1]):
for neighbor in neighbor_iterator(path[-1]):
if neighbor not in frozen_path:
queue.append(path + [neighbor])
elif (neighbor == path[0] and
Expand All @@ -1600,7 +1620,7 @@ def _all_paths_iterator(self, vertex, ending_vertices=None,
yield newpath
else:
# Non-simple paths requested: we add all of them
for neighbor in self.neighbor_out_iterator(path[-1]):
for neighbor in neighbor_iterator(path[-1]):
queue.append(path + [neighbor])

if not queue:
Expand Down Expand Up @@ -1686,6 +1706,21 @@ def all_paths_iterator(self, starting_vertices=None, ending_vertices=None,
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)
Expand Down Expand Up @@ -1909,6 +1944,33 @@ def all_simple_paths(self, starting_vertices=None, ending_vertices=None,
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],
Expand Down

0 comments on commit 35e7445

Please sign in to comment.