Skip to content

Commit 87f1e8e

Browse files
committed
Fixed validity check for external_face in Tutte layout
1 parent 28ee004 commit 87f1e8e

File tree

1 file changed

+13
-17
lines changed

1 file changed

+13
-17
lines changed

src/sage/graphs/generic_graph.py

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21663,13 +21663,14 @@ def layout_tutte(self, external_face=None, external_face_pos=None, **options):
2166321663
OUTPUT: a dictionary mapping vertices to positions
2166421664

2166521665
EXAMPLES::
21666+
2166621667
sage: g = graphs.WheelGraph(n=7)
2166721668
sage: g.plot(layout='tutte', external_face=[0,1,2]) # needs sage.plot
2166821669
Graphics object consisting of 20 graphics primitives
2166921670
sage: g = graphs.CubeGraph(n=3, embedding=2)
2167021671
sage: g.plot(layout='tutte', external_face=['101','111','001',
2167121672
....: '011'], external_face_pos={'101':(1,0), '111':(0,0),
21672-
....: '001':(2,1), '011':(-1,1)}) # needs sage.plot
21673+
....: '001':(2,1), '011':(-1,1)}) # needs sage.plot
2167321674
Graphics object consisting of 21 graphics primitives
2167421675
sage: g = graphs.CompleteGraph(n=5)
2167521676
sage: g.plot(layout='tutte', external_face=[0,1,2])
@@ -21688,32 +21689,27 @@ def layout_tutte(self, external_face=None, external_face_pos=None, **options):
2168821689
if (external_face is not None) and (len(external_face) < 3):
2168921690
raise ValueError("external face must have at least 3 vertices")
2169021691

21691-
if not self.is_planar():
21692+
if not self.is_planar(set_embedding=True):
2169221693
raise ValueError("graph must be planar")
2169321694

2169421695
if not self.vertex_connectivity(k=3):
2169521696
raise ValueError("graph must be 3-connected")
2169621697

21698+
faces_edges = self.faces()
21699+
faces_vertices = [[edge[0] for edge in face] for face in faces_edges]
2169721700
if external_face is None:
21698-
from sage.graphs.graph import Graph
21699-
H = Graph(self) # take a (undirected) copy H of the graph
21700-
u, v = next(H.edge_iterator(labels=False)) # take any edge (u, v) of H
21701-
H.delete_edge(u, v) # remove edge (u, v) from H
21702-
external_face = H.shortest_path(v, u)
21703-
# Compute a shortest path from v to u in H minus (u, v)H = G.
21704-
# Cycle existence is guaranteed since G is 3-connected.
21701+
external_face = faces_vertices[0]
2170521702
else:
21706-
C = self.subgraph(vertices=external_face)
21707-
if (not C.is_cycle(directed_cycle=False)):
21708-
raise ValueError("external face must be a cycle")
21709-
external_face = C.depth_first_search(start=external_face[0], ignore_direction=False)
21703+
# Check that external_face is a face and order it correctly
21704+
matching_face = next((f for f in faces_vertices if sorted(external_face) == sorted(f)), None)
21705+
if matching_face is None:
21706+
raise ValueError("external face must be a face of the graph")
21707+
external_face = matching_face
2171021708

21711-
pos = dict()
2171221709
if external_face_pos is None:
2171321710
pos = self._circle_embedding(external_face, return_dict=True)
2171421711
else:
21715-
for v, p in external_face_pos.items():
21716-
pos[v] = p
21712+
pos = external_face_pos.copy()
2171721713

2171821714
n = self.order()
2171921715
M = zero_matrix(RR, n, n)
@@ -22123,7 +22119,7 @@ def plot(self, **options):
2212322119
appear on the bottom (resp., top) and the tree will grow upwards
2212422120
(resp. downwards). Ignored unless ``layout='tree'``.
2212522121

22126-
- ``external_face`` -- list of vertices; the external face to be made a
22122+
- ``external_face`` -- list of vertices (default: ``None``); the external face to be made a
2212722123
in the Tutte layout. Ignored unless ``layout='tutte''``.
2212822124

2212922125
- ``external_face_pos`` -- dictionary (default: ``None``). If specified,

0 commit comments

Comments
 (0)