From 8ccaa0f8cfb318861d0f959836d1cfb52a2a6f11 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Wed, 8 May 2024 20:00:57 +0200 Subject: [PATCH 1/4] random cograph generator --- src/sage/graphs/generators/random.py | 91 ++++++++++++++++++++++++++++ src/sage/graphs/graph_generators.py | 1 + 2 files changed, 92 insertions(+) diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index 9459124a0fe..e741087a89a 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -18,6 +18,7 @@ from sage.graphs.graph import Graph from sage.misc.randstate import current_randstate from sage.misc.randstate import set_random_seed +from sage.misc.prandom import getrandbits from sage.misc.prandom import random from sage.misc.prandom import randint @@ -659,6 +660,96 @@ def RandomBoundedToleranceGraph(n, seed=None): return ToleranceGraph(tolrep) +def RandomCoGraph(n, seed=None): + r""" + Return a random cograph of order `n`. + + A cograph is a `P_4`-free graph, that is a graph without induced + path of order 4. Any cograph may be constructed, starting from + the single vertex graph, by a sequence of + :meth:`sage.graphs.graph.Graph.join` and + :meth:`sage.graphs.graph.Graph.disjoint_union` operations. + See the :wikipedia:`Cograph` for more details. + + ALGORITHM: + + This method proceeds as follows: to build a random cograph of order `n > 1`, + it first build a random cograph `A` of order `r` and a random cograph `B` of + order `n - r`. Then it randomly selects to apply + :meth:`sage.graphs.graph.Graph.join` or + :meth:`sage.graphs.graph.Graph.disjoint_union` operation on `A` and `B` to + get `G`. + + In practice, we use a stack to avoid the recursive calls. + + INPUT: + + - ``n`` -- integer; the number of vertices in the random cograph + + - ``seed`` -- a ``random.Random`` seed or a Python ``int`` for the random + number generator (default: ``None``) + + EXAMPLES:: + + sage: G = graphs.RandomCoGraph(17) + sage: G.is_cograph() + True + + TESTS:: + + sage: graphs.RandomCoGraph(0) + Traceback (most recent call last): + ... + ValueError: a cograph has at least one vertex + """ + if n < 1: + raise ValueError("a cograph has at least one vertex") + if n == 1: + return Graph(1, name="Random cograph") + if seed is None: + seed = int(current_randstate().long_seed() % sys.maxsize) + + g_one = Graph(1) + # We need n - 1 bits for the random choices of operations + bits = getrandbits(n - 1) + + i = randint(1, n - 1) + stack = [[bits % 2, i, n - i, 0]] + bits >>= 1 + while stack: + op, left, right, parent = stack[-1] + if not isinstance(left, Graph): + # We build a cograph of order left + if left == 1: + left = stack[-1][1] = g_one + else: + i = randint(1, left - 1) + stack.append([bits % 2, i, left - i, 1]) + bits >>= 1 + continue + if not isinstance(right, Graph): + # We build a cograph of order right + if right == 1: + right = stack[-1][2] = g_one + else: + i = randint(1, right - 1) + stack.append([bits % 2, i, right - i, 2]) + bits >>= 1 + continue + + # We combine the two graphs and store the result in parent + stack.pop() + if op: + G = left.join(right, labels="integers", immutable=False) + else: + G = left.disjoint_union(right, labels="integers", immutable=False) + if stack: + stack[-1][parent] = G + + G.name("Random cograph") + return G + + def RandomGNM(n, m, dense=False, seed=None): """ Returns a graph randomly picked out of all graphs on n vertices diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index 5a09c617ba2..c6c2a8190d8 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -2755,6 +2755,7 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None RandomBlockGraph = staticmethod(random.RandomBlockGraph) RandomBoundedToleranceGraph = staticmethod(random.RandomBoundedToleranceGraph) RandomChordalGraph = staticmethod(random.RandomChordalGraph) + RandomCoGraph = staticmethod(random.RandomCoGraph) RandomGNM = staticmethod(random.RandomGNM) RandomGNP = staticmethod(random.RandomGNP) RandomHolmeKim = staticmethod(random.RandomHolmeKim) From 64630560cd272bd6686f30fe3e54260824f7706d Mon Sep 17 00:00:00 2001 From: dcoudert Date: Wed, 8 May 2024 20:13:12 +0200 Subject: [PATCH 2/4] fix lint --- src/sage/graphs/generators/random.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index e741087a89a..134f84d9f74 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -723,16 +723,16 @@ def RandomCoGraph(n, seed=None): if left == 1: left = stack[-1][1] = g_one else: - i = randint(1, left - 1) + i = randint(1, left - 1) stack.append([bits % 2, i, left - i, 1]) bits >>= 1 continue - if not isinstance(right, Graph): + if not isinstance(right, Graph): # We build a cograph of order right if right == 1: right = stack[-1][2] = g_one else: - i = randint(1, right - 1) + i = randint(1, right - 1) stack.append([bits % 2, i, right - i, 2]) bits >>= 1 continue From 47f8a54f8a43c729fe3f9fc62558d58b1336336b Mon Sep 17 00:00:00 2001 From: dcoudert Date: Wed, 8 May 2024 21:22:15 +0200 Subject: [PATCH 3/4] fix documentation --- src/sage/graphs/generators/random.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index 134f84d9f74..4685ff6bf1f 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -664,11 +664,10 @@ def RandomCoGraph(n, seed=None): r""" Return a random cograph of order `n`. - A cograph is a `P_4`-free graph, that is a graph without induced - path of order 4. Any cograph may be constructed, starting from - the single vertex graph, by a sequence of - :meth:`sage.graphs.graph.Graph.join` and - :meth:`sage.graphs.graph.Graph.disjoint_union` operations. + A cograph is a `P_4`-free graph, that is a graph without induced path of + order 4. Any cograph may be constructed, starting from the single vertex + graph, by a sequence of :meth:`sage.graphs.graph.Graph.join` and + :meth:`sage.graphs.generic_graph.GenericGraph.disjoint_union` operations. See the :wikipedia:`Cograph` for more details. ALGORITHM: @@ -677,8 +676,8 @@ def RandomCoGraph(n, seed=None): it first build a random cograph `A` of order `r` and a random cograph `B` of order `n - r`. Then it randomly selects to apply :meth:`sage.graphs.graph.Graph.join` or - :meth:`sage.graphs.graph.Graph.disjoint_union` operation on `A` and `B` to - get `G`. + :meth:`sage.graphs.generic_graph.GenericGraph.disjoint_union` operation on + `A` and `B` to get `G`. In practice, we use a stack to avoid the recursive calls. From 2bc741ff9241badf46842137490e43236ca6b0c3 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Wed, 8 May 2024 22:50:01 +0200 Subject: [PATCH 4/4] the complement of a cograph is a cograph --- src/sage/graphs/generators/random.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index 4685ff6bf1f..2077691bb99 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -693,6 +693,8 @@ def RandomCoGraph(n, seed=None): sage: G = graphs.RandomCoGraph(17) sage: G.is_cograph() True + sage: G.complement().is_cograph() + True TESTS::