/**
  * Get all objects (as representend by their IDs) in the subtree including the objects located
  * directly at this node. Note that objects can occur more than once.
  *
  * @return Iterator of String
  */
 public Collection<Object> getExampleIdsInSubtree() {
   Collection<Object> examples = new LinkedList<Object>();
   for (HierarchicalClusterNode subNode : subNodes) {
     examples.addAll(subNode.getExampleIdsInSubtree());
   }
   return examples;
 }
 public void showObject(Object object) {
   this.model.removeAllElements();
   if (object != null) {
     HierarchicalClusterNode node = (HierarchicalClusterNode) object;
     for (Object id : node.getExampleIdsInSubtree()) this.model.addElement(id);
   }
 }
 /**
  * Returns the number of objects in the subtree including the objects at the current node. Note
  * that objects can occur more than once and are counted as such. To get the number of distinct
  * objects use the getObjectsInSubtree function first and use the resulting list to calculate the
  * number of distinct objects.
  *
  * @return number of objects
  */
 public int getNumberOfExamplesInSubtree() {
   int subtreeSum = 0;
   for (HierarchicalClusterNode subNode : subNodes) {
     subtreeSum += subNode.getNumberOfExamplesInSubtree();
   }
   return subtreeSum;
 }
 public int getTotalNumberOfSubnodes() {
   if (getNumberOfSubNodes() == 0) {
     return 1;
   } else {
     int count = 0;
     for (HierarchicalClusterNode child : getSubNodes()) {
       count += child.getTotalNumberOfSubnodes();
     }
     count++;
     return count;
   }
 }
  @Override
  public void doWork() throws OperatorException {
    ExampleSet exampleSet = exampleSetInput.getData(ExampleSet.class);
    DistanceMeasure measure = measureHelper.getInitializedMeasure(exampleSet);

    // additional checks
    Tools.onlyNonMissingValues(exampleSet, getOperatorClassName(), this, new String[0]);
    Tools.checkAndCreateIds(exampleSet);

    Attribute idAttribute = exampleSet.getAttributes().getId();
    boolean idAttributeIsNominal = idAttribute.isNominal();
    DistanceMatrix matrix = new DistanceMatrix(exampleSet.size());
    Map<Integer, HierarchicalClusterNode> clusterMap =
        new HashMap<Integer, HierarchicalClusterNode>(exampleSet.size());
    int[] clusterIds = new int[exampleSet.size()];
    // filling the distance matrix
    int nextClusterId = 0;
    for (Example example1 : exampleSet) {
      checkForStop();
      clusterIds[nextClusterId] = nextClusterId;
      int y = 0;
      for (Example example2 : exampleSet) {
        if (y > nextClusterId) {
          matrix.set(nextClusterId, y, measure.calculateDistance(example1, example2));
        }
        y++;
      }
      if (idAttributeIsNominal) {
        clusterMap.put(
            nextClusterId,
            new HierarchicalClusterLeafNode(nextClusterId, example1.getValueAsString(idAttribute)));
      } else {
        clusterMap.put(
            nextClusterId,
            new HierarchicalClusterLeafNode(nextClusterId, example1.getValue(idAttribute)));
      }
      nextClusterId++;
    }

    // creating linkage method
    AbstractLinkageMethod linkage = new SingleLinkageMethod(matrix, clusterIds);
    if (getParameterAsString(PARAMETER_MODE).equals(modes[1])) {
      linkage = new CompleteLinkageMethod(matrix, clusterIds);
    } else if (getParameterAsString(PARAMETER_MODE).equals(modes[2])) {
      linkage = new AverageLinkageMethod(matrix, clusterIds);
    }

    // now building agglomerative tree bottom up
    while (clusterMap.size() > 1) {
      Agglomeration agglomeration = linkage.getNextAgglomeration(nextClusterId, clusterMap);
      HierarchicalClusterNode newNode =
          new HierarchicalClusterNode(nextClusterId, agglomeration.getDistance());
      newNode.addSubNode(clusterMap.get(agglomeration.getClusterId1()));
      newNode.addSubNode(clusterMap.get(agglomeration.getClusterId2()));
      clusterMap.remove(agglomeration.getClusterId1());
      clusterMap.remove(agglomeration.getClusterId2());
      clusterMap.put(nextClusterId, newNode);
      nextClusterId++;
    }

    // creating model
    HierarchicalClusterModel model =
        new DendogramHierarchicalClusterModel(clusterMap.entrySet().iterator().next().getValue());

    // registering visualizer
    ObjectVisualizerService.addObjectVisualizer(
        model, new ExampleVisualizer((ExampleSet) exampleSet.clone()));

    modelOutput.deliver(model);
    exampleSetOutput.deliver(exampleSet);
  }