package edu.nd.nina.alg; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.Vector; import java.util.logging.Logger; import edu.nd.nina.DirectedGraph; import edu.nd.nina.Graph; import edu.nd.nina.Graphs; import edu.nd.nina.UndirectedGraph; import edu.nd.nina.graph.Multigraph; import edu.nd.nina.math.Moment; import edu.nd.nina.math.Randoms; import edu.nd.nina.structs.Pair; import edu.nd.nina.structs.Triple; /** * Statistics of a snapshot of a graph (based on gstat.h/cpp in SNAP) * * @author Tim Weninger * @date 4/17/2013 * * @param <V> * Vertex type, must extend Comparable<V> * @param <E> * Edge type */ public class CalculateStatistics<V extends Comparable<V>, E> { private static Logger logger = Logger.getLogger(CalculateStatistics.class .getName()); /** * Number of tests to do when estimating graph diameter */ private static final Integer NDiamRuns = 10; /** * Number of single values in SVD to return */ private static final Integer TakeSngVals = 100; /** * Calculate all statistics. WARNING, this can take a long time for even * moderately sized graphs * * @param graph * Single snapshot of a graph * @param wcc * true if graph is weakly connected component * @param valStatH * table of single results * @param distrStatH * table of result distributions */ public static <V extends Comparable<V>, E> void calcStats( Graph<V, E> graph, boolean wcc, Hashtable<StatVal, Float> valStatH, Hashtable<StatVal, Vector<Pair<Float, Float>>> distrStatH) { System.out.printf("GraphStatistics: G(%d, %d)\n", graph.vertexSet() .size(), graph.edgeSet().size()); long FullTm = System.currentTimeMillis(); if (!wcc) { calcBasicStat(ConnectivityInspector.getMaxWcc(graph), true, valStatH); } else { calcBasicStat(graph, false, valStatH); } // diameter calcDiameter(graph, 100, valStatH, distrStatH); // degrees calcDegreeDistribution(graph, distrStatH); // components calcConnectedComponents(graph, distrStatH); // spectral calcSpectral(graph, -1, distrStatH); // clustering coefficient calcClusteringCoefficient(graph, valStatH); calcTriangleParticipation(graph, distrStatH); System.out.printf(" [%s]\n", System.currentTimeMillis() - FullTm); } /** * Calculates the triangle participation * * @param graph * Graph snapshot * @param distrStatH * table of result distributions */ public static <V extends Comparable<V>, E> void calcTriangleParticipation( Graph<V, E> graph, Hashtable<StatVal, Vector<Pair<Float, Float>>> distrStatH) { logger.info("Calculate Triangle Participation"); Vector<Pair<Float, Float>> triangleCountV = new Vector<Pair<Float, Float>>(); Vector<Pair<Integer, Integer>> countV = Triangles .getTriangleParticipation(graph); for (int i = 0; i < countV.size(); i++) { triangleCountV.add(new Pair<Float, Float>((float) countV.get(i).p1, (float) countV.get(i).p2)); } distrStatH.put(StatVal.gsdTriadPart, triangleCountV); } /** * Calculates the clustering coefficient of the graph * * @param graph * Graph snapshot * @param valStatH * table of result */ public static <V extends Comparable<V>, E> void calcClusteringCoefficient( Graph<V, E> graph, Hashtable<StatVal, Float> valStatH) { calcClusteringCoefficient(graph, -1, valStatH); } /** * Calculates the clustering coefficient of the graph * * @param graph * Graph snapshot * @param sampleNodes * Number of nodes to Sample, -1 to process all nodes * @param valStatH * table of result */ public static <V extends Comparable<V>, E> void calcClusteringCoefficient( Graph<V, E> graph, int sampleNodes, Hashtable<StatVal, Float> valStatH) { Triple<Float, Integer, Integer> t = Triangles.getClusteringCoefficient( graph, sampleNodes); valStatH.put(StatVal.gsvClustCf, t.v1); valStatH.put(StatVal.gsvOpenTriads, (float) t.v3); valStatH.put(StatVal.gsvClosedTriads, (float) t.v2); } /** * Calculates the spectral properties of the graph * * @param graph * Graph snapshot * @param distrStatH * table of result distributions */ public static <V extends Comparable<V>, E> void calcSpectral( Graph<V, E> graph, int singularValues, Hashtable<StatVal, Vector<Pair<Float, Float>>> distrStatH) { if (singularValues == -1) { singularValues = TakeSngVals; } // singular values, vectors singularValues = Math.min(singularValues, graph.vertexSet().size() / 2); Vector<Float> singularValues1 = SingularValueDecomposition .getSingularValues(graph, singularValues); Collections.sort(singularValues1); Vector<Pair<Float, Float>> singularValuesV = new Vector<Pair<Float, Float>>(); for (int i = 0; i < singularValues1.size(); i++) { singularValuesV.add(new Pair<Float, Float>((float) i + 1, (float) singularValues1.get(i))); } distrStatH.put(StatVal.gsdSngVal, singularValuesV); Vector<Float> leftV = new Vector<Float>(); Vector<Float> rightV = new Vector<Float>(); SingularValueDecomposition .getSingularValuesVector(graph, leftV, rightV); Collections.sort(leftV); Collections.sort(rightV); Vector<Pair<Float, Float>> singularValuesVectorLeft = new Vector<Pair<Float, Float>>(); for (int i = 0; i < Math.min(10000, leftV.size() / 2); i++) { if (leftV.get(i) > 0) { singularValuesVectorLeft.add(new Pair<Float, Float>((float) i, leftV.get(i))); } } distrStatH.put(StatVal.gsdSngVecLeft, singularValuesVectorLeft); Vector<Pair<Float, Float>> singularValuesVectorRight = new Vector<Pair<Float, Float>>(); for (int i = 0; i < Math.min(10000, rightV.size() / 2); i++) { if (rightV.get(i) > 0) { singularValuesVectorRight.add(new Pair<Float, Float>((float) i, rightV.get(i))); } } distrStatH.put(StatVal.gsdSngVecRight, singularValuesVectorRight); } /** * Calculates the connected components * * @param graph * Graph snapshot * @param distrStatH * table of result distributions */ public static <V extends Comparable<V>, E> void calcConnectedComponents( Graph<V, E> graph, Hashtable<StatVal, Vector<Pair<Float, Float>>> distrStatH) { logger.info("Calculate Weakly Connected Component"); distrStatH.put(StatVal.gsdWcc, ConnectivityInspector.getWccSizeCount(graph)); if (graph instanceof DirectedGraph) { logger.info("Calculate Strongly Connected Component"); distrStatH.put(StatVal.gsdWcc, StrongConnectivityInspector .getSccSizeCnt((DirectedGraph<V, E>) graph)); } } /** * Calculates the degree distribution * * @param graph * Graph snapshot * @param distrStatH * table of result distributions */ public static <V extends Comparable<V>, E> void calcDegreeDistribution( Graph<V, E> graph, Hashtable<StatVal, Vector<Pair<Float, Float>>> distrStatH) { // degree distribution logger.info("Count Indegree"); Vector<Pair<Float, Float>> indegreeV = countIndegree(graph); distrStatH.put(StatVal.gsdInDeg, indegreeV); logger.info("Count Outdegree"); Vector<Pair<Float, Float>> outdegreeV = countOutdegree(graph); distrStatH.put(StatVal.gsdOutDeg, outdegreeV); } /** * Calculates the degree distribution * * @param graph * Graph snapshot * @param distrStatH * table of result distributions */ public static <V extends Comparable<V>, E> void calcDegreeDistribution( Graph<V, E> graph, Hashtable<String, Vector<Pair<Float, Float>>> distrStatH, Set<Class<?>> types) { int i = 0; for (Class<?> t1 : types) { int j = 0; for (Class<?> t2 : types) { if (graph instanceof UndirectedGraph) { if (i < j) break; } logger.info("Count Indegree"); Vector<Pair<Float, Float>> indegreeV = countIndegree(graph, t1, t2); distrStatH.put("inDegree: " + t1.getSimpleName() + "-" + t2.getSimpleName(), indegreeV); logger.info("Count Outdegree"); Vector<Pair<Float, Float>> outdegreeV = countOutdegree(graph, t1, t2); distrStatH.put("outDegree: " + t1.getSimpleName() + "-" + t2.getSimpleName(), outdegreeV); } } } /** * Calculate graph diameter * * @param graph * Graph snapshot * @param numTestNodes * Number of nodes to test diameter for, -1 to test all nodes * @param statValH * table of result * @param distrStatH * table of result distributions */ public static <V extends Comparable<V>, E> void calcDiameter( Graph<V, E> graph, int numTestNodes, Hashtable<StatVal, Float> statValH, Hashtable<StatVal, Vector<Pair<Float, Float>>> distrStatH) { logger.info("Calculate Diameter"); Moment effectiveDiameterMom = new Moment(); Moment fullDiameterMom = new Moment(); Moment averageDiameterMom = new Moment(); Map<V, Integer> hops = null; for (int r = 0; r < NDiamRuns; r++) { double[] effectiveDiameter = { 0d }; int[] fullDiameter = { 0 }; double[] averageDiameter = { 0d }; logger.info("Diameter run: " + r); hops = BreadthFirstSearch.getBfsEffDiam(graph, numTestNodes, effectiveDiameter, fullDiameter, averageDiameter); effectiveDiameterMom.add((float) effectiveDiameter[0]); fullDiameterMom.add((float) fullDiameter[0]); averageDiameterMom.add((float) averageDiameter[0]); } effectiveDiameterMom.def(); fullDiameterMom.def(); averageDiameterMom.def(); statValH.put(StatVal.gsvFullDiam, fullDiameterMom.getMax()); statValH.put(StatVal.gsvFullDiamDev, fullDiameterMom.getSDev()); statValH.put(StatVal.gsvEffDiam, effectiveDiameterMom.getMean()); statValH.put(StatVal.gsvEffDiamDev, effectiveDiameterMom.getSDev()); statValH.put(StatVal.gsvAvgDiam, averageDiameterMom.getMean()); statValH.put(StatVal.gsvAvgDiamDev, averageDiameterMom.getSDev()); Hashtable<Float, Float> hopCountH = new Hashtable<Float, Float>(); Vector<Pair<Float, Float>> hopCountV = new Vector<Pair<Float, Float>>(); for (Integer e : hops.values()) { if (!hopCountH.containsKey(Float.valueOf(e))) { hopCountH.put(Float.valueOf(e), 1f); } else { hopCountH.put((float) e, hopCountH.get(Float.valueOf(e)) + 1); } } for (Entry<Float, Float> e : hopCountH.entrySet()) { hopCountV.add(new Pair<Float, Float>(e.getKey(), e.getValue())); } Collections.sort(hopCountV); distrStatH.put(StatVal.gsdHops, hopCountV); } /** * Calculate basic graph statistics * * @param graph * Graph snapshot * @param isMaxWcc * true if the graph is a WCC * @param valStatH * table of results */ public static <V extends Comparable<V>, E> void calcBasicStat( Graph<V, E> graph, boolean isMaxWcc, Hashtable<String, Float> valStatH, Set<Class<?>> types) { int i = 0; for (Class<?> t1 : types) { int j = 0; for (Class<?> t2 : types) { if (graph instanceof UndirectedGraph) { if (i < j) break; } logger.info("Calculate Basic Statistics: " + t1.getSimpleName() + " - " + t2.getSimpleName()); if (!isMaxWcc) { final int size = graph.getAllMatchingType(t1).size(); valStatH.put("nodes: " + t1.getSimpleName() + "-" + t2.getSimpleName(), Float.valueOf(size)); valStatH.put("zeroNodes: " + t1.getSimpleName() + "-" + t2.getSimpleName(), Float.valueOf(countNodesOfDegree(graph, 0, t1, t2))); valStatH.put("nonZeroNodes: " + t1.getSimpleName() + "-" + t2.getSimpleName(), size - valStatH.get("zeroNodes: " + t1.getSimpleName() + "-" + t2.getSimpleName())); valStatH.put( "srcNodes: " + t1.getSimpleName() + "-" + t2.getSimpleName(), (float) (size - countNodesOfOutdegree(graph, 0, t1, t2))); valStatH.put( "dstNodes: " + t1.getSimpleName() + "-" + t2.getSimpleName(), (float) (size - countNodesOfIndegree(graph, 0, t1, t2))); valStatH.put("edges: " + t1.getSimpleName() + "-" + t2.getSimpleName(), (float) countEdges(graph, t1, t2)); if (!(graph instanceof Multigraph)) { valStatH.put("uniqEdges: " + t1.getSimpleName() + "-" + t2.getSimpleName(), valStatH.get("edges: " + t1.getSimpleName() + "-" + t2.getSimpleName())); } else { valStatH.put("uniqEdges: " + t1.getSimpleName() + "-" + t2.getSimpleName(), (float) countUniqueEdges(graph, t1, t2)); } if (graph instanceof DirectedGraph) { valStatH.put( "bidiredges: " + t1 + "-" + t2, (float) countUniqueBidirectionalEdges(graph, t1, t2)); } else { if ((graph instanceof Multigraph)) { valStatH.put("uniqEdges: " + t1 + "-" + t2, (float) countUniqueEdges(graph, t1, t2)); } } } else { logger.info("Weakly Connected Component"); final int size = graph.vertexSet().size(); valStatH.put("wccNodes: " + t1 + "-" + t2, Float.valueOf(size)); valStatH.put("wccZeroNodes: " + t1 + "-" + t2, Float.valueOf(countNodesOfDegree(graph, 0))); valStatH.put("wccNonZeroNodes: " + t1 + "-" + t2, size - valStatH.get("zeroNodes")); valStatH.put("wccSrcNodes: " + t1 + "-" + t2, (float) (size - countNodesOfOutdegree(graph, 0))); valStatH.put("wccDstNodes: " + t1 + "-" + t2, (float) (size - countNodesOfIndegree(graph, 0))); valStatH.put("wccEdges: " + t1 + "-" + t2, (float) graph .edgeSet().size()); if (!(graph instanceof Multigraph)) { valStatH.put("wccUniqEdges: " + t1 + "-" + t2, (float) graph.edgeSet().size()); } else { valStatH.put("wccUniqEdges: " + t1 + "-" + t2, (float) countUniqueEdges(graph)); } if (graph instanceof DirectedGraph) { valStatH.put("wccBidiredges: " + t1 + "-" + t2, (float) countUniqueBidirectionalEdges(graph)); } else { if ((graph instanceof Multigraph)) { valStatH.put("wccUniqEdges: " + t1 + "-" + t2, (float) countUniqueEdges(graph)); } } } } } } /** * Calculate basic graph statistics * * @param graph * Graph snapshot * @param isMaxWcc * true if the graph is a WCC * @param valStatH * table of results */ public static <V extends Comparable<V>, E> void calcBasicStat( Graph<V, E> graph, boolean isMaxWcc, Hashtable<StatVal, Float> valStatH) { logger.info("Calculate Basic Statistics"); if (!isMaxWcc) { final int size = graph.vertexSet().size(); valStatH.put(StatVal.gsvNodes, Float.valueOf(size)); valStatH.put(StatVal.gsvZeroNodes, Float.valueOf(countNodesOfDegree(graph, 0))); valStatH.put(StatVal.gsvNonZNodes, size - valStatH.get(StatVal.gsvZeroNodes)); valStatH.put(StatVal.gsvSrcNodes, (float) (size - countNodesOfOutdegree(graph, 0))); valStatH.put(StatVal.gsvDstNodes, (float) (size - countNodesOfIndegree(graph, 0))); valStatH.put(StatVal.gsvEdges, (float) graph.edgeSet().size()); if (!(graph instanceof Multigraph)) { valStatH.put(StatVal.gsvUniqEdges, (float) graph.edgeSet() .size()); } else { valStatH.put(StatVal.gsvUniqEdges, (float) countUniqueEdges(graph)); } if (graph instanceof DirectedGraph) { valStatH.put(StatVal.gsvBiDirEdges, (float) countUniqueBidirectionalEdges(graph)); } else { valStatH.put(StatVal.gsvUniqEdges, (float) countUniqueEdges(graph)); } } else { logger.info("Weakly Connected Component"); final int size = graph.vertexSet().size(); valStatH.put(StatVal.gsvWccNodes, (float) size); valStatH.put(StatVal.gsvWccSrcNodes, (float) (size - countNodesOfOutdegree(graph, 0))); valStatH.put(StatVal.gsvWccDstNodes, (float) (size - countNodesOfIndegree(graph, 0))); valStatH.put(StatVal.gsvWccEdges, (float) graph.edgeSet().size()); if (!(graph instanceof Multigraph)) { valStatH.put(StatVal.gsvWccUniqEdges, (float) graph.edgeSet() .size()); } else { valStatH.put(StatVal.gsvWccUniqEdges, (float) countUniqueEdges(graph)); } if (graph instanceof DirectedGraph) { valStatH.put(StatVal.gsvWccBiDirEdges, (float) countUniqueBidirectionalEdges(graph)); } else { valStatH.put(StatVal.gsvUniqEdges, valStatH.get(StatVal.gsvWccEdges)); } } } /** * Calculates a distribution of jaccard coefficients for all pairs that * share a node * * @param graph * @return */ public static <V extends Comparable<V>, E> void calcJaccardCoefficient( Graph<V, E> graph, int sampleNodes, Class<?> startType, Hashtable<StatVal, Vector<Pair<Float, Float>>> distrStatH) { Vector<Pair<Float, Float>> x = new Vector<Pair<Float, Float>>(); Randoms r = new Randoms(); List<Pair<V, V>> newEdges = new ArrayList<Pair<V, V>>(); // add random edges List<V> nodes = new ArrayList<V>(graph.vertexSet()); Collections.shuffle(nodes); for (int i = 0, j=0; i < sampleNodes && j<nodes.size(); j++) { V v1 = nodes.get(j); if(!v1.getClass().equals(startType)){ continue; } List<V> n = Graphs.neighborListOf(graph, v1); if(n.size() == 0) continue; V v2 = n.get(r.next(n.size())); n = Graphs.neighborListOf(graph, v2); if(n.remove(v1) != true) { assert(false); } if(n.size() == 0) continue; V v3 = n.get(r.next(n.size())); newEdges.add(new Pair<V, V>(v1, v3)); i++; } //jacVals needs to be decreasing order float[] jacVals = { 0.512f, 0.256f, 0.128f, 0.064f, 0.032f, 0.016f, 0.008f, 0.004f, 0.002f, 0.001f }; for (float f : jacVals) { Float jccf = calcJaccardCoefficient(graph, f, newEdges); x.add(new Pair<Float, Float>(f, jccf)); } distrStatH.put(StatVal.gsdJacCoef, x); } /** * Calculates a distribution of jaccard coefficients for all pairs that * share a node * * @param graph * @return */ public static <V extends Comparable<V>, E> Float calcJaccardCoefficient( Graph<V, E> graph, Float cutoff, List<Pair<V, V>> edges) { float i=0; for (Pair<V, V> p : edges) { float jaccard = calcJaccardCoefficient(graph, p.p1, p.p2); if (jaccard > cutoff) { i++; } } return i/(float)edges.size(); } public static <V extends Comparable<V>, E> void calcJaccardAssortativity( Graph<V, E> graph, int sampleNodes, Class<?> startType, Hashtable<StatVal, Vector<Pair<Float, Float>>> distrStatH) { Vector<Pair<Float, Float>> x = new Vector<Pair<Float, Float>>(); Randoms r = new Randoms(); List<Pair<V, V>> newEdges = new ArrayList<Pair<V, V>>(); // add random edges List<V> nodes = new ArrayList<V>(graph.vertexSet()); Collections.shuffle(nodes); for (int i = 0, j=0; i < sampleNodes && j<nodes.size(); j++) { V v1 = nodes.get(j); if(!v1.getClass().equals(startType)){ continue; } List<V> n = Graphs.neighborListOf(graph, v1); if(n.size() == 0) continue; V v2 = n.get(r.next(n.size())); n = Graphs.neighborListOf(graph, v2); if(n.remove(v1) != true) { assert(false); } if(n.size() == 0) continue; V v3 = n.get(r.next(n.size())); newEdges.add(new Pair<V, V>(v1, v3)); i++; } //jacVals needs to be decreasing order float[] jacVals = { 0.512f, 0.256f, 0.128f, 0.064f, 0.032f, 0.016f, 0.008f, 0.004f, 0.002f, 0.001f }; for (float f : jacVals) { Float jccf = calcJaccardAssortativity(graph, f, newEdges); x.add(new Pair<Float, Float>(f, jccf)); } distrStatH.put(StatVal.gsdJacCoef, x); } /** * Calculates assortativity with edges parameter and jaccard cutoff * * @param graph * @return */ public static <V extends Comparable<V>, E> Float calcJaccardAssortativity( Graph<V, E> graph, Float cutoff, List<Pair<V, V>> edges) { float m = graph.edgeSet().size(); float numerator = 0f; float denominator = 0f; for (Pair<V, V> p : edges) { float jaccard = calcJaccardCoefficient(graph, p.p1, p.p2); if (jaccard > cutoff) { float a_ij = 1f; // edge exists float d_i = graph.edgesOf(p.p1).size(); float d_j = graph.edgesOf(p.p2).size(); float f_ij = 1f; // some measure/weight just 1 for now numerator += (a_ij - ((d_i * d_j) / (2f * m))) * f_ij; float delta_ij = 1; //edge exists denominator += (d_i*delta_ij - ((d_i*d_j)/(2f*m))) * f_ij; } } return numerator/denominator; } /** * Calculates assortativity all edges * * @param graph * @return */ public static <V extends Comparable<V>, E> Float calcAssortativity( Graph<V, E> graph, int sampleNodes) { float m = graph.edgeSet().size(); float numerator = 0f; for (E e : graph.edgeSet()) { float a_ij = 1f; // edge exists float d_i = graph.edgesOf(graph.getEdgeSource(e)).size(); float d_j = graph.edgesOf(graph.getEdgeTarget(e)).size(); float f_ij = 1f; // some measure/weight just 1 for now numerator += (a_ij - ((d_i*d_j)/(2f*m))) * f_ij; } float denominator = 0f; for (E e : graph.edgeSet()) { float d_i = graph.edgesOf(graph.getEdgeSource(e)).size(); float delta_ij = 1; //edge exists float d_j = graph.edgesOf(graph.getEdgeTarget(e)).size(); float f_ij = 1f; // some measure/weight just 1 for now denominator += (d_i*delta_ij - ((d_i*d_j)/(2f*m))) * f_ij; } return numerator/denominator; } public static <V extends Comparable<V>, E> Float calcJaccardCoefficient(Graph<V,E> graph, V v1, V v2){ Set<V> s = new HashSet<V>(); List<V> n1 = Graphs.neighborListOf(graph, v1); List<V> n2 = Graphs.neighborListOf(graph, v2); s.addAll(n1); float union = s.size(); float intersection = 0f; for(V v : n2){ if(s.contains(v)){ intersection++; }else{ union++; } } return intersection / union; } /** * Counts unique bidirectional edges: u->v && u<-v * * @param graph * Graph snapshot * @return count */ public static <V extends Comparable<V>, E> int countUniqueBidirectionalEdges( Graph<V, E> graph) { if (!(graph instanceof DirectedGraph)) { // then every edge is bi-directional return countUniqueEdges((UndirectedGraph<V, E>) graph); } DirectedGraph<V, E> dg = (DirectedGraph<V, E>) graph; int cnt = 0; for (V v : dg.vertexSet()) { for (E e : dg.outgoingEdgesOf(v)) { final V t = graph.getEdgeTarget(e); if (dg.containsEdge(t, v)) { cnt++; } } } return cnt; } /** * Counts unique bidirectional edges: u->v && u<-v * * @param graph * Graph snapshot * @param t1 * @param t2 * @return count */ public static <V extends Comparable<V>, E> int countUniqueBidirectionalEdges( Graph<V, E> graph, Class<?> t1, Class<?> t2) { if (!(graph instanceof DirectedGraph)) { // then every edge is bi-directional return countUniqueEdges((UndirectedGraph<V, E>) graph, t1, t2); } DirectedGraph<V, E> dg = (DirectedGraph<V, E>) graph; int cnt = 0; for (V v : dg.vertexSet()) { if (v.getClass().equals(t1)) { for (V t : Graphs.successorListOf(dg, v)) { if (t.getClass().equals(t2)) { if (dg.containsEdge(t, v)) { cnt++; } } } } } return cnt; } /** * Count number of unique edges (if multigraph) * * @param graph * Graph snapshot * @return count */ public static <V extends Comparable<V>, E> int countUniqueEdges( Graph<V, E> graph) { Set<E> nbrSet = new HashSet<E>(); int count = 0; for (E e : graph.edgeSet()) { nbrSet.add(e); } count += nbrSet.size(); return count; } /** * Count number of unique edges (if multigraph) * * @param graph * Graph snapshot * @param t1 * @param t2 * @return count */ public static <V extends Comparable<V>, E> int countUniqueEdges( Graph<V, E> graph, Class<?> t1, Class<?> t2) { Set<E> nbrSet = new HashSet<E>(); int count = 0; for (E e : graph.edgeSet()) { if ((graph.getEdgeSource(e).getClass().equals(t1) && graph .getEdgeTarget(e).getClass().equals(t2)) || (graph.getEdgeSource(e).getClass().equals(t2) && graph .getEdgeTarget(e).getClass().equals(t1))) { nbrSet.add(e); } } count = nbrSet.size(); return count; } /** * Count number of unique edges (if multigraph) * * @param graph * Graph snapshot * @param t1 * @param t2 * @return count */ public static <V extends Comparable<V>, E> int countEdges( Graph<V, E> graph, Class<?> t1, Class<?> t2) { int count = 0; for (E e : graph.edgeSet()) { if ((graph.getEdgeSource(e).getClass().equals(t1) && graph .getEdgeTarget(e).getClass().equals(t2)) || (graph.getEdgeSource(e).getClass().equals(t2) && graph .getEdgeTarget(e).getClass().equals(t1))) { count++; } } return count; } /** * Count the number of nodes containing a certain indegree * * @param graph * Graph snapshot * @param indegree * indegree size * @return count */ public static <V extends Comparable<V>, E> int countNodesOfIndegree( Graph<V, E> graph, int indegree) { int cnt = 0; if (graph instanceof DirectedGraph) { for (V v : graph.vertexSet()) { if (((DirectedGraph<V, E>) graph).inDegreeOf(v) == indegree) { cnt++; } } } else { for (V v : graph.vertexSet()) { if (graph.edgesOf(v).size() == indegree) { cnt++; } } } return cnt; } /** * Count the number of nodes containing a certain outdegree * * @param graph * Graph snapshot * @param outdegree * outdegree size * @param t1 * @param t2 * @return count */ public static <V extends Comparable<V>, E> int countNodesOfIndegree( Graph<V, E> graph, int outdegree, Class<?> t1, Class<?> t2) { int count = 0; if (graph instanceof DirectedGraph) { for (V v : graph.vertexSet()) { if (v.getClass().equals(t1)) { int z = 0; for (V dst : Graphs.predecessorListOf( ((DirectedGraph<V, E>) graph), v)) { if (dst.getClass().equals(t2)) { z++; } } if (z == outdegree) { count++; } } } } else { for (V v : graph.vertexSet()) { if (v.getClass().equals(t1)) { int z = 0; for (V dst : Graphs.neighborListOf(graph, v)) { if (dst.getClass().equals(t2)) { z++; } } if (z == outdegree) { count++; } } } } return count; } /** * Count the number of nodes containing a certain outdegree * * @param graph * Graph snapshot * @param outdegree * outdegree size * @return count */ public static <V extends Comparable<V>, E> int countNodesOfOutdegree( Graph<V, E> graph, int outdegree) { int count = 0; if (graph instanceof DirectedGraph) { for (V v : graph.vertexSet()) { if (((DirectedGraph<V, E>) graph).outDegreeOf(v) == outdegree) { count++; } } } else { for (V v : graph.vertexSet()) { if (graph.edgesOf(v).size() == outdegree) { count++; } } } return count; } /** * Count the number of nodes containing a certain outdegree * * @param graph * Graph snapshot * @param outdegree * outdegree size * @param t1 * @param t2 * @return count */ public static <V extends Comparable<V>, E> int countNodesOfOutdegree( Graph<V, E> graph, int outdegree, Class<?> t1, Class<?> t2) { int count = 0; if (graph instanceof DirectedGraph) { for (V v : graph.vertexSet()) { if (v.getClass().equals(t1)) { int z = 0; for (V dst : Graphs.successorListOf( ((DirectedGraph<V, E>) graph), v)) { if (dst.getClass().equals(t2)) { z++; } } if (z == outdegree) { count++; } } } } else { for (V v : graph.vertexSet()) { if (v.getClass().equals(t1)) { int z = 0; for (V dst : Graphs.neighborListOf(graph, v)) { if (dst.getClass().equals(t2)) { z++; } } if (z == outdegree) { count++; } } } } return count; } /** * Count the number of nodes containing a certain degree * * @param graph * Graph snapshot * @param degree * degree size * @return count */ public static <V extends Comparable<V>, E> Integer countNodesOfDegree( Graph<V, E> graph, int degree) { int count = 0; for (V v : graph.vertexSet()) { if (graph.edgesOf(v).size() == degree) { count++; } } return count; } /** * Count the number of nodes containing a certain degree * * @param graph * Graph snapshot * @param degree * degree size * @param t1 * @param t2 * @return count */ public static <V extends Comparable<V>, E> Integer countNodesOfDegree( Graph<V, E> graph, int degree, Class<?> t1, Class<?> t2) { int count = 0; for (V v : graph.vertexSet()) { if (v.getClass().equals(t1)) { int z = 0; for (V dst : Graphs.neighborListOf(graph, v)) { if (dst.getClass().equals(t2)) { z++; } } if (z == degree) count++; } } return count; } /** * Count the indegree distribution of the graph * * @param graph * Graph snapshot * @return Vector<Pair<indegree, count>> */ public static <V extends Comparable<V>, E> Vector<Pair<Float, Float>> countIndegree( Graph<V, E> graph) { Vector<Pair<Float, Float>> degreeToCountV = new Vector<Pair<Float, Float>>(); Hashtable<Integer, Integer> degreeToCountH = new Hashtable<Integer, Integer>(); for (V v : graph.vertexSet()) { if (graph instanceof DirectedGraph) { DirectedGraph<V, E> dg = (DirectedGraph<V, E>) graph; if (degreeToCountH.containsKey(dg.inDegreeOf(v))) { degreeToCountH.put(dg.inDegreeOf(v), degreeToCountH.get(dg.inDegreeOf(v)) + 1); } else { degreeToCountH.put(dg.inDegreeOf(v), 1); } } else { if (degreeToCountH.containsKey(graph.edgesOf(v).size())) { degreeToCountH.put(graph.edgesOf(v).size(), degreeToCountH.get(graph.edgesOf(v).size()) + 1); } else { degreeToCountH.put(graph.edgesOf(v).size(), 1); } } } for (Entry<Integer, Integer> e : degreeToCountH.entrySet()) { degreeToCountV.add(new Pair<Float, Float>((float) e.getKey(), (float) e.getValue())); } Collections.sort(degreeToCountV); return degreeToCountV; } /** * Count the indegree distribution of the graph * * @param graph * Graph snapshot * @param t1 * @param t2 * @return Vector<Pair<indegree, count>> */ public static <V extends Comparable<V>, E> Vector<Pair<Float, Float>> countIndegree( Graph<V, E> graph, Class<?> t1, Class<?> t2) { Vector<Pair<Float, Float>> degreeToCountV = new Vector<Pair<Float, Float>>(); Hashtable<Integer, Integer> degreeToCountH = new Hashtable<Integer, Integer>(); for (V v : graph.vertexSet()) { if (!v.getClass().equals(t1)) continue; if (graph instanceof DirectedGraph) { DirectedGraph<V, E> dg = (DirectedGraph<V, E>) graph; int cnt = 0; for (V t : Graphs.predecessorListOf(dg, v)) { if (t.getClass().equals(t2)) { cnt++; } } if (degreeToCountH.containsKey(cnt)) { degreeToCountH.put(cnt, degreeToCountH.get(cnt) + 1); } else { degreeToCountH.put(cnt, 1); } } else { int cnt = 0; for (V t : Graphs.neighborListOf(graph, v)) { if (t.getClass().equals(t2)) { cnt++; } } if (degreeToCountH.containsKey(cnt)) { degreeToCountH.put(cnt, degreeToCountH.get(cnt) + 1); } else { degreeToCountH.put(cnt, 1); } } } for (Entry<Integer, Integer> e : degreeToCountH.entrySet()) { degreeToCountV.add(new Pair<Float, Float>((float) e.getKey(), (float) e.getValue())); } Collections.sort(degreeToCountV); return degreeToCountV; } /** * Count the outdegree distribution of the graph * * @param graph * Graph snapshot * @return Vector<Pair<outdegree, count>> */ public static <V extends Comparable<V>, E> Vector<Pair<Float, Float>> countOutdegree( Graph<V, E> graph) { Vector<Pair<Float, Float>> degreeToCountV = new Vector<Pair<Float, Float>>(); Hashtable<Integer, Integer> degreeToCountH = new Hashtable<Integer, Integer>(); for (V v : graph.vertexSet()) { if (graph instanceof DirectedGraph) { DirectedGraph<V, E> dg = (DirectedGraph<V, E>) graph; if (degreeToCountH.containsKey(dg.outDegreeOf(v))) { degreeToCountH.put(dg.outDegreeOf(v), degreeToCountH.get(dg.outDegreeOf(v)) + 1); } else { degreeToCountH.put(dg.outDegreeOf(v), 1); } } else { if (degreeToCountH.containsKey(graph.edgesOf(v).size())) { degreeToCountH.put(graph.edgesOf(v).size(), degreeToCountH.get(graph.edgesOf(v).size()) + 1); } else { degreeToCountH.put(graph.edgesOf(v).size(), 1); } } } for (Entry<Integer, Integer> e : degreeToCountH.entrySet()) { degreeToCountV.add(new Pair<Float, Float>((float) e.getKey(), (float) e.getValue())); } Collections.sort(degreeToCountV); return degreeToCountV; } /** * Count the indegree distribution of the graph * * @param graph * Graph snapshot * @param t1 * @param t2 * @return Vector<Pair<indegree, count>> */ public static <V extends Comparable<V>, E> Vector<Pair<Float, Float>> countOutdegree( Graph<V, E> graph, Class<?> t1, Class<?> t2) { Vector<Pair<Float, Float>> degreeToCountV = new Vector<Pair<Float, Float>>(); Hashtable<Integer, Integer> degreeToCountH = new Hashtable<Integer, Integer>(); for (V v : graph.vertexSet()) { if (!v.getClass().equals(t1)) continue; if (graph instanceof DirectedGraph) { DirectedGraph<V, E> dg = (DirectedGraph<V, E>) graph; int cnt = 0; for (V t : Graphs.successorListOf(dg, v)) { if (t.getClass().equals(t2)) { cnt++; } } if (degreeToCountH.containsKey(cnt)) { degreeToCountH.put(cnt, degreeToCountH.get(cnt) + 1); } else { degreeToCountH.put(cnt, 1); } } else { int cnt = 0; for (V t : Graphs.neighborListOf(graph, v)) { if (t.getClass().equals(t2)) { cnt++; } } if (degreeToCountH.containsKey(cnt)) { degreeToCountH.put(cnt, degreeToCountH.get(cnt) + 1); } else { degreeToCountH.put(cnt, 1); } } } for (Entry<Integer, Integer> e : degreeToCountH.entrySet()) { degreeToCountV.add(new Pair<Float, Float>((float) e.getKey(), (float) e.getValue())); } Collections.sort(degreeToCountV); return degreeToCountV; } }