| Prev - Next - Down | SDMetrics - the UML design measurement tool |
The symmetric difference of two sets A and B is the set of elements contained in either A or B, but not both. For regular sets, we could express the symmetric difference in terms of the existing set operations as (A+B)-(A*B) (i.e., the union of the sets without the intersection of the sets, see Section 8.5.3 "Set Expressions"). For multisets, however, we must take the cardinality of elements into account: the cardinality of an element in the symmetric difference is the absolute difference of the cardinality of the element in sets A and B. For example, if the cardinality of element e is five in set A and three in set B, the cardinality of element e in the symmetric difference is two. The formula (A+B)-(A*B) would yield cardinality (5+3)-3=5 for element e and therefore cannot be used for multisets.
The following implementation handles both regular and multisets.
packacke com.acme;
import java.util.Collection;
import java.util.Iterator;
import com.sdmetrics.math.ExpressionNode;
import com.sdmetrics.metrics.MetricTools;
import com.sdmetrics.metrics.SDMetricsException;
import com.sdmetrics.metrics.SetOperation;
import com.sdmetrics.metrics.Variables;
import com.sdmetrics.model.ModelElement;
01 public class SetOperationSymmDiff extends SetOperation {
@Override
02 public Collection<?> calculateValue(ModelElement element,
ExpressionNode node, Variables vars) throws SDMetricsException {
03 Collection<?> left = evalSetExpression(element, node.getOperand(0),
vars);
04 Collection<?> right = evalSetExpression(element, node.getOperand(1),
vars);
05 boolean isMultiSet = MetricTools.isMultiSet(right)
|| MetricTools.isMultiSet(left);
06 Collection<?> result = MetricTools.createHashSet(isMultiSet);
// process elements from the first set
07 Iterator<?> it = MetricTools.getFlatIterator(left);
08 while (it.hasNext()) {
09 processElement(it.next(), result, left, right);
}
// process additional elements from the second set
10 it = MetricTools.getFlatIterator(right);
11 while (it.hasNext()) {
12 Object o = it.next();
13 if (!left.contains(o)) {
14 processElement(o, result, left, right);
}
}
15 return result;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
16 private void processElement(Object o, Collection col,
Collection<?> left, Collection<?> right) {
17 int leftCount = MetricTools.elementCount(left, o);
18 int rightCount = MetricTools.elementCount(right, o);
19 int count = Math.abs(leftCount - rightCount);
20 for (int i = 0; i < count; i++)
21 col.add(o);
}
}
Once more, we discuss the salient features of this implementation, line by line.
<setoperationdefinition name="symmdiff" class="com.acme.SetOperationSymmDiff" />Again, we deploy the class file of the class in the "bin" folder of our SDMetrics installation (path com/acme/SetOperationSymmDiff.class). After that, we can write set expressions using the new function. For example:
<metric name="FooBar" domain="package"> <compoundmetric term="size(symmdiff(FooBarClassesSet, FooBazClassesSet))" /> </metric>
| Prev | Up | Next |
| Section 9.5 "Scalar Functions" | Contents | Section 9.7 "Metrics Engine Extension Guidelines" |