Program: 57232
Project: 57232
Buggy source:
/** 
 * Helper method to create a multivariate normal mixture model which can be used to initialize   {@link #fit(MixtureMultivariateNormalDistribution)}. This method uses the data supplied to the constructor to try to determine a good mixture model at which to start the fit, but it is not guaranteed to supply a model which will find the optimal solution or even converge.
 * @param data Data to estimate distribution
 * @param numComponents Number of components for estimated mixture
 * @return Multivariate normal mixture model estimated from the data
 * @throws NumberIsTooLargeException if {@code numComponents} is greaterthan the number of data rows.
 * @throws NumberIsTooSmallException if {@code numComponents < 2}.
 * @throws NotStrictlyPositiveException if data has less than 2 rows
 * @throws DimensionMismatchException if rows of data have different numbersof columns
 */
public static MixtureMultivariateNormalDistribution estimate(final double[][] data,final int numComponents) throws NotStrictlyPositiveException, DimensionMismatchException {
  if (data.length < 2) {
    throw new NotStrictlyPositiveException(data.length);
  }
  if (numComponents < 2) {
    throw new NumberIsTooSmallException(numComponents,2,true);
  }
  if (numComponents > data.length) {
    throw new NumberIsTooLargeException(numComponents,data.length,true);
  }
  final int numRows=data.length;
  final int numCols=data[0].length;
  final DataRow[] sortedData=new DataRow[numRows];
  for (int i=0; i < numRows; i++) {
    sortedData[i]=new DataRow(data[i]);
  }
  Arrays.sort(sortedData);
  final int totalBins=numComponents;
  final double weight=1d / totalBins;
  final List<Pair<Double,MultivariateNormalDistribution>> components=new ArrayList<Pair<Double,MultivariateNormalDistribution>>();
  for (int binNumber=1; binNumber <= totalBins; binNumber++) {
    final int minIndex=(int)FastMath.max(0,FastMath.floor((binNumber - 1) * numRows / totalBins));
    final int maxIndex=(int)FastMath.ceil(binNumber * numRows / numComponents) - 1;
    final int numBinRows=maxIndex - minIndex + 1;
    final double[][] binData=new double[numBinRows][numCols];
    final double[] columnMeans=new double[numCols];
    for (int i=minIndex, iBin=0; i <= maxIndex; i++, iBin++) {
      for (int j=0; j < numCols; j++) {
        final double val=sortedData[i].getRow()[j];
        columnMeans[j]+=val;
        binData[iBin][j]=val;
      }
    }
    MathArrays.scaleInPlace(1d / numBinRows,columnMeans);
    final double[][] covMat=new Covariance(binData).getCovarianceMatrix().getData();
    final MultivariateNormalDistribution mvn=new MultivariateNormalDistribution(columnMeans,covMat);
    components.add(new Pair<Double,MultivariateNormalDistribution>(weight,mvn));
  }
  return new MixtureMultivariateNormalDistribution(components);
}

Fixed version (ground truth):
/** 
 * Helper method to create a multivariate normal mixture model which can be used to initialize   {@link #fit(MixtureMultivariateNormalDistribution)}. This method uses the data supplied to the constructor to try to determine a good mixture model at which to start the fit, but it is not guaranteed to supply a model which will find the optimal solution or even converge.
 * @param data Data to estimate distribution
 * @param numComponents Number of components for estimated mixture
 * @return Multivariate normal mixture model estimated from the data
 * @throws NumberIsTooLargeException if {@code numComponents} is greaterthan the number of data rows.
 * @throws NumberIsTooSmallException if {@code numComponents < 2}.
 * @throws NotStrictlyPositiveException if data has less than 2 rows
 * @throws DimensionMismatchException if rows of data have different numbersof columns
 */
public static MixtureMultivariateNormalDistribution estimate(final double[][] data,final int numComponents) throws NotStrictlyPositiveException, DimensionMismatchException {
  if (data.length < 2) {
    throw new NotStrictlyPositiveException(data.length);
  }
  if (numComponents < 2) {
    throw new NumberIsTooSmallException(numComponents,2,true);
  }
  if (numComponents > data.length) {
    throw new NumberIsTooLargeException(numComponents,data.length,true);
  }
  final int numRows=data.length;
  final int numCols=data[0].length;
  final DataRow[] sortedData=new DataRow[numRows];
  for (int i=0; i < numRows; i++) {
    sortedData[i]=new DataRow(data[i]);
  }
  Arrays.sort(sortedData);
  final double weight=1d / numComponents;
  final List<Pair<Double,MultivariateNormalDistribution>> components=new ArrayList<Pair<Double,MultivariateNormalDistribution>>();
  for (int binIndex=0; binIndex < numComponents; binIndex++) {
    final int minIndex=(binIndex * numRows) / numComponents;
    final int maxIndex=((binIndex + 1) * numRows) / numComponents;
    final int numBinRows=maxIndex - minIndex;
    final double[][] binData=new double[numBinRows][numCols];
    final double[] columnMeans=new double[numCols];
    for (int i=minIndex, iBin=0; i < maxIndex; i++, iBin++) {
      for (int j=0; j < numCols; j++) {
        final double val=sortedData[i].getRow()[j];
        columnMeans[j]+=val;
        binData[iBin][j]=val;
      }
    }
    MathArrays.scaleInPlace(1d / numBinRows,columnMeans);
    final double[][] covMat=new Covariance(binData).getCovarianceMatrix().getData();
    final MultivariateNormalDistribution mvn=new MultivariateNormalDistribution(columnMeans,covMat);
    components.add(new Pair<Double,MultivariateNormalDistribution>(weight,mvn));
  }
  return new MixtureMultivariateNormalDistribution(components);
}