package i5.las2peer.services.ocd.metrics; import i5.las2peer.services.ocd.graphs.Cover; import i5.las2peer.services.ocd.graphs.CustomGraph; import i5.las2peer.services.ocd.graphs.GraphType; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.la4j.matrix.Matrix; import y.base.Edge; import y.base.EdgeCursor; import y.base.Node; /* * @author YLi */ public class SignedModularityMetric implements StatisticalMeasure { public SignedModularityMetric() { } @Override public void setParameters(Map<String, String> parameters) { } @Override public Map<String, String> getParameters() { return new HashMap<String, String>(); } @Override public Set<GraphType> compatibleGraphTypes() { Set<GraphType> compatibleTypes = new HashSet<GraphType>(); compatibleTypes.add(GraphType.DIRECTED); compatibleTypes.add(GraphType.WEIGHTED); compatibleTypes.add(GraphType.NEGATIVE_WEIGHTS); return compatibleTypes; } public double measure(Cover cover) throws InterruptedException { double metricValue = 0; CustomGraph graph = cover.getGraph(); double positiveWeightSum = 0; double negativeWeightSum = 0; /* * calculate the effective number of edges */ EdgeCursor edges = graph.edges(); Edge edge; while (edges.ok()) { if (Thread.interrupted()) { throw new InterruptedException(); } edge = edges.edge(); double edgeWeight = graph.getEdgeWeight(edge); if (edgeWeight > 0) { positiveWeightSum += edgeWeight; } else if (edgeWeight < 0) { negativeWeightSum += Math.abs(edgeWeight); } int sameCommunity = examCommunityIdentity(cover, edge.source(), edge.target()); if (sameCommunity > 1) { if (edgeWeight > 0) { positiveWeightSum = positiveWeightSum + edgeWeight * (sameCommunity - 1); } else { negativeWeightSum = negativeWeightSum - edgeWeight * (sameCommunity - 1); } } edges.next(); } /* * Another round of iteration must be carried out, as the effective * number of edges has to be certain for calculation. */ EdgeCursor edgesMod = graph.edges(); Edge edgeMod; while (edgesMod.ok()) { if (Thread.interrupted()) { throw new InterruptedException(); } edgeMod = edgesMod.edge(); double edgeWeight = graph.getEdgeWeight(edgeMod); int sameCommunity = examCommunityIdentity(cover, edgeMod.source(), edgeMod.target()); metricValue += sameCommunity * (edgeWeight - (graph.getPositiveInDegree(edgeMod.source()) + graph.getPositiveOutDegree(edgeMod.source())) * (graph.getPositiveOutDegree(edgeMod.target()) + graph.getPositiveInDegree(edgeMod.target())) / (2 * positiveWeightSum) + (graph.getNegativeInDegree(edgeMod.source()) + graph.getNegativeOutDegree(edgeMod.source())) * (graph.getNegativeInDegree(edgeMod.target()) + graph.getNegativeOutDegree(edgeMod.target())) / (2 * negativeWeightSum)); edgesMod.next(); } return metricValue / (2 * positiveWeightSum + 2 * negativeWeightSum); } /* * Returns the number of communities node A nd node B both belong to. * * @param cover The cover being measured. * * @param sourceNode The source node of the edge. * * @param targetNode The target node of the edge. * * @return The number of communities node A and node B both belong to. * */ private int examCommunityIdentity(Cover cover, Node nodeA, Node nodeB) throws InterruptedException { int sameCommunity = 0; Matrix membershipMatrix = cover.getMemberships(); int communityCount = cover.communityCount(); for (int i = 0; i < communityCount; i++) { if (membershipMatrix.get(nodeA.index(), i) > 0 & membershipMatrix.get(nodeB.index(), i) > 0) { sameCommunity++; } } return sameCommunity; } }