All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgrapht.generate.RandomRegularGraphGenerator Maven / Gradle / Ivy

/*
 * (C) Copyright 2018-2021, by Emilio Cruciani and Contributors.
 *
 * JGraphT : a free Java graph-theory library
 *
 * See the CONTRIBUTORS.md file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0, or the
 * GNU Lesser General Public License v2.1 or later
 * which is available at
 * http://www.gnu.org/licenses/old-licenses/lgpl-2.1-standalone.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR LGPL-2.1-or-later
 */
package org.jgrapht.generate;

import org.jgrapht.*;
import org.jgrapht.util.*;

import java.util.*;

/**
 * Generate a random $d$-regular undirected graph with $n$ vertices. A regular graph is a graph
 * where each vertex has the same degree, i.e. the same number of neighbors.
 *
 * 

* The algorithm for the simple case, proposed in [SW99] and extending the one for the non-simple * case [W99], runs in expected $\mathcal{O}(nd^2)$ time. It has been proved in [KV03] to sample * from the space of random d-regular graphs in a way which is asymptotically uniform at random when * $d = \mathcal{O}(n^{1/3 - \epsilon})$. * *

* [KV03] Kim, Jeong Han, and Van H. Vu. "Generating random regular graphs." Proceedings of the * thirty-fifth annual ACM symposium on Theory of computing. ACM, 2003. * * [SW99] Steger, Angelika, and Nicholas C. Wormald. "Generating random regular graphs quickly." * Combinatorics, Probability and Computing 8.4 (1999): 377-396. * * [W99] Wormald, Nicholas C. "Models of random regular graphs." London Mathematical Society Lecture * Note Series (1999): 239-298. * * @author Emilio Cruciani * * @param graph node type * @param graph edge type */ public class RandomRegularGraphGenerator implements GraphGenerator { private final int n; private final int d; private final Random rng; /** * Construct a new RandomRegularGraphGenerator. * * @param n number of nodes * @param d degree of nodes * @throws IllegalArgumentException if number of nodes is negative * @throws IllegalArgumentException if degree is negative * @throws IllegalArgumentException if degree is greater than number of nodes * @throws IllegalArgumentException if the value "n * d" is odd */ public RandomRegularGraphGenerator(int n, int d) { this(n, d, new Random()); } /** * Construct a new RandomRegularGraphGenerator. * * @param n number of nodes * @param d degree of nodes * @param seed seed for the random number generator * @throws IllegalArgumentException if number of nodes is negative * @throws IllegalArgumentException if degree is negative * @throws IllegalArgumentException if degree is greater than number of nodes * @throws IllegalArgumentException if the value "n * d" is odd */ public RandomRegularGraphGenerator(int n, int d, long seed) { this(n, d, new Random(seed)); } /** * Construct a new RandomRegularGraphGenerator. * * @param n number of nodes * @param d degree of nodes * @param rng the random number generator to use * @throws IllegalArgumentException if number of nodes is negative * @throws IllegalArgumentException if degree is negative * @throws IllegalArgumentException if degree is greater than number of nodes * @throws IllegalArgumentException if the value "n * d" is odd */ public RandomRegularGraphGenerator(int n, int d, Random rng) { if (n < 0) { throw new IllegalArgumentException("number of nodes must be non-negative"); } if (d < 0) { throw new IllegalArgumentException("degree of nodes must be non-negative"); } if (d > n) { throw new IllegalArgumentException( "degree of nodes must be smaller than or equal to number of nodes"); } if ((n * d) % 2 != 0) { throw new IllegalArgumentException("value 'n * d' must be even"); } this.n = n; this.d = d; this.rng = rng; } /** * Generate a random regular graph. * * @param target the target graph * @param resultMap the result map * @throws IllegalArgumentException if target is not an undirected graph * @throws IllegalArgumentException if "n == d" and the graph is simple */ @Override public void generateGraph(Graph target, Map resultMap) { if (!target.getType().isUndirected()) { throw new IllegalArgumentException("target graph must be undirected"); } if (target.getType().isSimple()) { // simple case if (n == 0 || d == 0) { // no nodes or zero degree case new EmptyGraphGenerator(n).generateGraph(target); } else if (d == n) { throw new IllegalArgumentException("target graph must be simple if 'n == d'"); } else if (d == n - 1) { // complete case new CompleteGraphGenerator(n).generateGraph(target); } else { // general case generateSimpleRegularGraph(target); } } else { // non-simple case generateNonSimpleRegularGraph(target); } } /* * Auxiliary method to check if there are remaining suitable edges, in the simple regular graph * generator. */ private boolean suitable( Set> edges, Map potentialEdges) { if (potentialEdges.isEmpty()) { return true; } Integer[] keys = potentialEdges.keySet().toArray(new Integer[0]); Arrays.sort(keys); for (int i = 0; i < keys.length; i++) { int s2 = keys[i]; for (int j = 0; j < i; j++) { int s1 = keys[j]; Map.Entry e = new AbstractMap.SimpleImmutableEntry<>(s1, s2); if (!edges.contains(e)) { return true; } } } return false; } /* * Generate simple regular graph */ private void generateSimpleRegularGraph(Graph target) { // integers to vertices List vertices = new ArrayList<>(n); for (int i = 0; i < n; i++) { vertices.add(target.addVertex()); } // set of final edges to add to target graph Set> edges = CollectionUtil.newHashSetWithExpectedSize(n * d); do { List stubs = new ArrayList<>(n * d); for (int i = 0; i < n * d; i++) { stubs.add(i % n); } while (!stubs.isEmpty()) { Map potentialEdges = new HashMap<>(); Collections.shuffle(stubs, rng); for (int i = 0; i < stubs.size() - 1; i += 2) { int s1 = stubs.get(i); int s2 = stubs.get(i + 1); // s1 < s2 has to be true if (s1 > s2) { int temp = s1; s1 = s2; s2 = temp; } Map.Entry edge = new AbstractMap.SimpleImmutableEntry<>(s1, s2); if (s1 != s2 && !edges.contains(edge)) { edges.add(edge); } else { potentialEdges.put(s1, potentialEdges.getOrDefault(s1, 0) + 1); potentialEdges.put(s2, potentialEdges.getOrDefault(s2, 0) + 1); } } if (!suitable(edges, potentialEdges)) { edges.clear(); break; } stubs.clear(); for (Map.Entry e : potentialEdges.entrySet()) { int node = e.getKey(); int potential = e.getValue(); for (int i = 0; i < potential; i++) { stubs.add(node); } } } } while (edges.isEmpty()); // add edges to target for (Map.Entry e : edges) { target.addEdge(vertices.get(e.getKey()), vertices.get(e.getValue())); } } /* * Generate non-simple regular graph. */ private void generateNonSimpleRegularGraph(Graph target) { List vertices = new ArrayList<>(n * d); for (int i = 0; i < n; i++) { V vertex = target.addVertex(); for (int j = 0; j < d; j++) { vertices.add(vertex); } } Collections.shuffle(vertices, rng); for (int i = 0; i < (n * d) / 2; i++) { V u = vertices.get(2 * i); V v = vertices.get(2 * i + 1); target.addEdge(u, v); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy