Skip to content

Commit

Permalink
Merge branch 'master' into weighted-static-check
Browse files Browse the repository at this point in the history
Fixed conflicts due to deletion of test classes
  • Loading branch information
d-michail committed Mar 5, 2017
2 parents d783967 + c4c73bc commit eabb580
Show file tree
Hide file tree
Showing 23 changed files with 1,652 additions and 317 deletions.
2 changes: 2 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Changes to JGraphT in each version:
- Added a new, scalable `DOTImporter` which handles the full DOT specification including XML string identifiers. A dependency on the commons-lang3 package has been added to handle escaping/unescaping of strings efficiently; Updated antlr version to 4.6. (contributed by Dimitrios Michail)
- Added Johnson's all-pairs-shortest paths algorithm `JohnsonShortestPaths`; Simplified Bellman-Ford implementation and added support for negative cycle detection; added `AsWeightedUndirectedGraph` and `AsUnweightedUndirectedGraph`; Constructors of `UndirectedGraphUnion` are now public. (contributed by Dimitrios Michail)
- Refactored `DirectedAcyclicGraph`, moved it out of the experimental package, and refactored its perfomance tests using jmh; Deleted `GraphSquare` from experimental (inefficient implementation) (contributed by Dimitrios Michail)
- Added Watts-Strogatz small-world graph generator, Kleinberg's small-world graph generator, Barabasi-Albert graph generator, Linearized Chord Diagram GraphGenerator, AliasMethodSampler utility class with Vose's implementation; Refactored ScaleFreeGraphGenerator (constructor with random number generator added); Refactored CompleteGraphGenerator to not assume a specific graph type (simple, etc). (contributed by Dimitrios Michail)
- Deleted JUnit test suites. (contributed by Joris Kinable)

- **version 1.0.1** (16-Jan-2017):
- Deleted all previously deprecated methods (cleanup contributed by Joris Kinable and Dimitrios Michail)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/*
* (C) Copyright 2017-2017, by Dimitrios Michail and Contributors.
*
* JGraphT : a free Java graph-theory library
*
* 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.
*/
package org.jgrapht.alg.util;

import java.util.Comparator;
import java.util.Objects;
import java.util.Random;

/**
* The alias method for sampling from a discrete probability distribution.
*
* <p>
* The implementation is described in the paper: Michael D. Vose. A Linear Algorithm for Generating
* Random Numbers with a Given Distribution. IEEE Transactions on Software Engineering,
* 17(9):972--975, 1991.
*
* <p>
* Initialization takes O(n) where n is the number of items. Sampling takes O(1).
*
* @author Dimitrios Michail
* @since February 2017
*/
public class AliasMethodSampler
{
private final Random rng;
private Comparator<Double> comparator;

private final double[] prob;
private final int[] alias;

/**
* Constructor
*
* @param p the probability distribution where position i of the array is Prob(X=i)
* @throws IllegalArgumentException in case of a non-valid probability distribution
*/
public AliasMethodSampler(double[] p)
{
this(p, new Random(), ToleranceDoubleComparator.DEFAULT_EPSILON);
}

/**
* Constructor
*
* @param p the probability distribution where position i of the array is Prob(X=i)
* @param seed seed to use for the random number generator
*/
public AliasMethodSampler(double[] p, long seed)
{
this(p, new Random(seed), ToleranceDoubleComparator.DEFAULT_EPSILON);
}

/**
* Constructor
*
* @param p the probability distribution where position i of the array is Prob(X=i)
* @param rng the random number generator
* @throws IllegalArgumentException in case of a non-valid probability distribution
*/
public AliasMethodSampler(double[] p, Random rng)
{
this(p, rng, ToleranceDoubleComparator.DEFAULT_EPSILON);
}

/**
* Constructor
*
* @param p the probability distribution where position i of the array is Prob(X=i)
* @param rng the random number generator
* @param epsilon tolerance used when comparing floating-point values
* @throws IllegalArgumentException in case of a non-valid probability distribution
*/
public AliasMethodSampler(double[] p, Random rng, double epsilon)
{
this.rng = Objects.requireNonNull(rng, "Random number generator cannot be null");
this.comparator = new ToleranceDoubleComparator(epsilon);

if (p == null || p.length < 1) {
throw new IllegalArgumentException("Probabilities cannot be empty");
}
double sum = 0d;
for (int i = 0; i < p.length; i++) {
if (comparator.compare(p[i], 0d) < 0) {
throw new IllegalArgumentException("Non valid probability distribution");
}
sum += p[i];
}
if (comparator.compare(sum, 1d) != 0) {
throw new IllegalArgumentException("Non valid probability distribution");
}

/*
* Initialize large and small
*/
int n = p.length;
int[] large = new int[n];
int[] small = new int[n];
double threshold = 1d / n;

int l = 0, s = 0;
for (int j = 0; j < n; j++) {
if (comparator.compare(p[j], threshold) > 0) {
large[l++] = j;
} else {
small[s++] = j;
}
}

/*
* Compute probability and alias
*/
this.prob = new double[n];
this.alias = new int[n];
while (s != 0 && l != 0) {
int j = small[--s];
int k = large[--l];

prob[j] = n * p[j];
alias[j] = k;
p[k] += p[j] - threshold;
if (comparator.compare(p[k], threshold) > 0) {
large[l++] = k;
} else {
small[s++] = k;
}
}

while (s > 0) {
prob[small[--s]] = 1d;
}

while (l > 0) {
prob[large[--l]] = 1d;
}
}

/**
* Sample a value from the distribution.
*
* @return a sample from the distribution
*/
public int next()
{
double u = rng.nextDouble() * prob.length;
int j = (int) Math.floor(u);
if (comparator.compare(u - j, prob[j]) <= 0) {
return j;
} else {
return alias[j];
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/*
* (C) Copyright 2017-2017, by Dimitrios Michail and Contributors.
*
* JGraphT : a free Java graph-theory library
*
* 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.
*/
package org.jgrapht.generate;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.Set;

import org.jgrapht.Graph;
import org.jgrapht.VertexFactory;

/**
* Barabási-Albert growth and preferential attachment graph generator.
*
* <p>
* The generator is described in the paper: A.-L. Barabási and R. Albert. Emergence of scaling in
* random networks. Science, 286:509-512, 1999.
*
* <p>
* The generator starts with a complete graph of m0 nodes and grows the network by adding n-m0
* additional nodes. The additional nodes are added one by one and each of them is connected to m
* previously added nodes, where the probability of connecting to a node is proportional to its
* degree.
*
* <p>
* Note that the Barabàsi-Albert model is designed for undirected networks. Nevertheless, this
* generator also works with directed networks where the probabilities are proportional to the sum
* of incoming and outgoing degrees. For a more general discussion see the paper: M. E. J. Newman.
* The Structure and Function of Complex Networks. SIAM Rev., 45(2):167--256, 2003.
*
* @author Dimitrios Michail
* @since February 2017
*
* @param <V> the graph vertex type
* @param <E> the graph edge type
*/
public class BarabasiAlbertGraphGenerator<V, E>
implements GraphGenerator<V, E, V>
{
private final Random rng;
private final int m0;
private final int m;
private final int n;

/**
* Constructor
*
* @param m0 number of initial nodes
* @param m number of edges of each new node added during the network growth
* @param n final number of nodes
* @throws IllegalArgumentException in case of invalid parameters
*/
public BarabasiAlbertGraphGenerator(int m0, int m, int n)
{
this(m0, m, n, new Random());
}

/**
* Constructor
*
* @param m0 number of initial nodes
* @param m number of edges of each new node added during the network growth
* @param n final number of nodes
* @param seed seed for the random number generator
* @throws IllegalArgumentException in case of invalid parameters
*/
public BarabasiAlbertGraphGenerator(int m0, int m, int n, long seed)
{
this(m0, m, n, new Random(seed));
}

/**
* Constructor
*
* @param m0 number of initial nodes
* @param m number of edges of each new node added during the network growth
* @param n final number of nodes
* @param rng the random number generator to use
* @throws IllegalArgumentException in case of invalid parameters
*/
public BarabasiAlbertGraphGenerator(int m0, int m, int n, Random rng)
{
if (m0 < 1) {
throw new IllegalArgumentException("invalid initial nodes (" + m0 + " < 1)");
}
this.m0 = m0;
if (m <= 0) {
throw new IllegalArgumentException("invalid edges per node (" + m + " <= 0");
}
if (m > m0) {
throw new IllegalArgumentException("invalid edges per node (" + m + " > " + m0 + ")");
}
this.m = m;
if (n < m0) {
throw new IllegalArgumentException(
"total number of nodes must be at least equal to the initial set");
}
this.n = n;
this.rng = Objects.requireNonNull(rng, "Random number generator cannot be null");
}

/**
* Generates an instance.
*
* @param target the target graph
* @param vertexFactory the vertex factory
* @param resultMap not used by this generator, can be null
*/
@Override
public void generateGraph(
Graph<V, E> target, VertexFactory<V> vertexFactory, Map<String, V> resultMap)
{
/*
* Create complete graph with m0 nodes
*/
List<V> nodes = new ArrayList<>(n * m);
Set<V> oldNodes = new HashSet<>(target.vertexSet());
new CompleteGraphGenerator<V, E>(m0).generateGraph(target, vertexFactory, resultMap);
target.vertexSet().stream().filter(v -> !oldNodes.contains(v)).forEach(nodes::add);

/*
* Augment node list to have node multiplicity equal to m0-1.
*/
for (int i = 0; i < m0 - 2; i++) {
nodes.addAll(target.vertexSet());
}

/*
* Grow network with preferential attachment
*/
for (int i = m0; i < n; i++) {
V v = vertexFactory.createVertex();
if (!target.addVertex(v)) {
throw new IllegalArgumentException("Invalid vertex factory");
}

List<V> newEndpoints = new ArrayList<>();
int added = 0;
while (added < m) {
V u = nodes.get(rng.nextInt(nodes.size()));
if (!target.containsEdge(v, u)) {
target.addEdge(v, u);
added++;
newEndpoints.add(v);
if (i > 1) {
newEndpoints.add(u);
}
}
}
nodes.addAll(newEndpoints);
}

}

}
Loading

0 comments on commit eabb580

Please sign in to comment.