import java.util.Arrays;
import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
/**
* A helper class to sort all annotations associated with an alignment in
}
}
+ // the alignment with respect to which annotations are sorted
private final AlignmentI alignment;
+ // user preference for placement of non-sequence annotations
private boolean showAutocalcAbove;
+ // working map of sequence index in alignment
+ private final Map<SequenceI, Integer> sequenceIndices = new HashMap<SequenceI, Integer>();
+
/**
* Constructor given an alignment and the location (top or bottom) of
* Consensus and similar.
public void sort(AlignmentAnnotation[] alignmentAnnotations,
SequenceAnnotationOrder order)
{
+ // cache 'alignment sequence position' for the annotations
+ saveSequenceIndices(alignmentAnnotations);
+
Comparator<? super AlignmentAnnotation> comparator = getComparator(order);
if (alignmentAnnotations != null)
}
/**
+ * Calculate and save in a temporary map the position of each annotation's
+ * sequence (if it has one) in the alignment. Faster to do this once than for
+ * every annotation comparison.
+ *
+ * @param alignmentAnnotations
+ */
+ private void saveSequenceIndices(
+ AlignmentAnnotation[] alignmentAnnotations)
+ {
+ sequenceIndices.clear();
+ for (AlignmentAnnotation ann : alignmentAnnotations) {
+ SequenceI seq = ann.sequenceRef;
+ if (seq != null) {
+ int index = AlignmentUtils.getSequenceIndex(alignment, seq);
+ sequenceIndices.put(seq, index);
+ }
+ }
+ }
+
+ /**
* Get the comparator for the specified sort order.
*
* @param order
return showAutocalcAbove ? 1 : -1;
}
// get sequence index - but note -1 means 'at end' so needs special handling
- int index1 = AlignmentUtils.getSequenceIndex(alignment, seq1);
- int index2 = AlignmentUtils.getSequenceIndex(alignment, seq2);
+ int index1 = sequenceIndices.get(seq1);
+ int index2 = sequenceIndices.get(seq2);
if (index1 == index2)
{
return 0;
package jalview.analysis;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentAnnotation;
@Test
public void testSort_timingPresorted()
{
- final long targetTime = 100; // ms
- final int numSeqs = 10000;
- final int numAnns = 20000;
+ testTiming_presorted(50, 100);
+ testTiming_presorted(500, 1000);
+ testTiming_presorted(5000, 10000);
+ }
+
+ /**
+ * Test timing to sort annotations already in the sort order.
+ *
+ * @param numSeqs
+ * @param numAnns
+ */
+ private void testTiming_presorted(final int numSeqs, final int numAnns)
+ {
al = buildAlignment(numSeqs);
anns = buildAnnotations(numAnns);
System.out.println("Timing test for presorted " + numSeqs
+ " sequences and "
+ numAnns + " annotations took " + elapsed + "ms");
- assertTrue("Sort took more than " + targetTime + "ms",
- elapsed <= targetTime);
}
/**
- * Timing test for sorting randomly sorted annotations
+ * Timing tests for sorting randomly sorted annotations for various sizes.
*/
@Test
public void testSort_timingUnsorted()
{
- final int numSeqs = 2000;
- final int numAnns = 4000;
+ testTiming_unsorted(50, 100);
+ testTiming_unsorted(500, 1000);
+ testTiming_unsorted(5000, 10000);
+ }
+
+ /**
+ * Generate annotations randomly sorted with respect to sequences, and time
+ * sorting.
+ *
+ * @param numSeqs
+ * @param numAnns
+ */
+ private void testTiming_unsorted(final int numSeqs, final int numAnns)
+ {
al = buildAlignment(numSeqs);
anns = buildAnnotations(numAnns);
@Test
public void testSort_timingSemisorted()
{
- final int numSeqs = 2000;
- final int numAnns = 4000;
+ testTiming_semiSorted(50, 100);
+ testTiming_semiSorted(500, 1000);
+ testTiming_semiSorted(5000, 10000);
+ }
+
+ /**
+ * Mimic 'semi-sorted' annotations:
+ * <ul>
+ * <li>set up in sequence order, with randomly assigned labels from a limited
+ * range</li>
+ * <li>sort by label and sequence order, report timing</li>
+ * <li>resort by sequence and label, report timing</li>
+ * <li>resort by label and sequence, report timing</li>
+ * </ul>
+ *
+ * @param numSeqs
+ * @param numAnns
+ */
+ private void testTiming_semiSorted(final int numSeqs, final int numAnns)
+ {
al = buildAlignment(numSeqs);
anns = buildAnnotations(numAnns);
testee.sort(anns, SequenceAnnotationOrder.LABEL_AND_SEQUENCE);
long endTime = System.currentTimeMillis();
long elapsed = endTime - startTime;
- System.out.println("Sort by type for semisorted " + numSeqs
+ System.out.println("Sort by label for semisorted " + numSeqs
+ " sequences and "
+ numAnns + " annotations took " + elapsed + "ms");
+ " sequences and " + numAnns + " annotations took " + elapsed
+ "ms");
- // now resort by type
+ // now resort by label
startTime = System.currentTimeMillis();
testee.sort(anns, SequenceAnnotationOrder.LABEL_AND_SEQUENCE);
endTime = System.currentTimeMillis();
elapsed = endTime - startTime;
- System.out.println("Resort by type for semisorted " + numSeqs
+ System.out.println("Resort by label for semisorted " + numSeqs
+ " sequences and " + numAnns + " annotations took " + elapsed
+ "ms");
}