public void learn(float[][] data, int iteration) {
    for (int iter = 0; iter < iteration; iter++) {
      if (iter % 10 == 0) {
        System.out.print("Iteration " + iter + "\t");
        for (int i = 0; i < ksize; i++) System.out.print(clusterDataIndex.get(i).size() + " ");
        System.out.println();
        System.out.println("mu:");
        for (int k = 0; k < ksize; k++) ComUtil.print(p_mu[k], " ", "\n");
        System.out.println("lambda:");
        for (int k = 0; k < ksize; k++) ComUtil.print(p_lambda[k], " ", "\n");
      }

      // tranverse data
      for (int n = 0; n < data.length; n++) {
        double[] probs = new double[ksize];

        int currentz = clusterID[n];
        // decrease
        int toRemoveIndex = clusterDataIndex.get(currentz).indexOf(n);
        clusterDataIndex.get(currentz).remove(toRemoveIndex);
        // update mu lambda for currentz
        comAVGX(data, currentz);
        comDateMus(p_mu, p_lambda, data, clusterDataIndex, currentz);

        // computeProbs
        for (int k = 0; k < ksize; k++) {
          probs[k] = (clusterDataIndex.get(k).size() + alpha) / (vector_n + ksize * alpha);
          for (int d = 0; d < vector_d; d++)
            probs[k] *= MathUtil.phi(data[n][d], p_mu[k][d], Math.sqrt(1 / p_lambda[k][d]));
        }

        int newz = ComUtil.sample(probs, ksize);
        // increase
        clusterID[n] = newz;
        clusterDataIndex.get(newz).add(n);
        // update mu lambda for currentz
        comAVGX(data, newz);
        comDateMus(p_mu, p_lambda, data, clusterDataIndex, newz);
      }
    }
  }
  public double[] LearnProbs(float[][] data, int n) {
    double[] probs = new double[ksize];

    int currentz = clusterID[n];
    // decrease
    int toRemoveIndex = clusterDataIndex.get(currentz).indexOf(n);
    clusterDataIndex.get(currentz).remove(toRemoveIndex);

    // update mu lambda for currentz
    comAVGX(data, currentz, n, false);
    comDateMus(p_mu, p_lambda, data, clusterDataIndex, currentz);

    // computeProbs
    for (int k = 0; k < ksize; k++) {
      probs[k] = 1;
      for (int d = 0; d < vector_d; d++)
        probs[k] *= MathUtil.phi(data[n][d], p_mu[k][d], Math.sqrt(1 / p_lambda[k][d]));
      if (probs[k] < 1e-300) {
        probs[k] = 1e-300;
      }
    }

    return probs;
  }