| 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" |