public void optimizeParam(int numItns) {

    assert wordTopicHist != null;

    // update histograms

    int njMax = wordTopicCountsNorm[0];

    for (int j=1; j<T; j++)
      if (wordTopicCountsNorm[j] > njMax)
        njMax = wordTopicCountsNorm[j];

    wordTopicNormHist = new int[njMax + 1];

    for (int j=0; j<T; j++)
      wordTopicNormHist[wordTopicCountsNorm[j]]++;

    // optimize hyperparameters

    for (int i=0; i<numItns; i++) {

      double denominator = 0.0;
      double currentDigamma = 0.0;

      for (int n=1; n<wordTopicNormHist.length; n++) {
        currentDigamma += 1.0 / (paramSum + n - 1);
        denominator += wordTopicNormHist[n] * currentDigamma;
      }

      paramSum = 0.0;

      for (int w=0; w<W; w++) {

        double oldParam = param[w];
        param[w] = 0.0;
        currentDigamma = 0;

        for (int n=1; n<wordTopicHist[w].length; n++) {
          currentDigamma += 1.0 / (oldParam + n - 1);
          param[w] += wordTopicHist[w][n] * currentDigamma;
        }

        param[w] *= oldParam / denominator;

        if (param[w] == 0.0)
          param[w] = 1e-10;

        paramSum += param[w];
      }
    }
  }