/**
   * Gets the raw output from the classifier
   *
   * @return the raw output from the classifier
   */
  @Override
  public String getRawResultOutput() {
    StringBuffer result = new StringBuffer();

    if (m_clusterer == null) {
      return "<null> clusterer";
    }
    result.append(toString());
    result.append("Clustering model: \n" + m_clusterer.toString() + '\n');

    // append the performance statistics
    if (m_result != null) {
      // result.append(m_result);

      if (m_doesProduce != null) {
        for (int i = 0; i < m_doesProduce.length; i++) {
          if (m_doesProduce[i]) {
            try {
              double dv =
                  ((AdditionalMeasureProducer) m_clusterer).getMeasure(m_additionalMeasures[i]);
              Double value = new Double(dv);

              result.append(m_additionalMeasures[i] + " : " + value + '\n');
            } catch (Exception ex) {
              System.err.println(ex);
            }
          }
        }
      }
    }
    return result.toString();
  }
  /**
   * Returns an enumeration describing the available options.
   *
   * @return an enumeration of all the available options.
   */
  @Override
  public Enumeration<Option> listOptions() {

    Vector<Option> newVector = new Vector<Option>(2);

    newVector.addElement(
        new Option(
            "\tSkips the determination of sizes (train/test/clusterer)\n"
                + "\t(default: sizes are determined)",
            "no-size",
            0,
            "-no-size"));
    newVector.addElement(
        new Option(
            "\tThe full class name of the density based clusterer.\n" + "\teg: weka.clusterers.EM",
            "W",
            1,
            "-W <class name>"));

    if ((m_clusterer != null) && (m_clusterer instanceof OptionHandler)) {
      newVector.addElement(
          new Option(
              "",
              "",
              0,
              "\nOptions specific to clusterer " + m_clusterer.getClass().getName() + ":"));
      newVector.addAll(Collections.list(((OptionHandler) m_clusterer).listOptions()));
    }
    return newVector.elements();
  }
  /**
   * Gets the key describing the current SplitEvaluator. For example This may contain the name of
   * the classifier used for classifier predictive evaluation. The number of key fields must be
   * constant for a given SplitEvaluator.
   *
   * @return an array of objects containing the key.
   */
  @Override
  public Object[] getKey() {

    Object[] key = new Object[KEY_SIZE];
    key[0] = m_clusterer.getClass().getName();
    key[1] = m_clustererOptions;
    key[2] = m_clustererVersion;
    return key;
  }
  protected void updateOptions() {

    if (m_clusterer instanceof OptionHandler) {
      m_clustererOptions = Utils.joinOptions(((OptionHandler) m_clusterer).getOptions());
    } else {
      m_clustererOptions = "";
    }
    if (m_clusterer instanceof Serializable) {
      ObjectStreamClass obs = ObjectStreamClass.lookup(m_clusterer.getClass());
      m_clustererVersion = "" + obs.getSerialVersionUID();
    } else {
      m_clustererVersion = "";
    }
  }
  /**
   * Returns a text description of the split evaluator.
   *
   * @return a text description of the split evaluator.
   */
  @Override
  public String toString() {

    String result = "DensityBasedClustererSplitEvaluator: ";
    if (m_clusterer == null) {
      return result + "<null> clusterer";
    }
    return result
        + m_clusterer.getClass().getName()
        + " "
        + m_clustererOptions
        + "(version "
        + m_clustererVersion
        + ")";
  }
 /**
  * Returns the value of the named measure
  *
  * @param additionalMeasureName the name of the measure to query for its value
  * @return the value of the named measure
  * @exception IllegalArgumentException if the named measure is not supported
  */
 @Override
 public double getMeasure(String additionalMeasureName) {
   if (m_clusterer instanceof AdditionalMeasureProducer) {
     return ((AdditionalMeasureProducer) m_clusterer).getMeasure(additionalMeasureName);
   } else {
     throw new IllegalArgumentException(
         "DensityBasedClustererSplitEvaluator: "
             + "Can't return value for : "
             + additionalMeasureName
             + ". "
             + m_clusterer.getClass().getName()
             + " "
             + "is not an AdditionalMeasureProducer");
   }
 }
  /**
   * Gets the results for the supplied train and test datasets.
   *
   * @param train the training Instances.
   * @param test the testing Instances.
   * @return the results stored in an array. The objects stored in the array may be Strings,
   *     Doubles, or null (for the missing value).
   * @exception Exception if a problem occurs while getting the results
   */
  @Override
  public Object[] getResult(Instances train, Instances test) throws Exception {

    if (m_clusterer == null) {
      throw new Exception("No clusterer has been specified");
    }
    int addm = (m_additionalMeasures != null) ? m_additionalMeasures.length : 0;
    int overall_length = RESULT_SIZE + addm;

    if (m_removeClassColumn && train.classIndex() != -1) {
      // remove the class column from the training and testing data
      Remove r = new Remove();
      r.setAttributeIndicesArray(new int[] {train.classIndex()});
      r.setInvertSelection(false);
      r.setInputFormat(train);
      train = Filter.useFilter(train, r);

      test = Filter.useFilter(test, r);
    }
    train.setClassIndex(-1);
    test.setClassIndex(-1);

    ClusterEvaluation eval = new ClusterEvaluation();

    Object[] result = new Object[overall_length];
    long trainTimeStart = System.currentTimeMillis();
    m_clusterer.buildClusterer(train);
    double numClusters = m_clusterer.numberOfClusters();
    eval.setClusterer(m_clusterer);
    long trainTimeElapsed = System.currentTimeMillis() - trainTimeStart;
    long testTimeStart = System.currentTimeMillis();
    eval.evaluateClusterer(test);
    long testTimeElapsed = System.currentTimeMillis() - testTimeStart;
    // m_result = eval.toSummaryString();

    // The results stored are all per instance -- can be multiplied by the
    // number of instances to get absolute numbers
    int current = 0;
    result[current++] = new Double(train.numInstances());
    result[current++] = new Double(test.numInstances());

    result[current++] = new Double(eval.getLogLikelihood());
    result[current++] = new Double(numClusters);

    // Timing stats
    result[current++] = new Double(trainTimeElapsed / 1000.0);
    result[current++] = new Double(testTimeElapsed / 1000.0);

    // sizes
    if (m_NoSizeDetermination) {
      result[current++] = -1.0;
      result[current++] = -1.0;
      result[current++] = -1.0;
    } else {
      ByteArrayOutputStream bastream = new ByteArrayOutputStream();
      ObjectOutputStream oostream = new ObjectOutputStream(bastream);
      oostream.writeObject(m_clusterer);
      result[current++] = new Double(bastream.size());
      bastream = new ByteArrayOutputStream();
      oostream = new ObjectOutputStream(bastream);
      oostream.writeObject(train);
      result[current++] = new Double(bastream.size());
      bastream = new ByteArrayOutputStream();
      oostream = new ObjectOutputStream(bastream);
      oostream.writeObject(test);
      result[current++] = new Double(bastream.size());
    }

    for (int i = 0; i < addm; i++) {
      if (m_doesProduce[i]) {
        try {
          double dv = ((AdditionalMeasureProducer) m_clusterer).getMeasure(m_additionalMeasures[i]);
          Double value = new Double(dv);

          result[current++] = value;
        } catch (Exception ex) {
          System.err.println(ex);
        }
      } else {
        result[current++] = null;
      }
    }

    if (current != overall_length) {
      throw new Error("Results didn't fit RESULT_SIZE");
    }
    return result;
  }