private static Split findBestSplit(float[] sortedValues, float min_rd, int min_y, int NCount, int numThresholds) { int YCount = sortedValues.Length; float min = sortedValues[0]; float max = sortedValues[sortedValues.Length - 1]; float thresholdInterval = (max - min) / (numThresholds + 1); float NInterval = (float)NCount / (numThresholds + 1); int[] YCountLeft = new int[numThresholds + 1]; int[] NCountLeft = new int[numThresholds + 1]; int[] YCountRight = new int[numThresholds]; int[] NCountRight = new int[numThresholds]; float[] thresholds = new float[numThresholds]; float threshold = min + thresholdInterval; float NLeft = NInterval; int YLeft = 0; int YRight = YCount; for (int i = 0; i < numThresholds; i++) { thresholds[i] = threshold; for (; sortedValues[YLeft] < threshold; YLeft++, YRight--) { ; } YCountLeft[i] = YLeft; YCountRight[i] = YRight; NCountLeft[i] = (int)NLeft; NCountRight[i] = NCount - (int)NLeft; threshold += thresholdInterval; NLeft += NInterval; } YCountLeft[numThresholds] = YCount; NCountLeft[numThresholds] = NCount; Split best = new Split { Score = float.MinValue }; for (int i = 0; i < numThresholds; i++) { if (YCountLeft[i] < min_y) { continue; } float left_rd = (float)YCountLeft[i] / Math.Max(NCountLeft[i], 1); for (int j = i + 1; j < numThresholds; j++) { if (YCountRight[i] < min_y) { continue; } float right_rd = (float)YCountRight[i] / Math.Max(NCountRight[i], 1); float middleY = YCountLeft[j] - YCountLeft[i]; float middleN = Math.Max(NCountLeft[j] - NCountLeft[i], 1); float middle_rd = middleY / middleN; if (middle_rd < min_rd) { Split test = new Split { Score = left_rd + right_rd - middle_rd }; if (test.Score > best.Score) { if (j - i > 3) { float[] density = new float[j - i]; for (int k = 0; k < density.Length; k++) { density[k] = (float)(YCountLeft[i + k + 1] - YCountLeft[i + k]) / (NCountLeft[i + k + 1] - NCountLeft[i + k]); } density = Gaussian.Convolve(density, 1); int minIndex = density.MinIndex(); test.Threshold = thresholds[i + minIndex]; } else { test.Threshold = (thresholds[i] + thresholds[j]) / 2; } test.NLeft = (int)(((test.Threshold - min) * NCount) / (max - min)); best = test; } } } } return(best); }