forked from jgrapht/jgrapht
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into weighted-static-check
Fixed conflicts due to deletion of test classes
- Loading branch information
Showing
23 changed files
with
1,652 additions
and
317 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
168 changes: 168 additions & 0 deletions
168
jgrapht-core/src/main/java/org/jgrapht/alg/util/AliasMethodSampler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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]; | ||
} | ||
} | ||
|
||
} |
174 changes: 174 additions & 0 deletions
174
jgrapht-core/src/main/java/org/jgrapht/generate/BarabasiAlbertGraphGenerator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
|
||
} | ||
|
||
} |
Oops, something went wrong.