package uk.ac.rhul.cs.cl1.quality;
import uk.ac.rhul.cs.cl1.MutableNodeSet;
import uk.ac.rhul.cs.cl1.NodeSet;
/**
* Calculates the cohesiveness measure of a nodeset.
*
* The cohesiveness of a {@link uk.ac.rhul.cs.cl1.NodeSet} is defined as the total internal weight
* of the nodeset divided by the sum of the total internal and boundary weight
* of the nodeset.
*
* Optionally, the user may also specify a penalty value for each node. If the
* penalty is nonzero, it is assumed that each node in the nodeset (and also the
* ones to be added) has an extra boundary weight equal to the value of the
* penalty. This can be used to account for situations when the dataset is noisy;
* in this case, the fact that an external boundary node of a nodeset has a single
* boundary edge towards the nodeset and no other (completely external) edges does
* not necessarily mean that the node should belong to the nodeset; it may happen
* that the node has more external connections, which are not present in the dataset
* due to noise. Therefore, the addition of such nodes is feasible only if the
* connections to the nodeset are strong enough to counterbalance the effect of the
* penalty.
*
* @author tamas
*/
public class CohesivenessFunction implements QualityFunction {
/**
* Penalty value associated with each node.
*/
double penalty = 0.0;
/**
* Constructs a new cohesiveness function instance with no penalty.
*/
public CohesivenessFunction() {
this(0.0);
}
/**
* Constructs a new cohesiveness function instance.
*
* @param penalty the penalty value associated with each internal node.
*/
public CohesivenessFunction(double penalty) {
this.penalty = penalty;
}
/**
* Calculates the cohesiveness of a nodeset.
*
* @param nodeSet the nodeset for which we need the cohesiveness
* @return the cohesiveness
*/
public double calculate(NodeSet nodeSet) {
double num, den;
num = nodeSet.totalInternalEdgeWeight;
den = nodeSet.totalInternalEdgeWeight + nodeSet.totalBoundaryEdgeWeight +
nodeSet.size() * penalty;
return num/den;
}
/**
* Returns the addition affinity of a node to a mutable nodeset
*
* The addition affinity of an external node is defined as the value of the
* quality function when the nodeset is augmented by the given node.
*
* @param nodeSet the nodeset being checked
* @param index the index of the node being added to the nodeset
* @precondition the node is not in the set
*/
public double getAdditionAffinity(MutableNodeSet nodeSet, int index) {
double num, den;
num = nodeSet.totalInternalEdgeWeight + nodeSet.inWeights[index];
den = nodeSet.totalInternalEdgeWeight + nodeSet.totalBoundaryEdgeWeight +
(nodeSet.totalWeights[index] - nodeSet.inWeights[index]) +
(nodeSet.size() + 1) * penalty;
return num/den;
}
/**
* Returns the removal affinity of a node to this nodeset
*
* The removal affinity of an internal node is defined as the value of the quality
* function when the node is removed from the nodeset.
*
* @param nodeSet the nodeset being checked
* @param index the index of the node
* @precondition the node is already in the set
*/
public double getRemovalAffinity(MutableNodeSet nodeSet, int index) {
double num, den;
num = nodeSet.totalInternalEdgeWeight - nodeSet.inWeights[index];
den = nodeSet.totalInternalEdgeWeight + nodeSet.totalBoundaryEdgeWeight -
(nodeSet.totalWeights[index] - nodeSet.inWeights[index]) +
(nodeSet.size() - 1) * penalty;
return num/den;
}
}