/**
* This file is part of the Kompics P2P Framework.
*
* Copyright (C) 2009 Swedish Institute of Computer Science (SICS)
* Copyright (C) 2009 Royal Institute of Technology (KTH)
*
* Kompics is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package se.sics.gvod.common;
import se.sics.gvod.net.VodAddress;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;
import java.util.TreeMap;
import org.apache.commons.math.stat.descriptive.SummaryStatistics;
/**
* The <code>GraphUtil</code> class contains some utility code to generate an
* adjacency matrix for a directed graph and use it to compute the diameter,
* average path length, and the clustering coefficient, using n BFS traversals.
*
* You should extend this class to do the same thing for the undirected
* graph corresponding to this directed graph, to obtain results for the
* diameter and path length that are comparable to the results in the GVod
* paper, if you are interested.
*
* @author Cosmin Arad <cosmin@sics.se>
* @version $Id: GraphUtil.java 1118 2009-09-01 08:36:14Z Cosmin $
*/
public class GraphUtil {
int n;
byte m[][];
public int dist[][];
double inDegree[];
int outDegree[];
double clustering[];
VodAddress[] a;
HashMap<VodAddress, Integer> map;
int[][] neighbors;
SummaryStatistics inStats, outStats;
int diameter = 0, infinitePathCount = 0;
double avgPathLength = 0, avgIn = 0, avgOut = 0, avgClustering = 0,
utilitySetNbChange=0, upperSetNbChange=0,nbCycles=0;
double minIn = n, maxIn = 0;
public GraphUtil(TreeMap<VodAddress, VodNeighbors> alivePeers) {
super();
n = alivePeers.size();
m = new byte[n][n];
dist = new int[n][n];
inDegree = new double[n];
outDegree = new int[n];
clustering = new double[n];
a = new VodAddress[n];
map = new HashMap<VodAddress, Integer>();
neighbors = new int[n][];
inStats = new SummaryStatistics();
outStats = new SummaryStatistics();
// map all alive nodes to a contiguous sequence of integers
{
int p = 0;
for (VodAddress address : alivePeers.keySet()) {
VodAddress src = (VodAddress) address;
utilitySetNbChange+=(alivePeers.get(src).getUtilitySetNbChange()/alivePeers.get(src).getNbCycles());
upperSetNbChange+=(alivePeers.get(src).getUpperSetNbChange()/alivePeers.get(src).getNbCycles());
nbCycles+=alivePeers.get(src).getNbCycles();
a[p] = src;
map.put(src, p);
p++;
}
}
// build adjacency matrix
int d = -1;
{
try {
for (int s = 0; s < a.length; s++) {
VodAddress src = a[s];
VodNeighbors neigh = alivePeers.get(src);
int nn = 0;
for (VodDescriptor desc : neigh.getRandomSetDescriptors()) {
VodAddress dst = desc.getVodAddress();
if (!map.containsKey(dst)) {
continue;
}
d = map.get(dst);
m[s][d] = 1;
inDegree[d]++;
outDegree[s]++;
nn++;
}
neighbors[s] = new int[nn];
nn = 0;
for (VodDescriptor desc : neigh.getRandomSetDescriptors()) {
VodAddress dst = desc.getVodAddress();
if (map.containsKey(dst)) {
neighbors[s][nn++] = map.get(dst);
}
}
}
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
// build distance matrix, clustering coefficient, average path length
// diameter and average degrees
{
for (int i = 0; i < n; i++) {
bfs(i, dist[i]);
// we compute the clustering coefficient here
int neigh[] = neighbors[i];
if (neigh.length <= 1) {
clustering[i] = 1.0;
continue;
}
int edges = 0;
for (int j = 0; j < neigh.length; j++) {
for (int k = j + 1; k < neigh.length; k++) {
if (m[neigh[j]][neigh[k]] > 0
|| m[neigh[k]][neigh[j]] > 0) {
++edges;
}
}
}
clustering[i] = ((edges * 2.0) / neigh.length)
/ (neigh.length - 1);
}
int k = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (i == j)
continue;
if (dist[i][j] == n) {
infinitePathCount++;
continue;
}
if (dist[i][j] > diameter) {
diameter = dist[i][j];
}
avgPathLength = (avgPathLength * k + dist[i][j]) / (k + 1);
k++;
}
inStats.addValue(inDegree[i]);
outStats.addValue(outDegree[i]);
// avgIn = (avgIn * i + inDegree[i]) / (i + 1);
// minIn = minIn > inDegree[i] ? inDegree[i] : minIn;
// maxIn = maxIn < inDegree[i] ? inDegree[i] : maxIn;
// avgOut = (avgOut * i + outDegree[i]) / (i + 1);
avgClustering = (avgClustering * i + clustering[i]) / (i + 1);
}
}
}
private void bfs(int v, int d[]) {
Queue<Integer> q = new LinkedList<Integer>();
for (int i = 0; i < n; i++) {
d[i] = n; // also means that the node has not been visited
}
d[v] = 0;
q.offer(v);
q.offer(0); // depth of v
while (!q.isEmpty()) {
int u = q.poll();
int du = q.poll(); // depth of u
for (int t = 0; t < neighbors[u].length; t++) {
if (d[neighbors[u][t]] == n) {
// on the first encounter, add to the queue
d[neighbors[u][t]] = du + 1;
q.offer(neighbors[u][t]);
q.offer(du + 1);
}
}
}
}
public int getInDegree(int v) {
if (v < n) {
return (int) inDegree[v];
} else {
return 0;
}
}
public int getOutDegree(int v) {
if (v < n) {
return outDegree[v];
} else {
return 0;
}
}
public double getClustering(int v) {
if (v < n) {
return clustering[v];
} else {
return 0;
}
}
public double getMinInDegree() {
// return minIn;
return inStats.getMin();
}
public double getMaxInDegree() {
// return maxIn;
return inStats.getMax();
}
public double getMeanInDegree() {
// return avgIn;
return inStats.getMean();
}
public double getInDegreeStdDev() {
// return avgIn;
return inStats.getStandardDeviation();
}
public double getMeanOutDegree() {
// return avgOut;
return outStats.getMean();
}
public double getMeanClusteringCoefficient() {
return avgClustering;
}
public double getMeanPathLength() {
return avgPathLength;
}
public int getDiameter() {
return diameter;
}
public SummaryStatistics getInStats() {
return inStats;
}
public SummaryStatistics getOutStats() {
return outStats;
}
public int getNetworkSize() {
return n;
}
public double[] getInDegrees() {
return inDegree;
}
public int getNodeIndexByAddress(VodAddress address) {
return map.get(address);
}
public int getInfinitePathCount() {
return infinitePathCount;
}
public double getAvgUpperSetNbChange() {
return upperSetNbChange/n;
}
public double getAvgUtilitySetNbChange() {
return utilitySetNbChange/n;
}
}