Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
trac #16475: Merged with 6.7
Browse files Browse the repository at this point in the history
  • Loading branch information
nathanncohen committed May 18, 2015
2 parents e00f17b + 5732579 commit 7fadf1f
Showing 1 changed file with 69 additions and 82 deletions.
151 changes: 69 additions & 82 deletions src/sage/graphs/graph.py
Expand Up @@ -6312,7 +6312,7 @@ def is_prime(self):

return D[0] == "Prime" and len(D[1]) == self.order()

def _gomory_hu_tree(self, vertices=None, method="FF"):
def _gomory_hu_tree(self, vertices, method="FF"):
r"""
Returns a Gomory-Hu tree associated to self.
Expand Down Expand Up @@ -6345,101 +6345,65 @@ def _gomory_hu_tree(self, vertices=None, method="FF"):
example is only present to have a doctest coverage of 100%.
sage: g = graphs.PetersenGraph()
sage: t = g._gomory_hu_tree()
sage: t = g._gomory_hu_tree(frozenset(g.vertices()))
"""
self._scream_if_not_simple()
from sage.sets.set import Set

# The default capacity of an arc is 1
from sage.rings.real_mpfr import RR
capacity = lambda label: label if label in RR else 1

# Keeping the graph's embedding
pos = False

# Small case, not really a problem ;-)
if self.order() == 1:
return self.copy()

# This is a sign that this is the first call
# to this recursive function
if vertices is None:
# Now is the time to care about positions
pos = self.get_pos()

# if the graph is not connected, returns the union
# of the Gomory-Hu tree of each component
if not self.is_connected():
g = Graph()
for cc in self.connected_components_subgraphs():
g = g.union(cc._gomory_hu_tree(method=method))
g.set_pos(self.get_pos())
return g
# All the vertices is this graph are the "real ones"
vertices = Set(self.vertices())

# There may be many vertices, though only one which is "real"
if len(vertices) == 1:
g = Graph()
g.add_vertex(vertices[0])
g.add_vertices(vertices)
return g

# Take any two vertices
u,v = vertices[0:2]
# Take any two vertices (u,v)
it = vertices.__iter__()
u,v = it.next(),it.next()

# Recovers the following values
# flow is the connectivity between u and v
# edges of a min cut
# sets1, sets2 are the two sides of the edge cut
flow,edges,[set1,set2] = self.edge_cut(u, v, use_edge_labels=True, vertices=True, method=method)
# Compute a uv min-edge-cut.
#
# The graph is split into U,V with u \in U and v\in V.
flow,edges,[U,V] = self.edge_cut(u, v, use_edge_labels=True, vertices=True, method=method)

# One graph for each part of the previous one
g1,g2 = self.subgraph(set1), self.subgraph(set2)

# Adding the fake vertex to each part
g1_v = Set(set2)
g2_v = Set(set1)
g1.add_vertex(g1_v)
g1.add_vertex(g2_v)

# Each part of the graph had many edges going to the other part
# Now that we have a new fake vertex in each part
# we just say that the edges which were in the cut and going
# to the other side are now going to this fake vertex

# We must preserve the labels. They sum.

for e in edges:
x,y = e[0],e[1]
# Assumes x is in g1
if x in g2:
x,y = y,x
# If the edge x-g1_v exists, adds to its label the capacity of arc xy
if g1.has_edge(x, g1_v):
g1.set_edge_label(x, g1_v, g1.edge_label(x, g1_v) + capacity(self.edge_label(x, y)))
else:
# Otherwise, creates it with the good label
g1.add_edge(x, g1_v, capacity(self.edge_label(x, y)))
# Same thing for g2
if g2.has_edge(y, g2_v):
g2.set_edge_label(y, g2_v, g2.edge_label(y, g2_v) + capacity(self.edge_label(x, y)))
else:
g2.add_edge(y, g2_v, capacity(self.edge_label(x, y)))
gU,gV = self.subgraph(U), self.subgraph(V)

# Recursion for the two new graphs... The new "real" vertices are the intersection with
# with the previous set of "real" vertices
g1_tree = g1._gomory_hu_tree(vertices=(vertices & Set(g1.vertices())), method=method)
g2_tree = g2._gomory_hu_tree(vertices=(vertices & Set(g2.vertices())), method=method)
# A fake vertex fU (resp. fV) to represent U (resp. V)
fU = frozenset(U)
fV = frozenset(V)

# Union of the two partial trees ( it is disjoint, but
# disjoint_union does not preserve the name of the vertices )
g = g1_tree.union(g2_tree)
# Each edge (uu,vv) with uu \in U and vv\in V yields:
# - an edge (uu,fV) in gU
# - an edge (vv,fU) in gV
#
# If the same edge is added several times their capacities add up.

# An edge to connect them, with the appropriate label
g.add_edge(next(g1_tree.vertex_iterator()), next(g2_tree.vertex_iterator()), flow)
from sage.rings.real_mpfr import RR
for uu,vv,capacity in edges:
capacity = capacity if capacity in RR else 1

# Assume uu is in gU
if uu in V:
uu,vv = vv,uu

# Create the new edges if necessary
if not gU.has_edge(uu, fV):
gU.add_edge(uu, fV, 0)
if not gV.has_edge(vv, fU):
gV.add_edge(vv, fU, 0)

# update the capacities
gU.set_edge_label(uu, fV, gU.edge_label(uu, fV) + capacity)
gV.set_edge_label(vv, fU, gV.edge_label(vv, fU) + capacity)

# Recursion on each side
gU_tree = gU._gomory_hu_tree(vertices & frozenset(gU), method=method)
gV_tree = gV._gomory_hu_tree(vertices & frozenset(gV), method=method)

if pos:
g.set_pos(pos)
# Union of the two partial trees
g = gU_tree.union(gV_tree)

# An edge to connect them, with the appropriate label
g.add_edge(u, v, flow)

return g

Expand All @@ -6457,6 +6421,8 @@ def gomory_hu_tree(self, method="FF"):
`Wikipedia article on Gomory-Hu tree <http://en.wikipedia.org/wiki/Gomory%E2%80%93Hu_tree>`_.
Note that, in general, a graph admits more than one Gomory-Hu tree.
See also 15.4 (Gomory-Hu trees) from [SchrijverCombOpt]_.
INPUT:
- ``method`` -- There are currently two different
Expand Down Expand Up @@ -6511,8 +6477,29 @@ def gomory_hu_tree(self, method="FF"):
sage: g.edge_connectivity() == min(t.edge_labels())
True
TESTS:
:trac:`16475`::
sage: G = graphs.PetersenGraph()
sage: for u, v in [(0, 1), (0, 4), (0, 5), (1, 2), (1, 6), (3, 4), (5, 7), (5, 8)]:
....: G.set_edge_label(u, v, 2)
sage: T = G.gomory_hu_tree()
sage: from itertools import combinations
sage: for u,v in combinations(G,2):
....: assert T.flow(u,v,use_edge_labels=True) == G.flow(u,v,use_edge_labels=True)
"""
return self._gomory_hu_tree(method=method)
if not self.is_connected():
g = Graph()
for cc in self.connected_components_subgraphs():
g = g.union(cc._gomory_hu_tree(frozenset(cc.vertices()),method=method))
else:
g = self._gomory_hu_tree(frozenset(self.vertices()),method=method)

if self.get_pos() is not None:
g.set_pos(dict(self.get_pos()))
return g

def two_factor_petersen(self):
r"""
Expand Down

0 comments on commit 7fadf1f

Please sign in to comment.