# HG changeset patch
# User Nathann Cohen
# Date 1358334072 3600
# Node ID 607ad0a92935883746c9197d57919dd251848ac1
# Parent ef19ff1169d9f44ce696b467c65421494040b22c
Compute the root graph of a graph  move Graph.is_line_graph and GenericGraph.line_graph to sage.graphs.line_graph
diff git a/sage/graphs/generic_graph.py b/sage/graphs/generic_graph.py
 a/sage/graphs/generic_graph.py
+++ b/sage/graphs/generic_graph.py
@@ 12902,20 +12902,20 @@
def complement(self):
"""
Returns the complement of the (di)graph.

+
The complement of a graph has the same vertices, but exactly those
edges that are not in the original graph. This is not well defined
for graphs with multiple edges.

 EXAMPLES::

+
+ EXAMPLES::
+
sage: P = graphs.PetersenGraph()
sage: P.plot() # long time
sage: PC = P.complement()
sage: PC.plot() # long time

 ::

+
+ ::
+
sage: graphs.TetrahedralGraph().complement().size()
0
sage: graphs.CycleGraph(4).complement().edges()
@@ 12941,145 +12941,6 @@
G.add_edge(u,v)
return G
 def line_graph(self, labels=True):
 """
 Returns the line graph of the (di)graph.

 INPUT:

  ``labels`` (boolean)  whether edge labels should be taken in
 consideration. If ``labels=True``, the vertices of the line graph will
 be triples ``(u,v,label)``, and pairs of vertices otherwise.

 This is set to ``True`` by default.

 The line graph of an undirected graph G is an undirected graph H
 such that the vertices of H are the edges of G and two vertices e
 and f of H are adjacent if e and f share a common vertex in G. In
 other words, an edge in H represents a path of length 2 in G.

 The line graph of a directed graph G is a directed graph H such
 that the vertices of H are the edges of G and two vertices e and f
 of H are adjacent if e and f share a common vertex in G and the
 terminal vertex of e is the initial vertex of f. In other words, an
 edge in H represents a (directed) path of length 2 in G.

 .. NOTE::

 As a :class:`Graph` object only accepts hashable objects as vertices
 (and as the vertices of the line graph are the edges of the graph),
 this code will fail if edge labels are not hashable. You can also
 set the argument ``labels=False`` to ignore labels.

 EXAMPLES::

 sage: g = graphs.CompleteGraph(4)
 sage: h = g.line_graph()
 sage: h.vertices()
 [(0, 1, None),
 (0, 2, None),
 (0, 3, None),
 (1, 2, None),
 (1, 3, None),
 (2, 3, None)]
 sage: h.am()
 [0 1 1 1 1 0]
 [1 0 1 1 0 1]
 [1 1 0 0 1 1]
 [1 1 0 0 1 1]
 [1 0 1 1 0 1]
 [0 1 1 1 1 0]
 sage: h2 = g.line_graph(labels=False)
 sage: h2.vertices()
 [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
 sage: h2.am() == h.am()
 True
 sage: g = DiGraph([[1..4],lambda i,j: i hash(e[1]):
 elist.append((e[1],e[0])+e[2:])
 else:
 # Settle the conflict arbitrarily
 conflicts[e] = e
 conflicts[(e[1],e[0])+e[2:]] = e
 elist.append(e)

 G.add_vertices(elist)

 # 2) adjacencies in the line graph
 for v in self:
 elist = []

 # Add the edge to the list, according to hashes, as previously
 for e in self.edge_iterator(v, labels=labels):
 if hash(e[0]) < hash(e[1]):
 elist.append(e)
 elif hash(e[0]) > hash(e[1]):
 elist.append((e[1],e[0])+e[2:])
 else:
 elist.append(conflicts[e])

 # Alls pairs of elements in elist are edges of the
 # line graph
 while elist:
 x = elist.pop()
 for y in elist:
 G.add_edge(x,y)

 return G

def to_simple(self):
"""
Returns a simple version of itself (i.e., undirected and loops and
@@ 13109,23 +12970,21 @@
def disjoint_union(self, other, verbose_relabel=True):
"""
Returns the disjoint union of self and other.

+
If the graphs have common vertices, the vertices will be renamed to
form disjoint sets.

 INPUT:


+
+ INPUT:
+
 ``verbose_relabel``  (defaults to True) If True
and the graphs have common vertices, then each vertex v in the
first graph will be changed to '0,v' and each vertex u in the
second graph will be changed to '1,u'. If False, the vertices of
the first graph and the second graph will be relabeled with
consecutive integers.


 EXAMPLES::

+
+ EXAMPLES::
+
sage: G = graphs.CycleGraph(3)
sage: H = graphs.CycleGraph(4)
sage: J = G.disjoint_union(H); J
@@ 16855,6 +16714,10 @@
GenericGraph.distances_distribution = types.MethodType(sage.graphs.distances_all_pairs.distances_distribution, None, GenericGraph)
GenericGraph.wiener_index = types.MethodType(sage.graphs.distances_all_pairs.wiener_index, None, GenericGraph)
+# From Python modules
+import sage.graphs.line_graph
+GenericGraph.line_graph = sage.graphs.line_graph.line_graph
+
def tachyon_vertex_plot(g, bgcolor=(1,1,1),
vertex_colors=None,
vertex_size=0.06,
diff git a/sage/graphs/graph.py b/sage/graphs/graph.py
 a/sage/graphs/graph.py
+++ b/sage/graphs/graph.py
@@ 1839,57 +1839,6 @@
return True
 def is_line_graph(self, certificate = False):
 r"""
 Tests wether the graph is a line graph.

 INPUT:

  ``certificate`` (boolean)  whether to return a certificate
 when the graph is *not* a line graph. When ``certificate``
 is set to ``True``, and if the graph is not a line graph,
 the method returns a subgraph isomorphic to one of the 9
 forbidden induced subgraphs of a line graph (instead of the
 usual ``False``)

 .. TODO::

 This methods sequentially tests each of the forbidden subgraphs,
 which is a very slow method. There exist much better algorithms,
 including those which are actually able to return a graph whose line
 graph is isomorphic to the given graph.

 EXAMPLES:

 A complete graph is always the line graph of a star::

 sage: graphs.CompleteGraph(5).is_line_graph()
 True

 The Petersen Graph not being clawfree, it is not a line
 graph:

 sage: graphs.PetersenGraph().is_line_graph()
 False

 This is indeed the subgraph returned::

 sage: C = graphs.PetersenGraph().is_line_graph(certificate = True)
 sage: C.is_isomorphic(graphs.ClawGraph())
 True
 """
 from sage.graphs.graph_generators import graphs

 for g in graphs.line_graph_forbidden_subgraphs():
 h = self.subgraph_search(g, induced = True)
 if h is not None:
 if certificate:
 return h
 else:
 return False

 return True

def is_bipartite(self, certificate = False):
"""
Returns ``True`` if graph `G` is bipartite, ``False`` if not.
@@ 1967,7 +1916,7 @@
return True, color
else:
return True

+
def is_triangle_free(self, algorithm='bitset'):
r"""
Returns whether ``self`` is trianglefree
@@ 5840,6 +5789,10 @@
import sage.graphs.graph_decompositions.graph_products
Graph.is_cartesian_product = types.MethodType(sage.graphs.graph_decompositions.graph_products.is_cartesian_product, None, Graph)
+# From Python modules
+import sage.graphs.line_graph
+Graph.is_line_graph = sage.graphs.line_graph.is_line_graph
+
def compare_edges(x, y):
"""
This function has been deprecated.
diff git a/sage/graphs/line_graph.py b/sage/graphs/line_graph.py
 a/sage/graphs/line_graph.py
+++ b/sage/graphs/line_graph.py
@@ 15,9 +15,9 @@
Author:
 Nathann Cohen (012013), while listening to Nina Simone *"I wish I
 knew how it would feel to be free"*. Crazy good song. And *"Prendre
 ta douleur"*, too.
+ Nathann Cohen (012013), :meth:`root_graph` method and module documentation.
+ Written while listening to Nina Simone *"I wish I knew how it would feel to be
+ free"*. Crazy good song. And *"Prendre ta douleur"*, too.
Definition

@@ 149,6 +149,195 @@

"""
+def is_line_graph(g, certificate = False):
+ r"""
+ Tests wether the graph is a line graph.
+
+ INPUT:
+
+  ``certificate`` (boolean)  whether to return a certificate when the
+ graph is *not* a line graph. When ``certificate`` is set to ``True``, and
+ if the graph is not a line graph, the method returns a subgraph isomorphic
+ to one of the 9 forbidden induced subgraphs of a line graph (instead of
+ the usual ``False``)
+
+ .. TODO::
+
+ This methods sequentially tests each of the forbidden subgraphs, which
+ is a very slow method. There exist much better algorithms, including
+ those which are actually able to return a graph whose line graph is
+ isomorphic to the given graph.
+
+ EXAMPLES:
+
+ A complete graph is always the line graph of a star::
+
+ sage: graphs.CompleteGraph(5).is_line_graph()
+ True
+
+ The Petersen Graph not being clawfree, it is not a line
+ graph:
+
+ sage: graphs.PetersenGraph().is_line_graph()
+ False
+
+ This is indeed the subgraph returned::
+
+ sage: C = graphs.PetersenGraph().is_line_graph(certificate = True)
+ sage: C.is_isomorphic(graphs.ClawGraph())
+ True
+ """
+ from sage.graphs.graph_generators import graphs
+
+ for fg in graphs.line_graph_forbidden_subgraphs():
+ h = g.subgraph_search(fg, induced = True)
+ if h is not None:
+ if certificate:
+ return h
+ else:
+ return False
+
+ return True
+
+def line_graph(self, labels=True):
+ """
+ Returns the line graph of the (di)graph.
+
+ INPUT:
+
+  ``labels`` (boolean)  whether edge labels should be taken in
+ consideration. If ``labels=True``, the vertices of the line graph will be
+ triples ``(u,v,label)``, and pairs of vertices otherwise.
+
+ This is set to ``True`` by default.
+
+ The line graph of an undirected graph G is an undirected graph H such that
+ the vertices of H are the edges of G and two vertices e and f of H are
+ adjacent if e and f share a common vertex in G. In other words, an edge in H
+ represents a path of length 2 in G.
+
+ The line graph of a directed graph G is a directed graph H such that the
+ vertices of H are the edges of G and two vertices e and f of H are adjacent
+ if e and f share a common vertex in G and the terminal vertex of e is the
+ initial vertex of f. In other words, an edge in H represents a (directed)
+ path of length 2 in G.
+
+ .. NOTE::
+
+ As a :class:`Graph` object only accepts hashable objects as vertices
+ (and as the vertices of the line graph are the edges of the graph), this
+ code will fail if edge labels are not hashable. You can also set the
+ argument ``labels=False`` to ignore labels.
+
+ EXAMPLES::
+
+ sage: g = graphs.CompleteGraph(4)
+ sage: h = g.line_graph()
+ sage: h.vertices()
+ [(0, 1, None),
+ (0, 2, None),
+ (0, 3, None),
+ (1, 2, None),
+ (1, 3, None),
+ (2, 3, None)]
+ sage: h.am()
+ [0 1 1 1 1 0]
+ [1 0 1 1 0 1]
+ [1 1 0 0 1 1]
+ [1 1 0 0 1 1]
+ [1 0 1 1 0 1]
+ [0 1 1 1 1 0]
+ sage: h2 = g.line_graph(labels=False)
+ sage: h2.vertices()
+ [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
+ sage: h2.am() == h.am()
+ True
+ sage: g = DiGraph([[1..4],lambda i,j: i hash(e[1]):
+ elist.append((e[1],e[0])+e[2:])
+ else:
+ # Settle the conflict arbitrarily
+ conflicts[e] = e
+ conflicts[(e[1],e[0])+e[2:]] = e
+ elist.append(e)
+
+ G.add_vertices(elist)
+
+ # 2) adjacencies in the line graph
+ for v in self:
+ elist = []
+
+ # Add the edge to the list, according to hashes, as previously
+ for e in self.edge_iterator(v, labels=labels):
+ if hash(e[0]) < hash(e[1]):
+ elist.append(e)
+ elif hash(e[0]) > hash(e[1]):
+ elist.append((e[1],e[0])+e[2:])
+ else:
+ elist.append(conflicts[e])
+
+ # Alls pairs of elements in elist are edges of the
+ # line graph
+ while elist:
+ x = elist.pop()
+ for y in elist:
+ G.add_edge(x,y)
+
+ return G
+
def root_graph(g, verbose = False):
r"""
Computes the root graph corresponding to the given graph