package i5.las2peer.services.ocd.metrics;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.la4j.matrix.Matrix;
import i5.las2peer.services.ocd.graphs.Cover;
import i5.las2peer.services.ocd.graphs.CustomGraph;
import i5.las2peer.services.ocd.graphs.GraphType;
import y.base.Edge;
import y.base.EdgeCursor;
/*
* @author YLi
*/
public class FrustrationMetric implements StatisticalMeasure {
/*
* Parameter for weighting between negative edges within communities and
* positive edges between communities.
*/
private double weightingParameter = 0.5d;
@Override
public void setParameters(Map<String, String> parameters) {
if (parameters.containsKey(WEIGHT_NAME)) {
weightingParameter = Double.parseDouble(parameters.get(WEIGHT_NAME));
parameters.remove(WEIGHT_NAME);
if (weightingParameter < 0 || weightingParameter > 1) {
throw new IllegalArgumentException();
}
}
if (parameters.size() > 0) {
throw new IllegalArgumentException();
}
}
@Override
public Map<String, String> getParameters() {
Map<String, String> parameters = new HashMap<String, String>();
parameters.put(WEIGHT_NAME, Double.toString(weightingParameter));
return parameters;
}
@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;
}
/**
* Creates a standardized instance of the frustration metric.
*/
public FrustrationMetric() {
}
/**
* Creates an instance of the frustration metric with a predefined
* parameter.
*/
public FrustrationMetric(double weightingParameter) {
this.weightingParameter = weightingParameter;
}
protected final String WEIGHT_NAME = "weightingParameter";
public double measure(Cover cover) throws InterruptedException {
CustomGraph graph = cover.getGraph();
Matrix membership = cover.getMemberships();
int communityCount = cover.communityCount();
int intraEdgeNegative = 0;
int interEdgePositive = 0;
int effectiveEdges = graph.edgeCount();
EdgeCursor edges = graph.edges();
Edge edge;
while (edges.ok()) {
if (Thread.interrupted()) {
throw new InterruptedException();
}
edge = edges.edge();
int belongingToSameCommunity = 0;
int belongingToDiffCommunity = 0;
for (int i = 0; i < communityCount; i++) {
if (membership.get(edge.source().index(), i) * membership.get(edge.target().index(), i) != 0.0) {
belongingToSameCommunity++;
} else if (membership.get(edge.source().index(), i) * membership.get(edge.target().index(), i) == 0.0
& (membership.get(edge.source().index(), i)
+ membership.get(edge.target().index(), i)) != 0.0) {
belongingToDiffCommunity++;
}
}
/*
* If the nodes of an edge belong to more than one community the
* edge will be counted more than once when calculating effective
* edges
*/
if (belongingToSameCommunity > 0) {
effectiveEdges += belongingToSameCommunity - 1;
}
if (graph.getEdgeWeight(edge) < 0) {
intraEdgeNegative += belongingToSameCommunity;
} else if (graph.getEdgeWeight(edge) > 0 & belongingToSameCommunity == 0 & belongingToDiffCommunity != 0) {
/*
* if the concerned two nodes are in no common community,the
* weight of the edge connecting these nodes should never be
* positive
*/
interEdgePositive++;
}
edges.next();
}
return (weightingParameter * intraEdgeNegative + (1 - weightingParameter) * interEdgePositive) / effectiveEdges;
}
}