Program: 149555
Project: 149555
Buggy source:
/** 
 * Trace localisations across frames that are the same molecule. <p> Any spot that occurred within time threshold and distance threshold of a previous spot is grouped into the same trace as that previous spot. The resulting trace is assigned a spatial position equal to the centroid position of all the spots included in the trace. <p> See Coltharp, et al. Accurate Construction of Photoactivated Localization Microscopy (PALM) Images for Quantitative Measurements (2012). PLoS One. 7(12): e51725. DOI: http://dx.doi.org/10.1371%2Fjournal.pone.0051725 <p> Note: The actual traces representing molecules can be obtained by calling   {@link #getTraces()}
 * @param distanceThreshold
 * @param timeThreshold
 * @return The number of traces
 */
public int traceMolecules(final double distanceThreshold,final int timeThreshold){
  if (timeThreshold <= 0 || distanceThreshold < 0)   return totalTraces=localisations.length;
  totalTraces=totalFiltered=0;
  dThresh2=(float)(distanceThreshold * distanceThreshold);
  dExclusion2=(distanceExclusion >= distanceThreshold) ? (float)(distanceExclusion * distanceExclusion) : 0;
  if (tracker != null)   tracker.progress(0);
  maxT=new int[localisations.length + 1];
  int[] traceIdToLocalisationsIndexMap=new int[localisations.length + 1];
  int nextIndex=index[localisations[0].t + 1];
  for (int index=0; index < nextIndex; index++) {
    localisations[index].trace=addTrace(index,traceIdToLocalisationsIndexMap,maxT);
  }
  Assignment[] assigned=new Assignment[10];
  while (nextIndex < localisations.length) {
    if (tracker != null)     tracker.progress(nextIndex,localisations.length);
    final int currentIndex=nextIndex;
    final int t=localisations[currentIndex].t;
    nextIndex=index[t + 1];
    int pastT=FastMath.max(t - timeThreshold,0);
    if (pulseInterval > 0) {
      int intervalBoundary=1 + pulseInterval * ((t - 1) / pulseInterval);
      if (pastT < intervalBoundary)       pastT=intervalBoundary;
    }
    final int pastEndIndex=endIndex[pastT];
    final int currentEndIndex=endIndex[t];
    if (pastEndIndex == currentEndIndex) {
      for (int index=currentIndex; index < nextIndex; index++) {
        localisations[index].trace=addTrace(index,traceIdToLocalisationsIndexMap,maxT);
      }
      continue;
    }
    if (assigned.length < nextIndex - currentIndex) {
      assigned=new Assignment[nextIndex - currentIndex];
    }
    int assignedToTrace=0;
    for (int index=currentIndex; index < nextIndex; index++) {
      int traceId=findForerunner(index,pastEndIndex,currentEndIndex);
      if (traceId == 0) {
        localisations[index].trace=addTrace(index,traceIdToLocalisationsIndexMap,maxT);
      }
 else {
        assigned[assignedToTrace++]=new Assignment(index,minD,traceId);
      }
    }
    if (assignedToTrace > 1) {
      int[] dualAllocation=new int[assignedToTrace];
      int[] ignore=new int[assignedToTrace];
      int ignoreCount=0;
      boolean reSort=true;
      for (int i=0; i < assignedToTrace - 1; i++) {
        if (assigned[i].distance < 0)         continue;
        if (reSort) {
          reSort=false;
          Arrays.sort(assigned,i,assignedToTrace - 1,new Comparator<Assignment>(){
            public int compare(            Assignment o1,            Assignment o2){
              if (o1.distance < o2.distance)               return -1;
              if (o1.distance > o2.distance)               return 1;
              return 0;
            }
          }
);
          if (assigned[i].distance < 0)           continue;
        }
        int dualAllocationCount=0;
        for (int j=i + 1; j < assignedToTrace; j++) {
          if (assigned[i].traceId == assigned[j].traceId)           dualAllocation[dualAllocationCount++]=j;
        }
        if (dualAllocationCount > 0) {
          ignore[ignoreCount++]=assigned[i].traceId;
          for (int a=0; a < dualAllocationCount; a++) {
            int index=assigned[dualAllocation[a]].index;
            int traceId=findAlternativeForerunner(index,pastEndIndex,currentEndIndex,ignoreCount,ignore);
            if (traceId == 0) {
              traceId=addTrace(index,traceIdToLocalisationsIndexMap,maxT);
              assigned[dualAllocation[a]].distance=-1;
            }
 else {
              reSort=true;
              assigned[dualAllocation[a]].distance=minD;
            }
            assigned[dualAllocation[a]].traceId=traceId;
          }
        }
      }
    }
    for (int i=0; i < assignedToTrace; i++) {
      localisations[assigned[i].index].trace=assigned[i].traceId;
      maxT[assigned[i].traceId]=localisations[assigned[i].index].endT;
    }
  }
  if (tracker != null)   tracker.progress(1.0);
  return getTotalTraces();
}

Fixed version (ground truth):
/** 
 * Trace localisations across frames that are the same molecule. <p> Any spot that occurred within time threshold and distance threshold of a previous spot is grouped into the same trace as that previous spot. The resulting trace is assigned a spatial position equal to the centroid position of all the spots included in the trace. <p> See Coltharp, et al. Accurate Construction of Photoactivated Localization Microscopy (PALM) Images for Quantitative Measurements (2012). PLoS One. 7(12): e51725. DOI: http://dx.doi.org/10.1371%2Fjournal.pone.0051725 <p> Note: The actual traces representing molecules can be obtained by calling   {@link #getTraces()}
 * @param distanceThreshold
 * @param timeThreshold
 * @return The number of traces
 */
public int traceMolecules(final double distanceThreshold,final int timeThreshold){
  if (timeThreshold <= 0 || distanceThreshold < 0)   return totalTraces=localisations.length;
  totalTraces=totalFiltered=0;
  dThresh2=(float)(distanceThreshold * distanceThreshold);
  dExclusion2=(distanceExclusion >= distanceThreshold) ? (float)(distanceExclusion * distanceExclusion) : 0;
  if (tracker != null)   tracker.progress(0);
  maxT=new int[localisations.length + 1];
  int[] traceIdToLocalisationsIndexMap=new int[localisations.length + 1];
  int nextIndex=index[localisations[0].t + 1];
  for (int index=0; index < nextIndex; index++) {
    localisations[index].trace=addTrace(index,traceIdToLocalisationsIndexMap,maxT);
  }
  Assignment[] assigned=new Assignment[10];
  while (nextIndex < localisations.length) {
    if (tracker != null)     tracker.progress(nextIndex,localisations.length);
    final int currentIndex=nextIndex;
    final int t=localisations[currentIndex].t;
    nextIndex=index[t + 1];
    int pastT=FastMath.max(t - timeThreshold,0);
    if (pulseInterval > 0) {
      int intervalBoundary=1 + pulseInterval * ((t - 1) / pulseInterval);
      if (pastT < intervalBoundary)       pastT=intervalBoundary;
    }
    final int pastEndIndex=endIndex[pastT];
    final int currentEndIndex=endIndex[t];
    if (pastEndIndex == currentEndIndex) {
      for (int index=currentIndex; index < nextIndex; index++) {
        localisations[index].trace=addTrace(index,traceIdToLocalisationsIndexMap,maxT);
      }
      continue;
    }
    if (assigned.length < nextIndex - currentIndex) {
      assigned=new Assignment[nextIndex - currentIndex];
    }
    int assignedToTrace=0;
    for (int index=currentIndex; index < nextIndex; index++) {
      int traceId=findForerunner(index,pastEndIndex,currentEndIndex);
      if (traceId == 0) {
        localisations[index].trace=addTrace(index,traceIdToLocalisationsIndexMap,maxT);
      }
 else {
        assigned[assignedToTrace++]=new Assignment(index,minD,traceId);
      }
    }
    if (assignedToTrace > 1) {
      int[] dualAllocation=new int[assignedToTrace];
      int[] ignore=new int[assignedToTrace];
      int ignoreCount=0;
      boolean reSort=true;
      for (int i=0; i < assignedToTrace - 1; i++) {
        if (assigned[i].distance < 0)         continue;
        if (reSort) {
          reSort=false;
          Arrays.sort(assigned,i,assignedToTrace,new Comparator<Assignment>(){
            public int compare(            Assignment o1,            Assignment o2){
              if (o1.distance < o2.distance)               return -1;
              if (o1.distance > o2.distance)               return 1;
              return 0;
            }
          }
);
          if (assigned[i].distance < 0)           continue;
        }
        int dualAllocationCount=0;
        for (int j=i + 1; j < assignedToTrace; j++) {
          if (assigned[i].traceId == assigned[j].traceId)           dualAllocation[dualAllocationCount++]=j;
        }
        ignore[ignoreCount++]=assigned[i].traceId;
        if (dualAllocationCount > 0) {
          for (int a=0; a < dualAllocationCount; a++) {
            final int j=dualAllocation[a];
            final int index=assigned[j].index;
            int traceId=findAlternativeForerunner(index,pastEndIndex,currentEndIndex,ignoreCount,ignore);
            if (traceId == 0) {
              traceId=addTrace(index,traceIdToLocalisationsIndexMap,maxT);
              assigned[j].distance=-1;
            }
 else {
              reSort=true;
              assigned[j].distance=minD;
            }
            assigned[j].traceId=traceId;
          }
        }
        assigned[i].distance=-1;
      }
    }
    for (int i=0; i < assignedToTrace; i++) {
      localisations[assigned[i].index].trace=assigned[i].traceId;
      maxT[assigned[i].traceId]=localisations[assigned[i].index].endT;
    }
  }
  if (tracker != null)   tracker.progress(1.0);
  return getTotalTraces();
}