diff --git a/src/org/graphstream/algorithm/Dijkstra.java b/src/org/graphstream/algorithm/Dijkstra.java index cab457d6e636d5da29e993f2a75d14f0f51f9446..6ac8a9c9d32f7df02c8338972bae5b73d948277b 100644 --- a/src/org/graphstream/algorithm/Dijkstra.java +++ b/src/org/graphstream/algorithm/Dijkstra.java @@ -35,6 +35,7 @@ import java.util.List; import java.util.NoSuchElementException; import java.util.Stack; +import org.graphstream.algorithm.util.FibonacciHeap; import org.graphstream.graph.Edge; import org.graphstream.graph.Graph; import org.graphstream.graph.Node; diff --git a/src/org/graphstream/algorithm/Toolkit.java b/src/org/graphstream/algorithm/Toolkit.java index 9dc0d3f237c94ba58d44d4d312fe32bcd980355a..3284e1a5d144ae17b3ded15ac73980f272ffdf4c 100644 --- a/src/org/graphstream/algorithm/Toolkit.java +++ b/src/org/graphstream/algorithm/Toolkit.java @@ -31,6 +31,7 @@ package org.graphstream.algorithm; import java.util.*; +import org.graphstream.algorithm.util.RandomTools; import org.graphstream.graph.*; import org.graphstream.stream.GraphReplay; import org.graphstream.ui.layout.Layout; @@ -1347,9 +1348,9 @@ public class Toolkit extends * The adjacency matrix of a graph is a n times n matrix * {@code a}, where n is the number of nodes of the graph. The * element {@code a[i][j]} of this matrix is equal to the number of edges - * from the node {@code graph.getNode(i)} to the node {@code - * graph.getNode(j)}. An undirected edge between i-th and j-th node is - * counted twice: in {@code a[i][j]} and in {@code a[j][i]}. + * from the node {@code graph.getNode(i)} to the node + * {@code graph.getNode(j)}. An undirected edge between i-th and j-th node + * is counted twice: in {@code a[i][j]} and in {@code a[j][i]}. * * @param graph * A graph. @@ -1381,9 +1382,9 @@ public class Toolkit extends * The adjacency matrix of a graph is a n times n matrix * {@code a}, where n is the number of nodes of the graph. The * element {@code a[i][j]} of this matrix is equal to the number of edges - * from the node {@code graph.getNode(i)} to the node {@code - * graph.getNode(j)}. An undirected edge between i-th and j-th node is - * counted twice: in {@code a[i][j]} and in {@code a[j][i]}. + * from the node {@code graph.getNode(i)} to the node + * {@code graph.getNode(j)}. An undirected edge between i-th and j-th node + * is counted twice: in {@code a[i][j]} and in {@code a[j][i]}. * * @param graph * A graph @@ -1407,12 +1408,12 @@ public class Toolkit extends * number of edges of the graph. The coefficients {@code a[i][j]} of this * matrix have the following values: *
- *
• -1 if {@code graph.getEdge(j)} is directed and {@code - * graph.getNode(i)} is its source.
• - *
• 1 if {@code graph.getEdge(j)} is undirected and {@code - * graph.getNode(i)} is its source.
• - *
• 1 if {@code graph.getNode(i)} is the target of {@code - * graph.getEdge(j)}.
• + *
• -1 if {@code graph.getEdge(j)} is directed and + * {@code graph.getNode(i)} is its source.
• + *
• 1 if {@code graph.getEdge(j)} is undirected and + * {@code graph.getNode(i)} is its source.
• + *
• 1 if {@code graph.getNode(i)} is the target of + * {@code graph.getEdge(j)}.
• *
• 0 otherwise. *
* In the special case when the j-th edge is a loop connecting the i-th node @@ -1450,12 +1451,12 @@ public class Toolkit extends * number of edges of the graph. The coefficients {@code a[i][j]} of this * matrix have the following values: *
- *
• -1 if {@code graph.getEdge(j)} is directed and {@code - * graph.getNode(i)} is its source.
• - *
• 1 if {@code graph.getEdge(j)} is undirected and {@code - * graph.getNode(i)} is its source.
• - *
• 1 if {@code graph.getNode(i)} is the target of {@code - * graph.getEdge(j)}.
• + *
• -1 if {@code graph.getEdge(j)} is directed and + * {@code graph.getNode(i)} is its source.
• + *
• 1 if {@code graph.getEdge(j)} is undirected and + * {@code graph.getNode(i)} is its source.
• + *
• 1 if {@code graph.getNode(i)} is the target of + * {@code graph.getEdge(j)}.
• *
• 0 otherwise.
• *
* In the special case when the j-th edge is a loop connecting the i-th node @@ -1523,4 +1524,190 @@ public class Toolkit extends public static void computeLayout(Graph g) { computeLayout(g, new SpringBox(), 0.99); } + + /** + * Returns a random subset of nodes of fixed size. Each node has the same + * chance to be chosen. + * + * @param graph + * A graph. + * @param k + * The size of the subset. + * @return A random subset of nodes of size `k`. + * @throws IllegalArgumentException + * If `k` is negative or greater than the number of + * nodes. + * @complexity O(`k`) + */ + public static List randomNodeSet(Graph graph, int k) { + return randomNodeSet(graph, k, new Random()); + } + + /** + * Returns a random subset of nodes of fixed size. Each node has the same + * chance to be chosen. + * + * @param graph + * A graph. + * @param k + * The size of the subset. + * @param random + * A source of randomness. + * @return A random subset of nodes of size `k`. + * @throws IllegalArgumentException + * If `k` is negative or greater than the number of + * nodes. + * @complexity O(`k`) + */ + public static List randomNodeSet(Graph graph, int k, + Random random) { + if (k < 0 || k > graph.getNodeCount()) + throw new IllegalArgumentException("k must be between 0 and " + + graph.getNodeCount()); + Set subset = RandomTools.randomKsubset(graph.getNodeCount(), + k, null, random); + List result = new ArrayList(subset.size()); + for (int i : subset) + result.add(graph. getNode(i)); + return result; + } + + /** + * Returns a random subset of nodes. Each node is chosen with given + * probability. + * + * @param graph + * A graph. + * @param p + * The probability to choose each node. + * @return A random subset of nodes. + * @throws IllegalArgumentException + * If `p` is negative or greater than one. + * @complexity In average O(```n * p), where n is the + * number of nodes. + */ + public static List randomNodeSet(Graph graph, double p) { + return randomNodeSet(graph, p, new Random()); + } + + /** + * Returns a random subset of nodes. Each node is chosen with given + * probability. + * + * @param graph + * A graph. + * @param p + * The probability to choose each node. + * @param random + * A source of randomness. + * @return A random subset of nodes. + * @throws IllegalArgumentException + * If p is negative or greater than one. + * @complexity In average O(n * p), where n is the + * number of nodes. + */ + public static List randomNodeSet(Graph graph, double p, + Random random) { + if (p < 0 || p > 1) + throw new IllegalArgumentException("p must be between 0 and 1"); + Set subset = RandomTools.randomPsubset(graph.getNodeCount(), + p, null, random); + List result = new ArrayList(subset.size()); + for (int i : subset) + result.add(graph. getNode(i)); + return result; + } + + /** + * Returns a random subset of edges of fixed size. Each edge has the same + * chance to be chosen. + * + * @param graph + * A graph. + * @param k + * The size of the subset. + * @return A random subset of edges of size k. + * @throws IllegalArgumentException + * If k is negative or greater than the number of + * edges. + * @complexity O(k) + */ + public static List randomEdgeSet(Graph graph, int k) { + return randomEdgeSet(graph, k, new Random()); + } + + /** + * Returns a random subset of edges of fixed size. Each edge has the same + * chance to be chosen. + * + * @param graph + * A graph. + * @param k + * The size of the subset. + * @param random + * A source of randomness. + * @return A random subset of edges of size k. + * @throws IllegalArgumentException + * If k is negative or greater than the number of + * edges. + * @complexity O(k) + */ + public static List randomEdgeSet(Graph graph, int k, + Random random) { + if (k < 0 || k > graph.getEdgeCount()) + throw new IllegalArgumentException("k must be between 0 and " + + graph.getEdgeCount()); + Set subset = RandomTools.randomKsubset(graph.getEdgeCount(), + k, null, random); + List result = new ArrayList(subset.size()); + for (int i : subset) + result.add(graph. getEdge(i)); + return result; + } + + /** + * Returns a random subset of edges. Each edge is chosen with given + * probability. + * + * @param graph + * A graph. + * @param p + * The probability to choose each edge. + * @return A random subset of edges. + * @throws IllegalArgumentException + * If p is negative or greater than one. + * @complexity In average O(m * p), where m is the + * number of edges. + */ + public static List randomEdgeSet(Graph graph, double p) { + return randomEdgeSet(graph, p, new Random()); + } + + /** + * Returns a random subset of edges. Each edge is chosen with given + * probability. + * + * @param graph + * A graph. + * @param p + * The probability to choose each edge. + * @param random + * A source of randomness. + * @return A random subset of edges. + * @throws IllegalArgumentException + * If p is negative or greater than one. + * @complexity In average O(m * p), where m is the + * number of edges. + */ + public static List randomEdgeSet(Graph graph, double p, + Random random) { + if (p < 0 || p > 1) + throw new IllegalArgumentException("p must be between 0 and 1"); + Set subset = RandomTools.randomPsubset(graph.getEdgeCount(), + p, null, random); + List result = new ArrayList(subset.size()); + for (int i : subset) + result.add(graph. getEdge(i)); + return result; + } } diff --git a/src/org/graphstream/algorithm/FibonacciHeap.java b/src/org/graphstream/algorithm/util/FibonacciHeap.java similarity index 99% rename from src/org/graphstream/algorithm/FibonacciHeap.java rename to src/org/graphstream/algorithm/util/FibonacciHeap.java index f58f475414b993442973216b5eec3475e4388240..7e62024231557453b96df37dcd11a953ae515f51 100644 --- a/src/org/graphstream/algorithm/FibonacciHeap.java +++ b/src/org/graphstream/algorithm/util/FibonacciHeap.java @@ -27,7 +27,7 @@ * The fact that you are presently reading this means that you have had * knowledge of the CeCILL-C and LGPL licenses and that you accept their terms. */ -package org.graphstream.algorithm; +package org.graphstream.algorithm.util; import java.util.ArrayList; diff --git a/src/org/graphstream/algorithm/util/RandomTools.java b/src/org/graphstream/algorithm/util/RandomTools.java new file mode 100644 index 0000000000000000000000000000000000000000..4460d0f4d383f714636a83fb56519c564b1948b7 --- /dev/null +++ b/src/org/graphstream/algorithm/util/RandomTools.java @@ -0,0 +1,129 @@ +package org.graphstream.algorithm.util; + +import java.util.HashSet; +import java.util.Random; +import java.util.Set; + +/** + * This class provides several static methods for generating random numbers and + * sets + */ +public class RandomTools { + + /** + * Returns a pseudorandom number drawn from exponential distribution with + * mean 1. + * + * Uses the von Neumann's exponential generator. + * + * @param rnd + * source of randomness + * @return a pseudorandom number drawn from exponential distribution with + * mean 1. + * @complexity O(1) average complexity. The expected number of uniformly + * distributed numbers used is e^2 / (e - 1) + * + */ + public static double exponential(Random rnd) { + double y, w, u; + int z, k; + z = -1; + do { + w = y = rnd.nextDouble(); + k = 1; + while (true) { + u = rnd.nextDouble(); + if (u > w) + break; + w = u; + k++; + } + z++; + } while ((k & 1) == 0); + return z + y; + } + + /** + * Returns a pseudorandom number drawn from binomial distribution B(n, p). + * + * Uses a simple waiting time method based on exponential distribution. + * + * @param n + * number of tries + * @param p + * success probability + * @param rnd + * source of randomness + * @return a pseudorandom number drawn from binomial distribution + * @complexity Average complexity O(np) + */ + public static int binomial(int n, double p, Random rnd) { + double q = -Math.log(1 - p); + int x = 0; + double s = 0; + do { + s += exponential(rnd) / (n - x); + x++; + } while (s <= q); + return x - 1; + } + + /** + * Generates a pseudorandom subset of size k of the set {0, 1,...,n - 1}. + * Each element has the same chance to be chosen. + * + * Uses Floyd's method of subset generation with only k iterations. Note + * that the quality of this generator is limited by Java's random generator. + * Java stores the internal state in 48 bits, so in the best case we can + * only generate 2^48 different subsets. + * + * @param n + * the size of the initial set + * @param k + * the size of the generated set + * @param subset + * if not null, this set is cleared and the result is stored + * here. This avoids creations of sets at each call of this + * method + * @param rnd + * source of randomness + * @return a pseudorandom subset of size k of the set {0, 1,...,n} + * @complexity Depends on the set implementation. If add and lookup + * operations take constant time, the complexity is O(k) + */ + public static Set randomKsubset(int n, int k, Set subset, + Random rnd) { + if (subset == null) + subset = new HashSet(4 * k / 3 + 1); + else + subset.clear(); + for (int i = n - k; i < n; i++) { + int j = rnd.nextInt(i + 1); + subset.add(subset.contains(j) ? i : j); + } + return subset; + } + + /** + * Generates a pseudorandom subset of the set {0, 1,...,n - 1}. Each element + * is chosen with probability p. + * + * @param n + * the size of the initial set + * @param p + * the probability to choose each element + * @param subset + * if not null, this set is cleared and the result is stored + * here. This avoids creations of sets at each call of this + * method + * @param rnd + * source of randomness + * @return a pseudorandom subset of the set {0, 1,...,n}. + * @complexity Depends on the set implementation. If add and lookup + * operations take constant time, the complexity is O(np) + */ + public static Set randomPsubset(int n, double p, + Set subset, Random rnd) { + return randomKsubset(n, binomial(n, p, rnd), subset, rnd); + } +} diff --git a/src/org/graphstream/algorithm/util/package-info.java b/src/org/graphstream/algorithm/util/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..63279cd6a5d00a52d57ccfb54d214cbce9578444 --- /dev/null +++ b/src/org/graphstream/algorithm/util/package-info.java @@ -0,0 +1,30 @@ +/* + * Copyright 2006 - 2012 + * Stefan Balev + * Julien Baudry + * Antoine Dutot + * Yoann Pigné + * Guilhelm Savin + * + * GraphStream is a library whose purpose is to handle static or dynamic + * graph, create them from scratch, file or any source and display them. + * + * This program is free software distributed under the terms of two licenses, the + * CeCILL-C license that fits European law, and the GNU Lesser General Public + * License. You can use, modify and/ or redistribute the software under the terms + * of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following + * URL or under the terms of the GNU LGPL as published by + * the Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL-C and LGPL licenses and that you accept their terms. + */ +package org.graphstream.algorithm.util; ```