Program: 22731
Project: 22731
Buggy source:
/** 
 * Calculate the Rand index between to clusters, as described by William M. Rand \cite{Rand71}, but pruning out the zero component. Otherwise the Rand index gets symmetric. BibTeX: <pre> &#64;article{Rand71, author    = {William M. Rand}, title     = {Objective criteria for the evaluation of clustering methods}, journal   = {Journal of the American Statistical Association}, year      = {1971}, volume    = {66}, number    = {336}, pages     = {846--850}, doi       = {10.2307/2284239) } </pre>
 * @param cluster1 2D segmented image (objects are labeled with different numbers) 
 * @param cluster2 2D segmented image (objects are labeled with different numbers)
 * @return Rand index
 */
public ClassificationStatistics getRandIndexStats(ShortProcessor cluster1,ShortProcessor cluster2){
  final short[] pixels1=(short[])cluster1.getPixels();
  final short[] pixels2=(short[])cluster2.getPixels();
  double nPixels=pixels1.length;
  double n=0;
  cluster1.resetMinAndMax();
  cluster2.resetMinAndMax();
  int[][] cont=new int[(int)cluster1.getMax() + 1][(int)cluster2.getMax() + 1];
  for (int i=0; i < nPixels; i++) {
    cont[pixels1[i]][pixels2[i]]++;
    if (pixels1[i] > 0)     n++;
  }
  double[] ni=new double[cont.length];
  for (int i=1; i < cont.length; i++)   for (int j=0; j < cont[0].length; j++) {
    ni[i]+=cont[i][j];
  }
  double[] nj=new double[cont[0].length];
  for (int j=1; j < cont[0].length; j++)   for (int i=1; i < cont.length; i++) {
    nj[j]+=cont[i][j];
  }
  double truePositives=0;
  for (int j=1; j < cont[0].length; j++)   for (int i=1; i < cont.length; i++) {
    truePositives+=cont[i][j] * (cont[i][j] - 1.0) / 2.0;
  }
  double nPairsTotal=n * (n - 1) / 2;
  double nPosTrue=0;
  for (int k=0; k < ni.length; k++)   nPosTrue+=ni[k] * (ni[k] - 1) / 2;
  double nPosActual=0;
  for (int k=0; k < nj.length; k++)   nPosActual+=nj[k] * (nj[k] - 1) / 2;
  double nNegCorrect=nPairsTotal + truePositives - nPosTrue - nPosActual;
  double trueNegatives=nNegCorrect;
  double falsePositives=nPosActual - truePositives;
  double nNegActual=nPairsTotal - nPosActual;
  double falseNegatives=nNegActual - nNegCorrect;
  double agreements=truePositives + trueNegatives;
  double randIndex=agreements / nPairsTotal;
  return new ClassificationStatistics(truePositives,trueNegatives,falsePositives,falseNegatives,randIndex);
}

Fixed version (ground truth):
/** 
 * Calculate the Rand index between to clusters, as described by William M. Rand \cite{Rand71}, but pruning out the zero component of the ground truth, which leads to an asymmetric index. BibTeX: <pre> &#64;article{Rand71, author    = {William M. Rand}, title     = {Objective criteria for the evaluation of clustering methods}, journal   = {Journal of the American Statistical Association}, year      = {1971}, volume    = {66}, number    = {336}, pages     = {846--850}, doi       = {10.2307/2284239) } </pre>
 * @param cluster1 ground truth, 2D segmented image (objects are labeled with different numbers) 
 * @param cluster2 prediction, 2D segmented image (objects are labeled with different numbers)
 * @return Rand index value and prediction statistics
 */
public ClassificationStatistics getRandIndexStats(ShortProcessor cluster1,ShortProcessor cluster2){
  final short[] pixels1=(short[])cluster1.getPixels();
  final short[] pixels2=(short[])cluster2.getPixels();
  double nPixels=pixels1.length;
  double n=0;
  cluster1.resetMinAndMax();
  cluster2.resetMinAndMax();
  int[][] cont=new int[(int)cluster1.getMax() + 1][(int)cluster2.getMax() + 1];
  for (int i=0; i < nPixels; i++) {
    cont[pixels1[i]][pixels2[i]]++;
    if (pixels1[i] > 0)     n++;
  }
  double[] ni=new double[cont.length];
  for (int i=1; i < cont.length; i++)   for (int j=0; j < cont[0].length; j++) {
    ni[i]+=cont[i][j];
  }
  double[] nj=new double[cont[0].length];
  for (int j=1; j < cont[0].length; j++)   for (int i=1; i < cont.length; i++) {
    nj[j]+=cont[i][j];
  }
  double truePositives=0;
  for (int j=1; j < cont[0].length; j++)   for (int i=1; i < cont.length; i++) {
    truePositives+=cont[i][j] * (cont[i][j] - 1.0) / 2.0;
  }
  double nPairsTotal=n * (n - 1) / 2;
  double nPosTrue=0;
  for (int k=0; k < ni.length; k++)   nPosTrue+=ni[k] * (ni[k] - 1) / 2;
  double nPosActual=0;
  for (int k=0; k < nj.length; k++)   nPosActual+=nj[k] * (nj[k] - 1) / 2;
  double trueNegatives=nPairsTotal + truePositives - nPosTrue - nPosActual;
  double falsePositives=nPosActual - truePositives;
  double nNegActual=nPairsTotal - nPosActual;
  double falseNegatives=nNegActual - trueNegatives;
  double agreements=truePositives + trueNegatives;
  double randIndex=agreements / nPairsTotal;
  return new ClassificationStatistics(truePositives,trueNegatives,falsePositives,falseNegatives,randIndex);
}