Program: 72495
Project: 72495
Buggy source:
/** 
 * Java implementation of the Baum-Welch algorithm (Alpha-Beta Recursion) for parameter estimation and cluster assignment. This method uses normalized alpha values for computing the conditional probabilities of input sequences, to ensure numerical stability. Set nCategories to zero for continuous distribution types
 * @param y input observation stream
 * @param A transition probability matrix guess
 * @param prior prior state distribution guess
 * @param nCategories number of categories in the multinomial distribution, where applies
 * @return a HashMap containing the updated estimates of all model parameters
 * @throws IllegalActionException
 */
protected HashMap HMMAlphaBetaRecursion(double[][] y,double[][] A,double[] prior,int nCategories) throws IllegalActionException {
  boolean multinomial=nCategories > 0;
  int nStates=_nStates;
  int nObservations=y.length;
  int obsDimension=_obsDimension;
  double[][] alphas=new double[nObservations][nStates];
  double[][] gamma=new double[nObservations][nStates];
  double[][][] xi=new double[nObservations - 1][nStates][nStates];
  double[][] A_hat=new double[nStates][nStates];
  double[][] mu_hat=new double[nStates][obsDimension];
  double[][][] s_hat=new double[nStates][obsDimension][obsDimension];
  double[] pi_hat=new double[nStates];
  double[][] eta_hat=new double[nStates][nCategories];
  double[] alphaNormalizers=new double[nObservations];
  double alphaSum=0;
  for (int t=0; t < y.length; t++) {
    alphaSum=0;
    for (int i=0; i < nStates; i++) {
      alphas[t][i]=0;
      if (t == 0) {
        alphas[t][i]=prior[i] * emissionProbability(y[t],i);
      }
 else {
        for (int qt=0; qt < nStates; qt++) {
          alphas[t][i]+=A[qt][i] * emissionProbability(y[t],i) * alphas[t - 1][qt];
        }
      }
      alphaSum+=alphas[t][i];
    }
    for (int i=0; i < nStates; i++) {
      alphas[t][i]/=alphaSum;
      alphaNormalizers[t]=alphaSum;
    }
  }
  for (int t=y.length - 1; t >= 0; t--) {
    for (int qt=0; qt < nStates; qt++) {
      if (t == y.length - 1) {
        gamma[t][qt]=alphas[t][qt];
      }
 else {
        gamma[t][qt]=0;
        for (int qtp=0; qtp < nStates; qtp++) {
          double alphasum=0;
          for (int j=0; j < nStates; j++) {
            alphasum+=alphas[t][j] * A[j][qtp];
          }
          gamma[t][qt]+=(alphas[t][qt] * A[qt][qtp] * gamma[t + 1][qtp]) / alphasum;
        }
      }
    }
  }
  for (int next=0; next < nStates; next++) {
    for (int now=0; now < nStates; now++) {
      for (int t=0; t < (y.length - 1); t++) {
        if (alphas[t + 1][next] == 0) {
          xi[t][now][next]=0;
        }
 else {
          xi[t][now][next]=alphas[t][now] * emissionProbability(y[t + 1],next) * gamma[t + 1][next]* A[now][next] / alphas[t + 1][next];
        }
        A_hat[now][next]+=xi[t][now][next];
      }
    }
    for (int a=0; a < y[0].length; a++) {
      mu_hat[next][a]=0;
      for (int b=0; b < y[0].length; b++) {
        s_hat[next][a][b]=0;
      }
    }
  }
  double[] rowsum=new double[nStates];
  double[] gammasum=new double[nStates];
  for (int i=0; i < nStates; i++) {
    rowsum[i]=0;
    for (int j=0; j < nStates; j++) {
      rowsum[i]+=A_hat[i][j];
    }
    for (int j=0; j < nStates; j++) {
      A_hat[i][j]/=rowsum[i];
    }
    gammasum[i]=0.0;
  }
  for (int j=0; j < nStates; j++) {
    gammasum[j]=0.0;
    for (int t=0; t < y.length; t++) {
      gammasum[j]+=gamma[t][j];
      for (int i=0; i < y[0].length; i++) {
        mu_hat[j][i]+=gamma[t][j] * y[t][i];
      }
    }
    for (int i=0; i < y[0].length; i++) {
      mu_hat[j][i]=mu_hat[j][i] / gammasum[j];
    }
    for (int t=0; t < y.length; t++) {
      for (int a=0; a < y[0].length; a++) {
        for (int b=0; b < y[0].length; b++) {
          s_hat[j][a][b]+=gamma[t][j] * (y[t][a] - mu_hat[j][a]) * (y[t][b] - mu_hat[j][b]);
        }
      }
    }
    for (int a=0; a < y[0].length; a++) {
      for (int b=0; b < y[0].length; b++) {
        s_hat[j][a][b]=(s_hat[j][a][b] / gammasum[j]);
      }
    }
    pi_hat[j]=gamma[0][j];
  }
  if (multinomial) {
    for (int i=0; i < nStates; i++) {
      for (int j=0; j < nCategories; j++) {
        for (int t=0; t < y.length; t++) {
          eta_hat[i][j]+=gamma[t][i] * ((y[t][0] == j) ? 1 : 0);
        }
        eta_hat[i][j]/=gammasum[i];
      }
    }
  }
  int[] clusterAssignments=new int[y.length];
  for (int t=0; t < y.length; t++) {
    int maxState=0;
    for (int j=1; j < nStates; j++) {
      if (gamma[t][j] > gamma[t][maxState]) {
        maxState=j;
      }
    }
    clusterAssignments[t]=maxState;
  }
  double logLikelihood=0.0;
  for (int t=0; t < _observations.length - 1; t++) {
    logLikelihood+=emissionProbability(y[t],clusterAssignments[t]);
    logLikelihood+=A_hat[clusterAssignments[t]][clusterAssignments[t + 1]];
  }
  logLikelihood+=emissionProbability(y[_observations.length - 1],clusterAssignments[_observations.length - 1]);
  HashMap estimates=new HashMap();
  estimates.put("String_Node_Str",mu_hat);
  estimates.put("String_Node_Str",s_hat);
  estimates.put("String_Node_Str",gamma);
  estimates.put("String_Node_Str",A_hat);
  estimates.put("String_Node_Str",pi_hat);
  estimates.put("String_Node_Str",eta_hat);
  estimates.put("String_Node_Str",logLikelihood);
  return estimates;
}

Fixed version (ground truth):
/** 
 * Java implementation of the Baum-Welch algorithm (Alpha-Beta Recursion) for parameter estimation and cluster assignment. This method uses normalized alpha values for computing the conditional probabilities of input sequences, to ensure numerical stability. Set nCategories to zero for continuous distribution types
 * @param y input observation stream
 * @param A transition probability matrix guess
 * @param prior prior state distribution guess
 * @param nCategories number of categories in the multinomial distribution, where applies
 * @return a HashMap containing the updated estimates of all model parameters
 * @exception IllegalActionException
 */
protected HashMap HMMAlphaBetaRecursion(double[][] y,double[][] A,double[] prior,int nCategories) throws IllegalActionException {
  boolean multinomial=nCategories > 0;
  int nStates=_nStates;
  int nObservations=y.length;
  int obsDimension=_obsDimension;
  double[][] alphas=new double[nObservations][nStates];
  double[][] gamma=new double[nObservations][nStates];
  double[][][] xi=new double[nObservations - 1][nStates][nStates];
  double[][] A_hat=new double[nStates][nStates];
  double[][] mu_hat=new double[nStates][obsDimension];
  double[][][] s_hat=new double[nStates][obsDimension][obsDimension];
  double[] pi_hat=new double[nStates];
  double[][] eta_hat=new double[nStates][nCategories];
  double[] alphaNormalizers=new double[nObservations];
  double alphaSum=0;
  for (int t=0; t < y.length; t++) {
    alphaSum=0;
    for (int i=0; i < nStates; i++) {
      alphas[t][i]=0;
      if (t == 0) {
        alphas[t][i]=prior[i] * emissionProbability(y[t],i);
      }
 else {
        for (int qt=0; qt < nStates; qt++) {
          alphas[t][i]+=A[qt][i] * emissionProbability(y[t],i) * alphas[t - 1][qt];
        }
      }
      alphaSum+=alphas[t][i];
    }
    for (int i=0; i < nStates; i++) {
      alphas[t][i]/=alphaSum;
      alphaNormalizers[t]=alphaSum;
    }
  }
  for (int t=y.length - 1; t >= 0; t--) {
    for (int qt=0; qt < nStates; qt++) {
      if (t == y.length - 1) {
        gamma[t][qt]=alphas[t][qt];
      }
 else {
        gamma[t][qt]=0;
        for (int qtp=0; qtp < nStates; qtp++) {
          double alphasum=0;
          for (int j=0; j < nStates; j++) {
            alphasum+=alphas[t][j] * A[j][qtp];
          }
          gamma[t][qt]+=(alphas[t][qt] * A[qt][qtp] * gamma[t + 1][qtp]) / alphasum;
        }
      }
    }
  }
  for (int next=0; next < nStates; next++) {
    for (int now=0; now < nStates; now++) {
      for (int t=0; t < (y.length - 1); t++) {
        if (alphas[t + 1][next] == 0) {
          xi[t][now][next]=0;
        }
 else {
          xi[t][now][next]=alphas[t][now] * emissionProbability(y[t + 1],next) * gamma[t + 1][next]* A[now][next] / alphas[t + 1][next];
        }
        A_hat[now][next]+=xi[t][now][next];
      }
    }
    for (int a=0; a < y[0].length; a++) {
      mu_hat[next][a]=0;
      for (int b=0; b < y[0].length; b++) {
        s_hat[next][a][b]=0;
      }
    }
  }
  double[] rowsum=new double[nStates];
  double[] gammasum=new double[nStates];
  for (int i=0; i < nStates; i++) {
    rowsum[i]=0;
    for (int j=0; j < nStates; j++) {
      rowsum[i]+=A_hat[i][j];
    }
    for (int j=0; j < nStates; j++) {
      A_hat[i][j]/=rowsum[i];
    }
    gammasum[i]=0.0;
  }
  for (int j=0; j < nStates; j++) {
    gammasum[j]=0.0;
    for (int t=0; t < y.length; t++) {
      gammasum[j]+=gamma[t][j];
      for (int i=0; i < y[0].length; i++) {
        mu_hat[j][i]+=gamma[t][j] * y[t][i];
      }
    }
    for (int i=0; i < y[0].length; i++) {
      mu_hat[j][i]=mu_hat[j][i] / gammasum[j];
    }
    for (int t=0; t < y.length; t++) {
      for (int a=0; a < y[0].length; a++) {
        for (int b=0; b < y[0].length; b++) {
          s_hat[j][a][b]+=gamma[t][j] * (y[t][a] - mu_hat[j][a]) * (y[t][b] - mu_hat[j][b]);
        }
      }
    }
    for (int a=0; a < y[0].length; a++) {
      for (int b=0; b < y[0].length; b++) {
        s_hat[j][a][b]=(s_hat[j][a][b] / gammasum[j]);
      }
    }
    pi_hat[j]=gamma[0][j];
  }
  if (multinomial) {
    for (int i=0; i < nStates; i++) {
      for (int j=0; j < nCategories; j++) {
        for (int t=0; t < y.length; t++) {
          eta_hat[i][j]+=gamma[t][i] * ((y[t][0] == j) ? 1 : 0);
        }
        eta_hat[i][j]/=gammasum[i];
      }
    }
  }
  int[] clusterAssignments=new int[y.length];
  for (int t=0; t < y.length; t++) {
    int maxState=0;
    for (int j=1; j < nStates; j++) {
      if (gamma[t][j] > gamma[t][maxState]) {
        maxState=j;
      }
    }
    clusterAssignments[t]=maxState;
  }
  double logLikelihood=0.0;
  for (int t=0; t < _observations.length - 1; t++) {
    logLikelihood+=emissionProbability(y[t],clusterAssignments[t]);
    logLikelihood+=A_hat[clusterAssignments[t]][clusterAssignments[t + 1]];
  }
  logLikelihood+=emissionProbability(y[_observations.length - 1],clusterAssignments[_observations.length - 1]);
  HashMap estimates=new HashMap();
  estimates.put("String_Node_Str",mu_hat);
  estimates.put("String_Node_Str",s_hat);
  estimates.put("String_Node_Str",gamma);
  estimates.put("String_Node_Str",A_hat);
  estimates.put("String_Node_Str",pi_hat);
  estimates.put("String_Node_Str",eta_hat);
  estimates.put("String_Node_Str",logLikelihood);
  return estimates;
}