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

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

The newest version!
/*
 * (C) Copyright 2005-2023, by Assaf Lehr, Dimitrios Michail 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 java.util.*;

/**
 * Create a random graph based on the $G(n, M)$ Erdős–Rényi model. See the Wikipedia article for
 * details and references about Random
 * Graphs and the
 * Erdős–Rényi model
 * .
 * 
 * 

* In the $G(n, M)$ model, a graph is chosen uniformly at random from the collection of all graphs * which have $n$ nodes and $M$ edges. For example, in the $G(3, 2)$ model, each of the three * possible graphs on three vertices and two edges are included with probability $\frac{1}{3}$. * *

* The implementation creates the vertices and then randomly chooses an edge and tries to add it. If * the add fails for any reason (an edge already exists and multiple (parallel) edges are not * allowed) it will just choose another and try again. The performance therefore varies * significantly based on the probability of successfully constructing an acceptable edge. * *

* The implementation tries to guess the number of allowed edges based on the following. If * self-loops or multiple edges are allowed and requested, the maximum number of edges is * {@link Integer#MAX_VALUE}. Otherwise the maximum for undirected graphs with n vertices is * $\frac{n(n-1)}{2}$ while for directed $n(n-1)$. * *

* For the $G(n, p)$ model please see {@link GnpRandomGraphGenerator}. * * @author Assaf Lehr * @author Dimitrios Michail * * @param the graph vertex type * @param the graph edge type * * @see GnpRandomGraphGenerator */ public class GnmRandomGraphGenerator implements GraphGenerator { private static final boolean DEFAULT_ALLOW_LOOPS = false; private static final boolean DEFAULT_ALLOW_MULTIPLE_EDGES = false; private final Random rng; private final int n; private final int m; private final boolean loops; private final boolean multipleEdges; /** * Create a new $G(n, M)$ random graph generator. The generator does not create self-loops or * multiple (parallel) edges between the same two vertices. * * @param n the number of nodes * @param m the number of edges */ public GnmRandomGraphGenerator(int n, int m) { this(n, m, new Random(), DEFAULT_ALLOW_LOOPS, DEFAULT_ALLOW_MULTIPLE_EDGES); } /** * Create a new $G(n, M)$ random graph generator. The generator does not create self-loops or * multiple (parallel) edges between the same two vertices. * * @param n the number of nodes * @param m the number of edges * @param seed seed for the random number generator */ public GnmRandomGraphGenerator(int n, int m, long seed) { this(n, m, new Random(seed), DEFAULT_ALLOW_LOOPS, DEFAULT_ALLOW_MULTIPLE_EDGES); } /** * Create a new $G(n, M)$ random graph generator * * @param n the number of nodes * @param m the number of edges * @param seed seed for the random number generator * @param loops whether the generated graph may contain loops * @param multipleEdges whether the generated graph many contain multiple (parallel) edges * between the same two vertices */ public GnmRandomGraphGenerator(int n, int m, long seed, boolean loops, boolean multipleEdges) { this(n, m, new Random(seed), loops, multipleEdges); } /** * Create a new $G(n, M)$ random graph generator * * @param n the number of nodes * @param m the number of edges * @param rng the random number generator * @param loops whether the generated graph may contain loops * @param multipleEdges whether the generated graph many contain multiple (parallel) edges * between the same two vertices */ public GnmRandomGraphGenerator(int n, int m, Random rng, boolean loops, boolean multipleEdges) { if (n < 0) { throw new IllegalArgumentException("number of vertices must be non-negative"); } this.n = n; if (m < 0) { throw new IllegalArgumentException("number of edges must be non-negative"); } this.m = m; this.rng = Objects.requireNonNull(rng); this.loops = loops; this.multipleEdges = multipleEdges; } /** * Generates a random graph based on the $G(n, M)$ model * * @param target the target graph * @param resultMap not used by this generator, can be null * * @throws IllegalArgumentException if the number of edges, passed in the constructor, cannot be * created on a graph of the concrete type with the specified number of vertices * @throws IllegalArgumentException if the graph does not support a requested feature such as * self-loops or multiple (parallel) edges */ @Override public void generateGraph(Graph target, Map resultMap) { // special case if (n == 0) { return; } // check whether to create loops if (loops && !target.getType().isAllowingSelfLoops()) { throw new IllegalArgumentException("Provided graph does not support self-loops"); } // check whether to create multiple edges if (multipleEdges && !target.getType().isAllowingMultipleEdges()) { throw new IllegalArgumentException( "Provided graph does not support multiple edges between the same vertices"); } // compute maximum allowed edges if (m > computeMaximumAllowedEdges( n, target.getType().isDirected(), loops, multipleEdges)) { throw new IllegalArgumentException( "number of edges is not valid for the graph type " + "\n-> invalid number of edges=" + m + " for:" + " graph type=" + target.getType() + ", number of vertices=" + n); } // create vertices List vertices = new ArrayList<>(n); int previousVertexSetSize = target.vertexSet().size(); for (int i = 0; i < n; i++) { vertices.add(target.addVertex()); } if (target.vertexSet().size() != previousVertexSetSize + n) { throw new IllegalArgumentException( "Vertex factory did not produce " + n + " distinct vertices."); } // create edges int edgesCounter = 0; while (edgesCounter < m) { int sIndex = rng.nextInt(n); int tIndex = rng.nextInt(n); // lazy to avoid lookups V s = null; V t = null; // check whether to add the edge boolean addEdge = false; if (sIndex == tIndex) { // self-loop if (loops) { addEdge = true; } } else { if (multipleEdges) { addEdge = true; } else { s = vertices.get(sIndex); t = vertices.get(tIndex); if (!target.containsEdge(s, t)) { addEdge = true; } } } // if yes, add it if (addEdge) { try { if (s == null) { s = vertices.get(sIndex); t = vertices.get(tIndex); } E resultEdge = target.addEdge(s, t); if (resultEdge != null) { edgesCounter++; } } catch (IllegalArgumentException e) { // do nothing, just ignore the edge } } } } /** * Return the number of allowed edges based on the graph type. * * @param n number of nodes * @param isDirected whether the graph is directed or not * @param createLoops if loops are allowed * @param createMultipleEdges if multiple (parallel) edges are allowed * @return the number of maximum edges */ static int computeMaximumAllowedEdges( int n, boolean isDirected, boolean createLoops, boolean createMultipleEdges) { if (n == 0) { return 0; } int maxAllowedEdges; try { if (isDirected) { maxAllowedEdges = Math.multiplyExact(n, n - 1); } else { // assume undirected if (n % 2 == 0) { maxAllowedEdges = Math.multiplyExact(n / 2, n - 1); } else { maxAllowedEdges = Math.multiplyExact(n, (n - 1) / 2); } } if (createLoops) { if (createMultipleEdges) { return Integer.MAX_VALUE; } else { if (isDirected) { maxAllowedEdges = Math.addExact(maxAllowedEdges, Math.multiplyExact(2, n)); } else { // assume undirected maxAllowedEdges = Math.addExact(maxAllowedEdges, n); } } } else { if (createMultipleEdges) { if (n > 1) { return Integer.MAX_VALUE; } } } } catch (ArithmeticException e) { return Integer.MAX_VALUE; } return maxAllowedEdges; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy