@@ -127,6 +127,8 @@ Functions
127127---------
128128"""
129129
130+ from sage.structure.element cimport parent
131+
130132
131133def is_line_graph (g , certificate = False ):
132134 r """
@@ -263,21 +265,32 @@ def is_line_graph(g, certificate=False):
263265 return True
264266
265267
266- def line_graph(g, labels=True):
268+ def line_graph(g, labels=True, return_labels=False ):
267269 """
268- Return the line graph of the (di)graph ``g``.
270+ Return the line graph of the (di)graph ``g`` (multiedges and loops allowed) .
269271
270272 INPUT:
271273
272274 - ``labels`` -- boolean (default: ``True``); whether edge labels should be
273275 taken in consideration. If ``labels=True``, the vertices of the line graph
274- will be triples ``(u,v,label)``, and pairs of vertices otherwise.
275-
276- The line graph of an undirected graph G is an undirected graph H such that
277- the vertices of H are the edges of G and two vertices e and f of H are
276+ will be triples ``(u,v,label)``, and pairs of vertices otherwise. In case
277+ of multiple edges, the vertices of the line graph will be triples
278+ ``(u,v,an integer)``.
279+
280+ - ``return_labels`` -- boolean (default: ``False``); whether edge labels should
281+ be stored or not. If g has multiple edges and if ``return_labels=True``, the
282+ method returns a list the first element of which is the line-graph of g
283+ and the second element is a dictionary {vertex of the line-graph: former
284+ corresponding edge with its original label}. If ``return_labels=False``,
285+ the method returns only the line-graph.
286+
287+ The line graph of an undirected graph G is an undirected simple graph H such
288+ that the vertices of H are the edges of G and two vertices e and f of H are
278289 adjacent if e and f share a common vertex in G. In other words, an edge in H
279290 represents a path of length 2 in G.
280291
292+ Loops are not adjacent to themselves.
293+
281294 The line graph of a directed graph G is a directed graph H such that the
282295 vertices of H are the edges of G and two vertices e and f of H are adjacent
283296 if e and f share a common vertex in G and the terminal vertex of e is the
@@ -311,7 +324,7 @@ def line_graph(g, labels=True):
311324 (1, 2, None),
312325 (1, 3, None),
313326 (2, 3, None) ]
314- sage: h. am( ) # needs sage. modules
327+ sage: h. am( ) # needs sage. modules
315328 [0 1 1 1 1 0 ]
316329 [1 0 1 1 0 1 ]
317330 [1 1 0 0 1 1 ]
@@ -321,7 +334,7 @@ def line_graph(g, labels=True):
321334 sage: h2 = g. line_graph( labels=False)
322335 sage: h2. vertices( sort=True)
323336 [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3) ]
324- sage: h2. am( ) == h. am( ) # needs sage. modules
337+ sage: h2. am( ) == h. am( ) # needs sage. modules
325338 True
326339 sage: g = DiGraph( [[1..4 ], lambda i,j: i < j])
327340 sage: h = g. line_graph( )
@@ -338,6 +351,40 @@ def line_graph(g, labels=True):
338351 ((1, 3, None), (3, 4, None), None),
339352 ((2, 3, None), (3, 4, None), None) ]
340353
354+ Examples with multiple edges::
355+
356+ sage: L = Graph( [(0,1),(0,1),(1,2) ],multiedges=True) . line_graph( )
357+ sage: L. edges( )
358+ [((0, 1, 0), (0, 1, 1), None), ((0, 1, 1), (1, 2, 2), None),
359+ ((0, 1, 0), (1, 2, 2), None) ]
360+ sage: G = Graph( [(0,1),(0,1,'a'),(0,1,'b'),(0,2),(1,2,'c') ],
361+ .... : multiedges=True)
362+ sage: L = G. line_graph( False,True)
363+ sage: L[0 ]. edges( )
364+ [((0, 1, 1), (0, 1, 2), None), ((0, 1, 0), (0, 1, 2), None),
365+ ((0, 1, 2), (0, 2, 3), None), ((0, 1, 2), (1, 2, 4), None), ((0, 1, 0),
366+ (0, 1, 1), None), ((0, 1, 1), (0, 2, 3), None), ((0, 1, 1),
367+ (1, 2, 4), None), ((0, 1, 0), (0, 2, 3), None), ((0, 1, 0),
368+ (1, 2, 4), None), ((0, 2, 3), (1, 2, 4), None) ]
369+ sage: L[1 ]
370+ {( 0, 1, 0) : ( 0, 1, None) ,
371+ ( 0, 1, 1) : ( 0, 1, 'b') ,
372+ ( 0, 1, 2) : ( 0, 1, 'a') ,
373+ ( 0, 2, 3) : ( 0, 2, None) ,
374+ ( 1, 2, 4) : ( 1, 2, 'c') }
375+ sage: g = DiGraph( [(0,1),(0,1),(1,2) ],multiedges=True)
376+ sage: g. line_graph( ) . edges( )
377+ [((0, 1, 1), (1, 2, 2), None), ((0, 1, 0), (1, 2, 2), None) ]
378+
379+ An example with a loop::
380+
381+ sage: g = Graph( [(0,0),(0,1),(0,2),(1,2) ],multiedges=True,loops=True)
382+ sage: L = g. line_graph( )
383+ sage: L. edges( )
384+ [((0, 0, None), (0, 1, None), None), ((0, 0, None), (0, 2, None), None),
385+ ((0, 1, None), (0, 2, None), None), ((0, 1, None), (1, 2, None), None),
386+ ((0, 2, None), (1, 2, None), None) ]
387+
341388 TESTS:
342389
343390 :issue:`13787`::
@@ -351,17 +398,31 @@ def line_graph(g, labels=True):
351398 """
352399 cdef dict conflicts = {}
353400 cdef list elist = []
401+ cdef dict origlabels_dic = {} # stores original labels of edges in case of multiple edges
402+
403+ multiple = g. has_multiple_edges( )
404+
405+ if multiple:
406+ # As the edges of g are the vertices of its line graph, we need to distinguish between the mutliple edges of g.
407+ # To this aim, we assign to each edge of g an integer label ( between 0 and g. size( ) - 1) and set labels to True
408+ # in order to keep these labels during the construction of the line graph.
409+ labels = True
410+ origlabels_dic = {( u, v, id) : ( u, v, label)
411+ for id, ( u, v, label) in enumerate( g. edge_iterator( )) }
412+ g = parent( g) ( [g, origlabels_dic.keys() ], format='vertices_and_edges', multiedges=True)
354413
355- g. _scream_if_not_simple( )
356414 if g. _directed:
357415 from sage. graphs. digraph import DiGraph
358416 G = DiGraph( )
359417 G. add_vertices( g. edge_iterator( labels=labels))
360418 for v in g:
361419 # Connect appropriate incident edges of the vertex v
362420 G. add_edges(( e, f) for e in g. incoming_edge_iterator( v, labels=labels)
363- for f in g. outgoing_edge_iterator( v, labels=labels))
364- return G
421+ for f in g. outgoing_edge_iterator( v, labels=labels))
422+ if return_labels and multiple:
423+ return [G, origlabels_dic ]
424+ else:
425+ return G
365426
366427 from sage. graphs. graph import Graph
367428 G = Graph( )
@@ -393,7 +454,7 @@ def line_graph(g, labels=True):
393454 elist = []
394455
395456 # Add the edge to the list, according to hashes, as previously
396- for e in g. edge_iterator( v, labels=labels) :
457+ for e in g. edge_iterator( v, labels=labels) : # iterates over the edges incident to v
397458 if hash( e[0 ]) < hash( e[1 ]) :
398459 elist. append( e)
399460 elif hash( e[0 ]) > hash( e[1 ]) :
@@ -402,12 +463,17 @@ def line_graph(g, labels=True):
402463 elist. append( conflicts[e ])
403464
404465 # All pairs of elements in elist are edges of the line graph
466+ # if g has multiple edges, some pairs appear more than once but as G is defined as simple,
467+ # the corresponding edges are not added as multiedges ( as it should be) .
405468 while elist:
406469 x = elist. pop( )
407470 for y in elist:
408471 G. add_edge( x, y)
409472
410- return G
473+ if return_labels and multiple:
474+ return [G, origlabels_dic ]
475+ else:
476+ return G
411477
412478
413479def root_graph( g, verbose=False) :
0 commit comments