/* Copyright 2010 by Sean Luke and George Mason University Licensed under the Academic Free License version 3.0 See the file "LICENSE" for more information */ package sim.field.network.stats.actorcentrality; import sim.field.network.stats.*; import sim.field.network.*; import sim.util.mantissa.linalg.*; import java.util.*; /** * Actor Information Centrality (Wasserman and Faust, page 195 for undirected and page 201 for * directed graphs). * * <p>Note that this works for both dichotomous and valued relations (i.e. hops and weights). * * <p>It requires a matrix inversion that should be reused by all <code>getMeasure()</code> calls. * * @author Gabriel Catalin Balan */ public class InformationCentrality extends NodeIndex { final double normalizationDenominator; final double[] ci; public InformationCentrality(final Network network, final EdgeMetric weightFn) { super(network); int n = network.allNodes.numObjs; //imagine I move all isolated nodes at the end, //so the non isolated nodes are compact, so I can go ahead with the matrix inversion. //but when I compute the final stats I want the old order. int[] indirect = new int[n]; for(int i=0;i<n;i++) indirect[i]=i; int isolated = 0; Iterator nodeIO = network.indexOutInHash.values().iterator(); for(int k=0;k<n;k++) { Network.IndexOutIn ioi = (Network.IndexOutIn)nodeIO.next(); int index= ioi.index; if(ioi.out == null) { isolated++; indirect[n-isolated] = indirect[index]; indirect[index] = n-isolated; } } int nonIsolatedN = n -isolated; GeneralSquareMatrix a = new GeneralSquareMatrix(nonIsolatedN); //pseudo-adjacency matrix formed by replacing the diagonal of 1-X // with one plus each actor's degree for(int i=0;i<nonIsolatedN;i++) for(int j=0;j<nonIsolatedN;j++) a.setElement(i, j, 1); //TODO too many functioncalls nodeIO = network.indexOutInHash.values().iterator(); for(int k=0;k<n;k++) { Network.IndexOutIn ioi = (Network.IndexOutIn)nodeIO.next(); int index= ioi.index; if(ioi.out == null) continue; int outDegree = ioi.out.numObjs; int indirectIndex = indirect[index]; Object nodeObj = network.allNodes.objs[ioi.index]; for(int i=0;i<outDegree;i++) { Edge e = (Edge)ioi.out.objs[i]; // this is getNodeIndex without the function call int j = ((Network.IndexOutIn)network.indexOutInHash.get(e.getOtherNode(nodeObj))).index; a.setElement(indirectIndex, indirect[j], 1-weightFn.getWeight(e)); // multigraphs will have edges ignored here } //there better not be self loops a.setElement(indirectIndex, indirectIndex, 1+outDegree); } Matrix c; double R=0, T=0; ci = new double[n]; //TODO maybe we could find a in-place matrix multiplication procedure try { c = a.getInverse(0.0); for(int i=0;i<nonIsolatedN;i++) { T+=c.getElement(i, i); R+=c.getElement(0, i); } for(int i=0;i<n;i++) { int indirectI = indirect[i]; ci[i]= (indirectI>=nonIsolatedN)? Double.POSITIVE_INFINITY : c.getElement(indirectI, indirectI); //I want the ci values of the isolated nodes to be 0, so 1 /positive infinity does the trick } }catch(SingularMatrixException ex) { throw new RuntimeException("Singular Matrix"); } double k = (T-2*R)/nonIsolatedN; double sum = 0; for(int i=0;i<n;i++) { ci[i]=1d/(ci[i]+k); sum+=ci[i]; } normalizationDenominator = sum; } public double getValue(Object node) { return ci[network.getNodeIndex(node)]; } public double getValue(int nodeIndex) { return ci[nodeIndex]; } /** * Sum_{i} getMeasure(i) */ public double getMaxValue(){return normalizationDenominator;} }