Skip to content

Commit

Permalink
Trac #17893: Incorrect decomposition returned by Graph.treewidth
Browse files Browse the repository at this point in the history
As reported on asksage [1], the function `Graph.treewidth` can return
incorrect tree decompositions.

{{{
sage: graphs.PathGraph(10).treewidth(certificate=True).vertices()
[{2}, {1}, {4}, {8, 9}, {8}, {6}, {0}, {3}, {5}, {7}]
}}}

The computations are actually done right (the width returned is
correct), but my attempts to "simplify" the tree while it is being built
simplified.. a bit too much.

The way it is done now is a bit more correct, though a tad more
ressource-consuming. Nothing important, as the post-processing is
infiinitely cheaper than the actual solving anyway.

{{{
sage: graphs.PathGraph(10).treewidth(certificate=True).vertices()
[{0, 1}, {4, 5}, {1, 2}, {2, 3}, {8, 7}, {8, 9}, {6, 7}, {5, 6}, {3, 4}]
}}}

Nathann

[1] http://ask.sagemath.org/question/26011/treewidth/

URL: http://trac.sagemath.org/17893
Reported by: ncohen
Ticket author(s): Nathann Cohen
Reviewer(s): Frédéric Chapoton
  • Loading branch information
Release Manager authored and vbraun committed Mar 6, 2015
2 parents 5028a8d + d3d967d commit 56c8ae9
Showing 1 changed file with 29 additions and 24 deletions.
53 changes: 29 additions & 24 deletions src/sage/graphs/graph.py
Expand Up @@ -2702,7 +2702,7 @@ def treewidth(self,k=None,certificate=False):
sage: graphs.PetersenGraph().treewidth()
4
sage: graphs.PetersenGraph().treewidth(certificate=True)
Graph on 7 vertices
Graph on 6 vertices
The treewidth of a 2d grid is its smallest side::
Expand All @@ -2720,7 +2720,7 @@ def treewidth(self,k=None,certificate=False):
sage: g.treewidth()
1
sage: g.treewidth(certificate=True)
Graph on 6 vertices
Graph on 4 vertices
sage: g.treewidth(2)
True
sage: g.treewidth(1)
Expand All @@ -2738,7 +2738,19 @@ def treewidth(self,k=None,certificate=False):
sage: graphs.PetersenGraph().treewidth(k=3,certificate=True)
False
sage: graphs.PetersenGraph().treewidth(k=4,certificate=True)
Graph on 7 vertices
Graph on 6 vertices
TESTS:
All edges do appear (:trac:`17893`)::
sage: from itertools import combinations
sage: g = graphs.PathGraph(10)
sage: td = g.treewidth(certificate=True)
sage: for bag in td:
....: g.delete_edges(list(combinations(bag,2)))
sage: g.size()
0
"""
from sage.misc.cachefunc import cached_function
from sage.sets.set import Set
Expand Down Expand Up @@ -2810,7 +2822,8 @@ def rec(cut,cc):

if certificate:
sons.extend(son)
sons.append((cut,reduced_cut))
sons.append((cut,cutv))
sons.append((cutv,reduced_cut))

# Weird Python syntax which is useful once in a lifetime : if break
# was never called in the loop above, we return "sons".
Expand All @@ -2836,26 +2849,18 @@ def rec(cut,cc):
G = Graph()
G.add_edges([(Set(x),Set(y)) for x,y in TD])

# The Tree-Decomposition contains a lot of useless nodes that we now remove.
prune_list = G.vertices()

for v in prune_list:
# We remove any vertex of degree 1 whose corresponding set is contained
# in the set represented by its unique neighbor.
if G.degree(v)==1:
v1 = G.neighbors(v)[0]
if v.issubset(v1):
G.delete_vertex(v)
prune_list.append(v1)

# We remove a vertex v with two neighbors v1,v2 if v1 is a subset of v
# and v is a subset of v2
elif G.degree(v) == 2:
v1,v2 = G.neighbors(v)
if ((v1.issubset(v) and v.issubset(v2)) or
(v1.issuperset(v) and v.issuperset(v2))):
G.add_edge(v1,v2)
G.delete_vertex(v)
# The Tree-Decomposition contains a lot of useless nodes.
#
# We merge all edges between two sets S,S' where S is a subset of S'
changed = True
while changed:
changed=False
for v in G.vertices():
for u in G.neighbors(v):
if u.issuperset(v):
G.merge_vertices([u,v]) # the new vertex is named 'u'
changed = True
break

return G

Expand Down

0 comments on commit 56c8ae9

Please sign in to comment.