Skip to content

Commit cd41cee

Browse files
committed
add rooted product of graphs
1 parent 3230f00 commit cd41cee

File tree

2 files changed

+121
-0
lines changed

2 files changed

+121
-0
lines changed

src/sage/graphs/generic_graph.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24266,6 +24266,7 @@ def is_self_complementary(self):
2426624266
from sage.graphs.domination import dominating_set
2426724267
from sage.graphs.domination import greedy_dominating_set
2426824268
from sage.graphs.base.static_dense_graph import connected_subgraph_iterator
24269+
rooted_product = LazyImport('sage.graphs.graph_decompositions.graph_products', 'rooted_product')
2426924270
from sage.graphs.path_enumeration import shortest_simple_paths
2427024271
from sage.graphs.path_enumeration import all_paths
2427124272
from sage.graphs.traversals import lex_BFS

src/sage/graphs/graph_decompositions/graph_products.pyx

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,3 +339,123 @@ def is_cartesian_product(g, certificate=False, relabeling=False):
339339
return factors
340340
else:
341341
return True
342+
343+
344+
def rooted_product(G, H, root=None):
345+
r"""
346+
Return the rooted product of `G` and `H`.
347+
348+
The rooted product of two graphs `G` and `H` is the graph `R` defined as
349+
follows: take a copy of `G` and `|V(G)|` copies of `H`, and for every vertex
350+
`g_i` of `G`, identify `g_i` with the root of the `i`-th copy of `H`.
351+
Mode formally, let `V(G) = \{g_1, g_2, \ldots, g_n\}`,
352+
`V(H) = \{h_1, h_2, \ldots, h_m\}`, and let `h_1` be the root vertex of `H`.
353+
The vertex set `V(R)` is equal to the cartesian product of the sets of
354+
vertices `V(G)` and `V(H)`, that is
355+
`V(R) = \{(g_i, h_j) : g_i \in V(G), h_j \in V(H)\}`. The edge set `E(R)`
356+
is the union of the edges of a copy of `G`, that is
357+
`\{((g_i, h_1), (g_j, h_1)) : (g_i, g_j) \in E(G)\}`, and the edges of the
358+
copies of `H` for every `g_i \in V(G)`, that is
359+
`\{((g_i, h_j), (g_i, h_k)) : (h_j, h_k) \in V(H)\}`.
360+
361+
See :wikipedia:`Rooted_product_of_graphs` for more details.
362+
363+
.. SEEALSO::
364+
365+
- :meth:`~sage.graphs.generic_graph.cartesian_product`
366+
-- return the cartesian product of two graphs
367+
368+
- :mod:`~sage.graphs.graph_decompositions.graph_products`
369+
-- a module on graph products
370+
371+
EXAMPLES:
372+
373+
The rooted product of two trees is a tree::
374+
375+
sage: T1 = graphs.RandomTree(7)
376+
sage: T2 = graphs.RandomTree(8)
377+
sage: T = T1.rooted_product(T2)
378+
sage: T.is_tree()
379+
True
380+
381+
The rooted product of `G` and `H` depends on the selected root in `H`::
382+
383+
sage: G = graphs.CycleGraph(4)
384+
sage: H = graphs.PathGraph(3)
385+
sage: R1 = G.rooted_product(H, root=0)
386+
sage: R2 = G.rooted_product(H, root=1)
387+
sage: R1.is_isomorphic(R2)
388+
False
389+
sage: sorted(R1.degree())
390+
[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]
391+
sage: sorted(R2.degree())
392+
[1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4]
393+
394+
The domination number of the rooted product of any graph `G` and a path of
395+
order 2 is the order of `G`::
396+
397+
sage: G = graphs.RandomGNP(20, .3)
398+
sage: P = graphs.PathGraph(2)
399+
sage: R = G.rooted_product(P)
400+
sage: len(R.dominating_set()) == G.order()
401+
True
402+
sage: G = digraphs.RandomDirectedGNP(20, .3)
403+
sage: P = digraphs.Path(2)
404+
sage: R = G.rooted_product(P)
405+
sage: len(R.dominating_set()) == G.order()
406+
True
407+
408+
The rooted product of two graphs is a subgraph of the cartesian product of
409+
the same two graphs::
410+
411+
sage: G = graphs.RandomGNP(6, .4)
412+
sage: H = graphs.RandomGNP(7, .4)
413+
sage: R = G.rooted_product(H)
414+
sage: C = G.cartesian_product(H)
415+
sage: R.is_subgraph(C, induced=False)
416+
True
417+
418+
Corner cases::
419+
420+
sage: Graph().rooted_product(Graph())
421+
Rooted product of Graph on 0 vertices and Graph on 0 vertices: Graph on 0 vertices
422+
sage: Graph(1).rooted_product(Graph())
423+
Rooted product of Graph on 1 vertex and Graph on 0 vertices: Graph on 0 vertices
424+
sage: Graph().rooted_product(Graph(1))
425+
Rooted product of Graph on 0 vertices and Graph on 1 vertex: Graph on 0 vertices
426+
sage: Graph(1).rooted_product(Graph(1))
427+
Rooted product of Graph on 1 vertex and Graph on 1 vertex: Graph on 1 vertex
428+
429+
TESTS::
430+
431+
sage: Graph().rooted_product(DiGraph())
432+
Traceback (most recent call last):
433+
...
434+
TypeError: the graphs should be both directed or both undirected
435+
"""
436+
G._scream_if_not_simple(allow_loops=True)
437+
if G._directed and H._directed:
438+
from sage.graphs.digraph import DiGraph
439+
R = DiGraph(loops=(G.has_loops() or H.has_loops()))
440+
elif (not G._directed) and (not H._directed):
441+
from sage.graphs.graph import Graph
442+
R = Graph(loops=(G.has_loops() or H.has_loops()))
443+
else:
444+
raise TypeError('the graphs should be both directed or both undirected')
445+
446+
R.name(f'Rooted product of {G} and {H}')
447+
448+
if not G or not H:
449+
return R
450+
if root is None:
451+
root = next(H.vertex_iterator())
452+
elif root not in H:
453+
raise ValueError("the specified root is not a vertex of H")
454+
455+
R.add_vertices((u, x) for u in G for x in H)
456+
for u, v in G.edge_iterator(labels=False):
457+
R.add_edge((u, root), (v, root))
458+
for x, y in H.edge_iterator(labels=False):
459+
R.add_edges(((u, x), (u, y)) for u in G)
460+
461+
return R

0 commit comments

Comments
 (0)