Skip to content

Commit cb8c43b

Browse files
committed
some improvements in sage/graphs/orientations.py
1 parent 543f8d6 commit cb8c43b

File tree

1 file changed

+38
-28
lines changed

1 file changed

+38
-28
lines changed

src/sage/graphs/orientations.py

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,31 @@
2525
Methods
2626
-------
2727
"""
28+
# ****************************************************************************
29+
# Copyright (C) 2017 Kolja Knauer <[email protected]>
30+
# 2017 Petru Valicov <[email protected]>
31+
# 2017-2023 David Coudert <[email protected]>
32+
#
33+
# This program is free software: you can redistribute it and/or modify
34+
# it under the terms of the GNU General Public License as published by
35+
# the Free Software Foundation, either version 2 of the License, or
36+
# (at your option) any later version.
37+
# https://www.gnu.org/licenses/
38+
# ****************************************************************************
39+
2840
from copy import copy
2941
from sage.graphs.digraph import DiGraph
3042

3143

3244
def strong_orientations_iterator(G):
3345
r"""
34-
Returns an iterator over all strong orientations of a graph `G`.
46+
Return an iterator over all strong orientations of a graph `G`.
3547
36-
A strong orientation of a graph is an orientation of its edges such that
37-
the obtained digraph is strongly connected (i.e. there exist a directed path
38-
between each pair of vertices).
48+
A strong orientation of a graph is an orientation of its edges such that the
49+
obtained digraph is strongly connected (i.e. there exist a directed path
50+
between each pair of vertices). According Robin's theorem (see the
51+
:wikipedia:`Robbins_theorem`), the graphs that have strong orientations are
52+
exactly the 2-edge-connected graphs (i.e., the bridgeless graphs).
3953
4054
ALGORITHM:
4155
@@ -84,7 +98,7 @@ def strong_orientations_iterator(G):
8498
8599
A tree cannot be strongly oriented::
86100
87-
sage: g = graphs.RandomTree(100)
101+
sage: g = graphs.RandomTree(10)
88102
sage: len(list(g.strong_orientations_iterator()))
89103
0
90104
@@ -115,44 +129,37 @@ def strong_orientations_iterator(G):
115129
sage: g = graphs.PetersenGraph()
116130
sage: nr1 = len(list(g.strong_orientations_iterator()))
117131
sage: nr2 = g.tutte_polynomial()(0,2)
118-
sage: nr1 == nr2/2 # The Tutte polynomial counts also the symmetrical orientations
132+
sage: nr1 == nr2/2 # The Tutte polynomial counts also the symmetrical orientations
119133
True
120-
121134
"""
122135
# if the graph has a bridge or is disconnected,
123136
# then it cannot be strongly oriented
124-
if G.order() < 3 or not G.is_biconnected():
137+
if G.order() < 3 or not G.is_connected() or any(G.bridges(labels=False)):
125138
return
126139

127-
V = G.vertices(sort=False)
128-
Dg = DiGraph([V, G.edges(sort=False)], pos=G.get_pos())
140+
V = list(G)
129141

130142
# compute an arbitrary spanning tree of the undirected graph
131-
te = G.min_spanning_tree()
132-
treeEdges = [(u, v) for u, v, _ in te]
133-
tree_edges_set = set(treeEdges)
134-
A = [edge for edge in G.edge_iterator(labels=False) if edge not in tree_edges_set]
143+
T = G.subgraph(vertices=G, edges=G.min_spanning_tree(), inplace=False)
144+
treeEdges = list(T.edges(labels=False, sort=False))
145+
A = [edge for edge in G.edge_iterator(labels=False) if not T.has_edge(edge)]
146+
147+
# Initialize a digraph with the edges of the spanning tree doubly oriented
148+
Dg = T.to_directed(sparse=True)
149+
Dg.add_edges(A)
135150

136151
# initialization of the first binary word 00...0
137152
# corresponding to the current orientation of the non-tree edges
138153
existingAedges = [0] * len(A)
139154

140-
# Make the edges of the spanning tree doubly oriented
141-
for e in treeEdges:
142-
if Dg.has_edge(e):
143-
Dg.add_edge(e[1], e[0])
144-
else:
145-
Dg.add_edge(e)
146-
147155
# Generate all orientations for non-tree edges (using Gray code)
148156
# Each of these orientations can be extended to a strong orientation
149157
# of G by orienting properly the tree-edges
150158
previousWord = 0
151-
i = 0
152159

153160
# the orientation of one edge is fixed so we consider one edge less
154161
nr = 2**(len(A) - 1)
155-
while i < nr:
162+
for i in range(nr):
156163
word = (i >> 1) ^ i
157164
bitChanged = word ^ previousWord
158165

@@ -171,7 +178,6 @@ def strong_orientations_iterator(G):
171178
# launch the algorithm for enumeration of the solutions
172179
for sol in _strong_orientations_of_a_mixed_graph(Dg, V, treeEdges):
173180
yield sol
174-
i = i + 1
175181

176182

177183
def _strong_orientations_of_a_mixed_graph(Dg, V, E):
@@ -201,9 +207,9 @@ def _strong_orientations_of_a_mixed_graph(Dg, V, E):
201207
202208
sage: from sage.graphs.orientations import _strong_orientations_of_a_mixed_graph
203209
sage: g = graphs.CycleGraph(5)
204-
sage: Dg = DiGraph(g) # all edges of g will be doubly oriented
210+
sage: Dg = DiGraph(g) # all edges of g will be doubly oriented
205211
sage: it = _strong_orientations_of_a_mixed_graph(Dg, list(g), list(g.edges(labels=False, sort=False)))
206-
sage: len(list(it)) # there are two orientations of this multigraph
212+
sage: len(list(it)) # there are two orientations of this multigraph
207213
2
208214
"""
209215
length = len(E)
@@ -213,7 +219,9 @@ def _strong_orientations_of_a_mixed_graph(Dg, V, E):
213219
u, v = E[i]
214220
Dg.delete_edge(u, v)
215221
if not (v in Dg.depth_first_search(u)):
216-
del E[i]
222+
# del E[i] in constant time
223+
E[i] = E[-1]
224+
E.pop()
217225
length -= 1
218226
Dg.add_edge(u, v)
219227
Dg.delete_edge(v, u)
@@ -222,7 +230,9 @@ def _strong_orientations_of_a_mixed_graph(Dg, V, E):
222230
Dg.add_edge(u, v)
223231
Dg.delete_edge(v, u)
224232
if not (u in Dg.depth_first_search(v)):
225-
del E[i]
233+
# del E[i] in constant time
234+
E[i] = E[-1]
235+
E.pop()
226236
length -= 1
227237
boundEdges.append((u, v))
228238
Dg.delete_edge(u, v)

0 commit comments

Comments
 (0)