org.jgrapht.generate.RandomGraphGenerator Maven / Gradle / Ivy
/* ==========================================
* JGraphT : a free Java graph-theory library
* ==========================================
*
* Project Info: http://jgrapht.sourceforge.net/
* Project Creator: Barak Naveh (http://sourceforge.net/users/barak_naveh)
*
* (C) Copyright 2003-2008, by Barak Naveh and Contributors.
*
* This program and the accompanying materials are dual-licensed under
* either
*
* (a) the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation, or (at your option) any
* later version.
*
* or (per the licensee's choosing)
*
* (b) the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation.
*/
/* -----------------
* RandomGraphGenerator.java
* -----------------
* (C) Copyright 2005-2008, by Assaf Lehr and Contributors.
*
* Original Author: Assaf Lehr
* Contributor(s): -
*
* $Id$
*
* Changes
* -------
*/
package org.jgrapht.generate;
import java.util.*;
import org.jgrapht.*;
import org.jgrapht.graph.*;
/**
* This Generator creates a random-topology graph of a specified number of
* vertexes and edges. An instance of this generator will always return the same
* graph-topology in calls to generateGraph(). The vertexes can be different
* (depends on the VertexFactory implementation)
*
* However, two instances which use the same constructor parameters will
* produce two different random graphs (note: as with any random generator,
* there is always a small possibility that two instances will create the same
* results).
*
* @author Assaf Lehr
* @since Aug 6, 2005
*/
public class RandomGraphGenerator
implements GraphGenerator
{
private static long seedUniquifier = 8682522807148012L;
protected int numOfVertexes;
protected int numOfEdges;
protected Random randomizer;
private long randomizerSeed;
public RandomGraphGenerator(int aNumOfVertexes, int aNumOfEdges)
{
if ((aNumOfVertexes < 0) || (aNumOfEdges < 0)) {
throw new IllegalArgumentException("must be non-negative");
}
this.numOfVertexes = aNumOfVertexes;
this.numOfEdges = aNumOfEdges;
this.randomizerSeed = chooseRandomSeedOnce();
this.randomizer = new Random(this.randomizerSeed);
}
/**
* Should be called only once on creation. Chooses a seed which can be used
* later to reset the randomizer before each method call. This
* implementation copies the java.util.Random constructor because there is
* no getSeed() there, and seed is protected.
*
* @author Assaf
* @since Aug 6, 2005
*/
private synchronized static long chooseRandomSeedOnce()
{
return (++seedUniquifier + System.nanoTime());
}
/**
* Resets seed to generate the same random stream.
*/
private void resetRandomSeed()
{
this.randomizer.setSeed(this.randomizerSeed);
}
/**
* (non-Javadoc)
*
* @throws IllegalArgumentException if the aNumOfEdges passed in the
* constructor, cannot be created on a graph of the concrete type with
* aNumOfVertexes.
* org.jgrapht.generate.RandomGraphGenerator.DefaultEdgeTopologyFactory#isNumberOfEdgesValid(org.jgrapht.Graph,
* int)
*
* @see GraphGenerator#generateGraph(Graph, VertexFactory, Map)
*/
public void generateGraph(
Graph target,
VertexFactory vertexFactory,
Map resultMap)
{
resetRandomSeed();
// key = generation order (1st,2nd,3rd,...) value=vertex Object
// will be used later
Map orderToVertexMap =
new HashMap(this.numOfVertexes);
for (int i = 0; i < this.numOfVertexes; i++) {
V currVertex = vertexFactory.createVertex();
target.addVertex(currVertex);
orderToVertexMap.put(Integer.valueOf(i), currVertex);
}
if (target.vertexSet().size() != numOfVertexes) {
throw new IllegalArgumentException(
"Vertex factory did not produce " + numOfVertexes
+ " distinct vertices.");
}
// use specific type of edge factory, depending of the graph type
// and edge density
EdgeTopologyFactory edgesFactory =
edgeTopologyFactoryChooser(target, numOfEdges);
if (!edgesFactory.isNumberOfEdgesValid(target, numOfEdges)) {
throw new IllegalArgumentException(
"numOfEdges is not valid for the graph type "
+ "\n-> Invalid number Of Edges=" + numOfEdges + " for:"
+ " graph type=" + target.getClass()
+ " ,number Of Vertexes=" + this.numOfVertexes
+ "\n-> Advice: For the Max value , check the javadoc for"
+ " org.jgrapht.generate.RandomGraphGenerator.DefaultEdgeTopologyFactory");
}
edgesFactory.createEdges(
target,
orderToVertexMap,
this.numOfEdges,
this.randomizer);
}
/**
* Returns a concrete EdgeTopologyFactory, depending on graph type and
* numOfEdges
*
* @param target
*
* @return
*/
private EdgeTopologyFactory edgeTopologyFactoryChooser(
Graph target,
int numOfEdges)
{
return new DefaultEdgeTopologyFactory();
}
/**
* This class is used to generate the edge topology for a graph.
*
* @author Assaf
* @since Aug 6, 2005
*/
public interface EdgeTopologyFactory
{
/**
* Two different calls to the createEdges() with the same parameters
* must result in the generation of the same. But if the randomizer is
* different, it should, usually, create different edge topology.
*
* @param targetGraph - guranteed to start with zero edges.
* @param orderToVertexMap - key=Integer of vertex order . between zero
* to numOfVertexes (exclusive). value = vertex from the graph. unique.
* @param numberOfEdges - to create in the graph
* @param randomizer
*/
public void createEdges(
Graph targetGraph,
Map orderToVertexMap,
int numberOfEdges,
Random randomizer);
/**
* Checks if the graph can contain the givven numberOfEdges according to
* the graph type restrictions. For example: #V means number of
* vertexes in graph
* a Simple Graph, can have max of #V*(#V-1)/2 edges. etc
*
* @param targetGraph guranteed to start with zero edges.
* @param numberOfEdges
*/
public boolean isNumberOfEdgesValid(
Graph targetGraph,
int numberOfEdges);
}
/**
* Default implementation of the EdgeTopologyFactory interface. randomly
* chooses an edge and tries to add it. If the add fails from any reason
* (like: self edge / multiple edges in unpermitted graph type) it will just
* choose another and try again. Performance:
* when the number of possible edges becomes slim , this class will have
* a very poor performance , cause it will not use gready methods to choose
* them. for example : In simple graph , if #V = N (#x = number Of x) and we
* want full mesh #edges= N*(N-1)/2 , the first added edges will do so
* quickly (O(1) , the last will take O(N^2). So , do not use it in this
* kind of graphs.
* If the numberOfEdges is bigger than what the graph can add, there
* will be an infinite loop here. It is not tested.
*
* @author Assaf
* @since Aug 6, 2005
*/
public class DefaultEdgeTopologyFactory
implements EdgeTopologyFactory
{
public void createEdges(
Graph targetGraph,
Map orderToVertexMap,
int numberOfEdges,
Random randomizer)
{
int iterationsCounter = 0;
int edgesCounter = 0;
while (edgesCounter < numberOfEdges) {
// randomizer.nextInt(int n) return a number between zero
// (inclusive) and n(exclusive)
VV startVertex =
orderToVertexMap.get(
Integer.valueOf(randomizer.nextInt(numOfVertexes)));
VV endVertex =
orderToVertexMap.get(
Integer.valueOf(randomizer.nextInt(numOfVertexes)));
try {
EE resultEdge = targetGraph.addEdge(startVertex, endVertex);
if (resultEdge != null) {
edgesCounter++;
}
} catch (Exception e) {
// do nothing.just ignore the edge
}
iterationsCounter++;
}
}
/**
* checks if the numOfEdges is smaller than the Max edges according to
* the following table:
*
*
*
*
* Graph Type
* Directed / UnDirected
* multiple edges
* loops
* Max Edges
*
*
* SimpleGraph
* UnDirected
* -
* -
* N(N-1)/2
*
*
* Multigraph
* UnDirected
* +
* -
* Infinite
*
*
* Pseudograph
* UnDirected
* +
* +
* Infinite
*
*
* SimpleDirectedGraph
* Directed
* -
* -
* N (N-1)
*
*
* DefaultDirectedGraph
* Directed
* -
* +
* N*(N-1)+ N = N^2
*
*
* DirectedMultigraph
* Directed
* +
* +
* Infinite
*
*
*
* @see RandomGraphGenerator.EdgeTopologyFactory#isNumberOfEdgesValid(Graph,
* int)
*/
public boolean isNumberOfEdgesValid(
Graph targetGraph,
int numberOfEdges)
{
boolean result;
boolean infinite = false;
int maxAllowedEdges = getMaxEdgesForVertexNum(targetGraph);
if (maxAllowedEdges == -1) {
infinite = true;
}
if (true == infinite) {
result = true;
} else if (numberOfEdges <= maxAllowedEdges) {
result = true;
} else {
result = false;
}
return result;
}
/**
* Return max edges for that graph. If it is infinite return -1 instead.
*/
public int getMaxEdgesForVertexNum(Graph targetGraph)
{
int maxAllowedEdges = 0;
if (targetGraph instanceof SimpleGraph) {
maxAllowedEdges = numOfVertexes * (numOfVertexes - 1) / 2;
} else if (targetGraph instanceof SimpleDirectedGraph) {
maxAllowedEdges = numOfVertexes * (numOfVertexes - 1);
} else if (targetGraph instanceof DefaultDirectedGraph) {
maxAllowedEdges = numOfVertexes * numOfVertexes;
} else {
// This may be overly liberal in the case of something
// like a simple graph which has been wrapped with
// a graph adapter or view.
maxAllowedEdges = -1; // infinite
}
return maxAllowedEdges;
}
}
}
// End RandomGraphGenerator.java