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

Created functions to generate random k-tree and partial k-tree graphs #36587

Merged
merged 17 commits into from
Feb 25, 2024
Merged
Show file tree
Hide file tree
Changes from 14 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
189 changes: 189 additions & 0 deletions src/sage/graphs/generators/random.py
Original file line number Diff line number Diff line change
Expand Up @@ -1459,6 +1459,195 @@ def RandomTreePowerlaw(n, gamma=3, tries=1000, seed=None):
return False


def RandomKTree(n, k, seed=None):
r"""
Return a random `k`-tree on `n` nodes numbered `0` through `n-1`.

ALGORITHM:

The algorithm first generates a complete graph on `k + 1` vertices.
Vertices are subsequently generated by randomly choosing one of the
existing cliques in the graph, and creating a new clique by replacing
one of the vertices in the selected clique with a newly created one.

INPUT:

- ``n`` -- number of vertices in the `k`-tree

- ``k`` -- within a clique each vertex is connected to `k` vertices. `k`
also corresponds to the treewidth of the `k`-tree

- ``seed`` -- a ``random.Random`` seed or a Python ``int`` for the random
number generator (default: ``None``)

TESTS::

sage: g=graphs.RandomKTree(50,5)
damianbasso marked this conversation as resolved.
Show resolved Hide resolved
sage: g.size()
235
sage: g.order()
50
sage: g.treewidth()
5
sage: graphs.RandomKTree(-5, 5)
Traceback (most recent call last):
...
ValueError: n must not be negative
sage: graphs.RandomKTree(5, -5)
Traceback (most recent call last):
...
ValueError: k must not be negative
sage: graphs.RandomKTree(2, 5)
Traceback (most recent call last):
...
ValueError: n must be greater than k
sage: G = graphs.RandomKTree(50, 0)
sage: G.treewidth()
0

EXAMPLES::

sage: G = graphs.RandomKTree(50, 5)
sage: G.treewidth()
5
sage: G.show() # not tested
"""
if n < 0:
raise ValueError("n must not be negative")

if k < 0:
raise ValueError("k must not be negative")

# A graph with treewidth 0 has no edges
if k == 0:
g = Graph(n, name=f"Random 0-tree")
return g

if n < k + 1:
damianbasso marked this conversation as resolved.
Show resolved Hide resolved
raise ValueError("n must be greater than k")

if seed is not None:
set_random_seed(seed)

damianbasso marked this conversation as resolved.
Show resolved Hide resolved
g = Graph(name=f"Random {k}-tree")
g.add_clique(list(range(k + 1)))

cliques = [list(range(k+1))]

# Randomly choose a row, and copy 1 of the cliques
# One of those vertices is then replaced with a new vertex
for newVertex in range(k + 1, n):
copiedClique = cliques[randint(0, len(cliques)-1)].copy()
copiedClique[randint(0, k)] = newVertex
cliques.append(copiedClique)
for u in copiedClique:
if u != newVertex:
g.add_edge(u, newVertex)
return g


def RandomPartialKTree(n, k, x, seed=None):
r"""
Return a random partial `k`-tree on `n` nodes.

A partial `k`-tree is defined as a subgraph of a `k`-tree. This can also be
described as a graph with treewidth at most `k`.

INPUT:

- ``n`` -- number of vertices in the `k`-tree

- ``k`` -- within a clique each vertex is connected to `k` vertices. `k`
also corresponds to the treewidth of the `k`-tree

- ``x`` -- how many edges are deleted from the `k`-tree

- ``seed`` -- a ``random.Random`` seed or a Python ``int`` for the random
number generator (default: ``None``)

TESTS::

sage: g=graphs.RandomPartialKTree(50,5,2)
sage: g.order()
50
sage: g.size()
233
sage: g.treewidth()
5
sage: graphs.RandomPartialKTree(-5, 5, 2)
Traceback (most recent call last):
...
ValueError: n must not be negative
sage: graphs.RandomPartialKTree(5, -5, 2)
Traceback (most recent call last):
...
ValueError: k must not be negative
sage: G = graphs.RandomPartialKTree(2, 5, 2)
Traceback (most recent call last):
...
ValueError: n must be greater than k
sage: G = graphs.RandomPartialKTree(5, 2, 100)
Traceback (most recent call last):
...
ValueError: x must be less than the number of edges in the `k`-tree with `n` nodes
sage: G = graphs.RandomPartialKTree(50, 0, 0)
sage: G.treewidth()
0
sage: G = graphs.RandomPartialKTree(5, 2, 7)
sage: G.treewidth()
0
sage :g.size()
damianbasso marked this conversation as resolved.
Show resolved Hide resolved
0

EXAMPLES::

sage: G = graphs.RandomPartialKTree(50,5,2)
sage: G.treewidth()
5
sage: G.show() # not tested
"""
if n < 0:
raise ValueError("n must not be negative")

if k < 0:
raise ValueError("k must not be negative")

# A graph with treewidth 0 has no edges
if k == 0:
g = Graph(n, name=f"Random partial 0-tree")
return g

if n < k + 1:
raise ValueError("n must be greater than k")

if seed is not None:
set_random_seed(seed)

# This formula calculates how many edges are in a `k`-tree with `n` nodes
edgesInKTree = (k ^ 2 + k) / 2 + (n - k - 1) * k

# Check that x doesn't delete too many edges
if x > edgesInKTree:
raise ValueError("x must be less than the number of edges in the `k`-tree with `n` nodes")

# The graph will have no edges
if x == edgesInKTree:
g = Graph(n, name=f"Random partial {k}-tree")
return g

g = RandomKTree(n, k, seed)

from sage.misc.prandom import shuffle

edges = list(g.edges())
# Deletes x random edges from the graph
shuffle(edges)
g.delete_edges(edges[:x])

g.name(f"Random partial {k}-tree")
return g
damianbasso marked this conversation as resolved.
Show resolved Hide resolved


def RandomRegular(d, n, seed=None):
r"""
Return a random `d`-regular graph on `n` vertices, or ``False`` on failure.
Expand Down
4 changes: 4 additions & 0 deletions src/sage/graphs/graph_generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,8 @@ def wrap_name(x):
"RandomHolmeKim",
"RandomChordalGraph",
"RandomIntervalGraph",
"RandomKTree",
"RandomPartialKTree",
"RandomLobster",
"RandomNewmanWattsStrogatz",
"RandomRegular",
Expand Down Expand Up @@ -2755,6 +2757,8 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None
RandomNewmanWattsStrogatz = staticmethod(random.RandomNewmanWattsStrogatz)
RandomRegular = staticmethod(random.RandomRegular)
RandomShell = staticmethod(random.RandomShell)
RandomKTree = staticmethod(random.RandomKTree)
RandomPartialKTree = staticmethod(random.RandomPartialKTree)
RandomToleranceGraph = staticmethod(random.RandomToleranceGraph)
RandomTreePowerlaw = staticmethod(random.RandomTreePowerlaw)
RandomTree = staticmethod(random.RandomTree)
Expand Down