Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add rooted product of graphs #35824

Merged
merged 1 commit into from
Jul 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/sage/graphs/generic_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -24266,6 +24266,7 @@ def is_self_complementary(self):
from sage.graphs.domination import dominating_set
from sage.graphs.domination import greedy_dominating_set
from sage.graphs.base.static_dense_graph import connected_subgraph_iterator
rooted_product = LazyImport('sage.graphs.graph_decompositions.graph_products', 'rooted_product')
from sage.graphs.path_enumeration import shortest_simple_paths
from sage.graphs.path_enumeration import all_paths
from sage.graphs.traversals import lex_BFS
Expand Down
120 changes: 120 additions & 0 deletions src/sage/graphs/graph_decompositions/graph_products.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -339,3 +339,123 @@ def is_cartesian_product(g, certificate=False, relabeling=False):
return factors
else:
return True


def rooted_product(G, H, root=None):
r"""
Return the rooted product of `G` and `H`.

The rooted product of two graphs `G` and `H` is the graph `R` defined as
follows: take a copy of `G` and `|V(G)|` copies of `H`, and for every vertex
`g_i` of `G`, identify `g_i` with the root of the `i`-th copy of `H`.
Mode formally, let `V(G) = \{g_1, g_2, \ldots, g_n\}`,
`V(H) = \{h_1, h_2, \ldots, h_m\}`, and let `h_1` be the root vertex of `H`.
The vertex set `V(R)` is equal to the cartesian product of the sets of
vertices `V(G)` and `V(H)`, that is
`V(R) = \{(g_i, h_j) : g_i \in V(G), h_j \in V(H)\}`. The edge set `E(R)`
is the union of the edges of a copy of `G`, that is
`\{((g_i, h_1), (g_j, h_1)) : (g_i, g_j) \in E(G)\}`, and the edges of the
copies of `H` for every `g_i \in V(G)`, that is
`\{((g_i, h_j), (g_i, h_k)) : (h_j, h_k) \in V(H)\}`.

See :wikipedia:`Rooted_product_of_graphs` for more details.

.. SEEALSO::

- :meth:`~sage.graphs.generic_graph.cartesian_product`
-- return the cartesian product of two graphs

- :mod:`~sage.graphs.graph_decompositions.graph_products`
-- a module on graph products

EXAMPLES:

The rooted product of two trees is a tree::

sage: T1 = graphs.RandomTree(7)
sage: T2 = graphs.RandomTree(8)
sage: T = T1.rooted_product(T2)
sage: T.is_tree()
True

The rooted product of `G` and `H` depends on the selected root in `H`::

sage: G = graphs.CycleGraph(4)
sage: H = graphs.PathGraph(3)
sage: R1 = G.rooted_product(H, root=0)
sage: R2 = G.rooted_product(H, root=1)
sage: R1.is_isomorphic(R2)
False
sage: sorted(R1.degree())
[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]
sage: sorted(R2.degree())
[1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4]

The domination number of the rooted product of any graph `G` and a path of
order 2 is the order of `G`::

sage: G = graphs.RandomGNP(20, .3)
sage: P = graphs.PathGraph(2)
sage: R = G.rooted_product(P)
sage: len(R.dominating_set()) == G.order()
True
sage: G = digraphs.RandomDirectedGNP(20, .3)
sage: P = digraphs.Path(2)
sage: R = G.rooted_product(P)
sage: len(R.dominating_set()) == G.order()
True

The rooted product of two graphs is a subgraph of the cartesian product of
the same two graphs::

sage: G = graphs.RandomGNP(6, .4)
sage: H = graphs.RandomGNP(7, .4)
sage: R = G.rooted_product(H)
sage: C = G.cartesian_product(H)
sage: R.is_subgraph(C, induced=False)
True

Corner cases::

sage: Graph().rooted_product(Graph())
Rooted product of Graph on 0 vertices and Graph on 0 vertices: Graph on 0 vertices
sage: Graph(1).rooted_product(Graph())
Rooted product of Graph on 1 vertex and Graph on 0 vertices: Graph on 0 vertices
sage: Graph().rooted_product(Graph(1))
Rooted product of Graph on 0 vertices and Graph on 1 vertex: Graph on 0 vertices
sage: Graph(1).rooted_product(Graph(1))
Rooted product of Graph on 1 vertex and Graph on 1 vertex: Graph on 1 vertex

TESTS::

sage: Graph().rooted_product(DiGraph())
Traceback (most recent call last):
...
TypeError: the graphs should be both directed or both undirected
"""
G._scream_if_not_simple(allow_loops=True)
if G._directed and H._directed:
from sage.graphs.digraph import DiGraph
R = DiGraph(loops=(G.has_loops() or H.has_loops()))
elif (not G._directed) and (not H._directed):
from sage.graphs.graph import Graph
R = Graph(loops=(G.has_loops() or H.has_loops()))
else:
raise TypeError('the graphs should be both directed or both undirected')

R.name(f'Rooted product of {G} and {H}')

if not G or not H:
return R
if root is None:
root = next(H.vertex_iterator())
elif root not in H:
raise ValueError("the specified root is not a vertex of H")

R.add_vertices((u, x) for u in G for x in H)
for u, v in G.edge_iterator(labels=False):
R.add_edge((u, root), (v, root))
for x, y in H.edge_iterator(labels=False):
R.add_edges(((u, x), (u, y)) for u in G)

return R