2 * Copyright (c) 2003-2005 The BISON Project
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 2 as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 package peersim.graph;
24 * Implements graph algorithms. The current implementation is NOT thread
25 * safe. Some algorithms are not static, many times the result of an
26 * algorithm can be read from non-static fields.
28 public class GraphAlgorithms {
30 // =================== public fields ==================================
31 // ====================================================================
33 /** output of some algorithms is passed here */
34 public int[] root = null;
35 private Stack<Integer> stack = new Stack<Integer>();
36 private int counter=0;
40 public final static int WHITE=0;
41 public final static int GREY=1;
42 public final static int BLACK=2;
44 /** output of some algorithms is passed here */
45 public int[] color = null;
47 /** output of some algorithms is passed here */
48 public Set<Integer> cluster = null;
50 /** output of some algorithms is passed here */
51 public int[] d = null;
53 // =================== private methods ================================
54 // ====================================================================
58 * Collects nodes accessible from node "from" using depth-first search.
59 * Works on the array {@link #color} which must be of the same length as
60 * the size of the graph, and must contain values according to the
61 * following semantics:
62 * WHITE (0): not seen yet, GREY (1): currently worked upon. BLACK
63 * (other than 0 or 1): finished.
64 * If a negative color is met, it is saved in the {@link #cluster} set
65 * and is treated as black. This can be used to check if the currently
66 * visited cluster is weakly connected to another cluster.
67 * On exit no nodes are GREY.
68 * The result is the modified array {@link #color} and the modified set
71 private void dfs( int from ) {
75 for(int j:g.getNeighbours(from))
83 if( color[j]<0 ) cluster.add(color[j]);
90 // --------------------------------------------------------------------
93 * Collects nodes accessible from node "from" using breadth-first search.
94 * Its parameters and side-effects are identical to those of dfs.
95 * In addition, it stores the shortest distances from "from" in {@link #d},
96 * if it is not null. On return, <code>d[i]</code> contains the length of
97 * the shortest path from "from" to "i", if such a path exists, or it is
98 * unchanged (ie the original value of <code>d[i]</code> is kept,
100 * <code>d</code> must either be long enough or null.
102 private void bfs( int from ) {
104 List<Integer> q = new LinkedList<Integer>();
109 if( d != null ) d[from] = 0;
113 while( ! q.isEmpty() )
115 u = q.remove(0).intValue();
116 du = q.remove(0).intValue();
118 for(int j:g.getNeighbours(u))
120 if( color[j]==WHITE )
126 if( d != null ) d[j] = du+1;
131 cluster.add(color[j]);
138 // --------------------------------------------------------------------
140 /** The recursive part of the Tarjan algorithm. */
141 private void tarjanVisit(int i) {
147 for(int j:g.getNeighbours(i))
149 if( color[j]==WHITE )
153 if( color[j]>0 && color[root[j]]<color[root[i]] )
154 // inComponent is false and have to update root
161 if(root[i]==i) //this node is the root of its cluster
173 // =================== public methods ================================
174 // ====================================================================
176 /** Returns the weakly connected cluster indexes with size as a value.
177 * Cluster membership can be seen from the content of the array {@link #color};
178 * each node has the cluster index as color. The cluster indexes carry no
179 * information; we guarantee only that different clusters have different indexes.
181 public Map weaklyConnectedClusters( Graph g ) {
184 if( cluster == null ) cluster = new HashSet<Integer>();
185 if( color==null || color.length<g.size() ) color = new int[g.size()];
187 // cluster numbers are negative integers
188 int i, j, actCluster=0;
189 for(i=0; i<g.size(); ++i) color[i]=WHITE;
190 for(i=0; i<g.size(); ++i)
192 if( color[i]==WHITE )
195 bfs(i); // dfs is recursive, for large graphs not ok
197 for(j=0; j<g.size(); ++j)
199 if( color[j] == BLACK ||
200 cluster.contains(color[j]) )
201 color[j] = actCluster;
206 Hashtable<Integer,Integer> ht = new Hashtable<Integer,Integer>();
207 for(j=0; j<g.size(); ++j)
209 Integer num = ht.get(color[j]);
210 if( num == null ) ht.put(color[j],Integer.valueOf(1));
211 else ht.put(color[j],num+1);
217 // --------------------------------------------------------------------
220 * In <code>{@link #d}[j]</code> returns the length of the shortest path between
221 * i and j. The value -1 indicates that j is not accessible from i.
223 public void dist( Graph g, int i ) {
226 if( d==null || d.length<g.size() ) d = new int[g.size()];
227 if( color==null || color.length<g.size() ) color = new int[g.size()];
229 for(int j=0; j<g.size(); ++j)
238 // --------------------------------------------------------------------
241 * Calculates the clustering coefficient for the given node in the given
242 * graph. The clustering coefficient is the number of edges between
243 * the neighbours of i divided by the number of possible edges.
244 * If the graph is directed, an exception is thrown.
245 * If the number of neighbours is 1, returns 1. For zero neighbours
247 * @throws IllegalArgumentException if g is directed
249 public static double clustering( Graph g, int i ) {
251 if( g.directed() ) throw new IllegalArgumentException(
252 "graph is directed");
254 Object[] n = g.getNeighbours(i).toArray();
256 if( n.length==1 ) return 1.0;
260 for(int j=0; j<n.length; ++j)
261 for(int k=j+1; k<n.length; ++k)
262 if( g.isEdge((Integer)n[j],(Integer)n[k]) ) ++edges;
264 return ((edges*2.0)/n.length)/(n.length-1);
267 // --------------------------------------------------------------------
270 * Performs anti-entropy epidemic multicasting from node 0.
271 * As a result the number of nodes that have been reached in cycle i
272 * is put into <code>b[i]</code>.
273 * The number of cycles performed is determined by <code>b.length</code>.
274 * In each cycle each node contacts a random neighbour and exchanges
275 * information. The simulation is generational: when a node contacts a neighbor
276 * in cycle i, it sees their state as in cycle i-1, besides, all nodes update
277 * their state at the same time point, synchronously.
279 public static void multicast( Graph g, int[] b, Random r ) {
281 int c1[] = new int[g.size()];
282 int c2[] = new int[g.size()];
283 for(int i=0; i<c1.length; ++i) c2[i]=c1[i]=WHITE;
285 Collection<Integer> neighbours=null;
289 for(; k<b.length || black<g.size(); ++k)
291 for(int i=0; i<c2.length; ++i)
293 neighbours=g.getNeighbours(i);
294 Iterator<Integer> it=neighbours.iterator();
295 for(int j=r.nextInt(neighbours.size()); j>0; --j)
297 int randn = it.next();
299 // push pull exchane with random neighbour
300 if( c1[i]==BLACK ) //c2[i] is black too
302 if(c2[randn]==WHITE) ++black;
305 else if( c1[randn]==BLACK )
307 if(c2[i]==WHITE) ++black;
311 System.arraycopy(c2,0,c1,0,c1.length);
315 for(; k<b.length; ++k) b[k]=g.size();
318 // --------------------------------------------------------------------
321 * Performs flooding from given node.
322 * As a result <code>b[i]</code> contains the number of nodes
323 * reached in exactly i steps, and always <code>b[0]=1</code>.
324 * If the maximal distance from k is lower than <code>b.length</code>,
325 * then the remaining elements of b are zero.
327 public void flooding( Graph g, int[] b, int k ) {
331 for(int i=0; i<b.length; ++i) b[i]=0;
332 for(int i=0; i<d.length; ++i)
334 if( d[i] >= 0 && d[i] < b.length ) b[d[i]]++;
338 // --------------------------------------------------------------------
340 /** Returns the strongly connected cluster roots with size as a value.
341 * Cluster membership can be seen from the content of the array {@link #root};
342 * each node has the root of the strongly connected cluster it belongs to.
343 * A word of caution: for large graphs that have a large diameter and that
344 * are strongly connected (such as large rings) you can get stack overflow
345 * because of the large depth of recursion.
347 //XXX implement a non-recursive version ASAP!!!
348 public Map tarjan( Graph g ) {
352 if( root==null || root.length<g.size() ) root = new int[g.size()];
353 if( color==null || color.length<g.size() ) color = new int[g.size()];
354 for( int i=0; i<g.size(); ++i) color[i]=WHITE;
357 // color is WHITE (0): not visited
358 // not WHITE, positive (c>1): visited as the c-th node
359 // color is negative (c<1): inComponent true
360 for(int i=0; i<g.size(); ++i)
362 if( color[i]==WHITE ) tarjanVisit(i);
364 for( int i=0; i<g.size(); ++i) color[i]=0;
365 for( int i=0; i<g.size(); ++i) color[root[i]]++;
366 Hashtable<Integer,Integer> ht = new Hashtable<Integer,Integer>();
367 for(int j=0; j<g.size(); ++j)