public void buildClassifier(Instances instances) throws Exception {

    getCapabilities().testWithFail(instances);

    // copy the dataset 
    m_train = new Instances(instances);

    // new dataset in which examples with missing class value are removed
    m_train.deleteWithMissingClass();

    // build the Map for the estimatedDistributions 
    m_estimatedDistributions = new HashMap(m_train.numInstances()/2);

    // cycle through all instances 
    for (Iterator it = 
      new EnumerationIterator(instances.enumerateInstances()); 
    it.hasNext();) {
      Instance instance = (Instance) it.next();
      Coordinates c = new Coordinates(instance);

      // get DiscreteEstimator from the map
      DiscreteEstimator df = 
	(DiscreteEstimator) m_estimatedDistributions.get(c);

      // if no DiscreteEstimator is present in the map, create one 
      if (df == null) {
	df = new DiscreteEstimator(instances.numClasses(),0);
      }
      df.addValue(instance.classValue(),instance.weight()); // update
      m_estimatedDistributions.put(c,df); // put back in map
    }


    // build the map of cumulative distribution functions 
    m_estimatedCumulativeDistributions = 
      new HashMap(m_estimatedDistributions.size()/2);

    // Cycle trough the map of discrete distributions, and create a new
    // one containing cumulative discrete distributions
    for (Iterator it=m_estimatedDistributions.keySet().iterator();
    it.hasNext();) {
      Coordinates c = (Coordinates) it.next();
      DiscreteEstimator df = 
	(DiscreteEstimator) m_estimatedDistributions.get(c);
      m_estimatedCumulativeDistributions.put
      (c, new CumulativeDiscreteDistribution(df));
    }

    // check if the interpolation parameter needs to be tuned
    if (m_tuneInterpolationParameter && !m_interpolationParameterValid) {
      tuneInterpolationParameter();
    }

    // fill in the smallest and biggest element (for use in the
    // quasi monotone version of the algorithm)
    double[] tmpAttValues = new double[instances.numAttributes()];
    Instance instance = new DenseInstance(1, tmpAttValues);
    instance.setDataset(instances);
    smallestElement = new Coordinates(instance);
    if (m_Debug) {
      System.err.println("minimal element of data space = " 
	  + smallestElement);
    }
    for (int i = 0; i < tmpAttValues.length; i++) {
      tmpAttValues[i] = instances.attribute(i).numValues() - 1; 
    }

    instance = new DenseInstance(1, tmpAttValues);
    instance.setDataset(instances);
    biggestElement = new Coordinates(instance);
    if (m_Debug) {
      System.err.println("maximal element of data space = " 
	  + biggestElement);
    }
  }