public void addSample(int[] sample) {
    if (m_state == state_initializingClusters) {

      m_initSamples[m_initCounter++] = sample;
      IntTouple it = new IntTouple(sample);
      if (m_uniqueInitSamplesSet.add(it)) {
        // new element
        m_uniqueInitSamplesList.add(it);
      }
      if (m_initCounter == numInitSamples()) {
        initializeClusters();
      }

    } else if (m_state == state_updating) {

      Object[] pairing = determineClusterMembership(sample);
      int memberOf = ((Integer) pairing[0]).intValue();
      for (int i = 0; i < m_dimensions; i++) {
        m_tmpClusterAccum[memberOf][i] += sample[i];
      }
      m_tmpClusterCount[memberOf]++;

      m_error += ((Long) pairing[1]).longValue();

    } else if (m_state == state_doneAllComputingError) {

      Object[] pairing = determineClusterMembership(sample);
      m_error += ((Long) pairing[1]).longValue();

    } else {

      throw new RuntimeException();
    }
  }
  private void initializeClusters() {
    if (m_uniqueInitSamplesList.size() == 0) {
      throw new RuntimeException();
    }
    for (int i = 0; i < m_numClusters; i++) {
      int randomIndex = (int) Math.floor(m_uniqueInitSamplesList.size() * Math.random());
      m_clusters[i] =
          initSmoothClusterRandomly((IntTouple) m_uniqueInitSamplesList.get(randomIndex));
      m_uniqueInitSamplesList.remove(randomIndex);
    }

    m_state = state_updating;

    for (int i = 0; i < m_initCounter; i++) {
      addSample(m_initSamples[i]);
    }
  }