2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.analysis;
23 import static org.testng.AssertJUnit.assertEquals;
25 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
26 import jalview.datamodel.Alignment;
27 import jalview.datamodel.AlignmentAnnotation;
28 import jalview.datamodel.Sequence;
29 import jalview.datamodel.SequenceI;
30 import jalview.gui.JvOptionPane;
32 import java.util.ArrayList;
33 import java.util.List;
34 import java.util.Random;
36 import org.testng.annotations.BeforeClass;
37 import org.testng.annotations.BeforeMethod;
38 import org.testng.annotations.Test;
40 public class AnnotationSorterTest
43 @BeforeClass(alwaysRun = true)
44 public void setUpJvOptionPane()
46 JvOptionPane.setInteractiveMode(false);
47 JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
50 private static final int NUM_SEQS = 6;
52 private static final int NUM_ANNS = 7;
54 private static final String SS = "secondary structure";
56 AlignmentAnnotation[] anns = new AlignmentAnnotation[0];
61 * Set up 6 sequences and 7 annotations.
63 @BeforeMethod(alwaysRun = true)
66 al = buildAlignment(NUM_SEQS);
67 anns = buildAnnotations(NUM_ANNS);
71 * Construct an array of numAnns annotations
77 protected AlignmentAnnotation[] buildAnnotations(int numAnns)
79 List<AlignmentAnnotation> annlist = new ArrayList<AlignmentAnnotation>();
80 for (int i = 0; i < numAnns; i++)
82 AlignmentAnnotation ann = new AlignmentAnnotation(SS + i, "", 0);
85 return annlist.toArray(anns);
89 * Make an alignment with numSeqs sequences in it.
95 private Alignment buildAlignment(int numSeqs)
97 SequenceI[] seqs = new Sequence[numSeqs];
98 for (int i = 0; i < numSeqs; i++)
100 seqs[i] = new Sequence("Sequence" + i, "axrdkfp");
102 return new Alignment(seqs);
106 * Test sorting by annotation type (label) within sequence order, including
108 * <li>annotations with no sequence reference - sort to end keeping mutual
110 * <li>annotations with sequence ref = sort in sequence order</li>
111 * <li>multiple annotations for same sequence ref - sort by label
112 * non-case-specific</li>
113 * <li>annotations with reference to sequence not in alignment - treat like no
117 @Test(groups = { "Functional" })
118 public void testSortBySequenceAndType_autocalcLast()
121 anns[0].sequenceRef = al.getSequenceAt(1); anns[0].label = "label0";
122 anns[1].sequenceRef = al.getSequenceAt(3); anns[1].label = "structure";
123 anns[2].sequenceRef = al.getSequenceAt(3); anns[2].label = "iron";
124 anns[3].autoCalculated = true; anns[3].label = "Quality";
125 anns[4].autoCalculated = true; anns[4].label = "Consensus";
126 anns[5].sequenceRef = al.getSequenceAt(0); anns[5].label = "label5";
127 anns[6].sequenceRef = al.getSequenceAt(3); anns[6].label = "IRP";
130 AnnotationSorter testee = new AnnotationSorter(al, false);
131 testee.sort(anns, SequenceAnnotationOrder.SEQUENCE_AND_LABEL);
132 assertEquals("label5", anns[0].label); // for sequence 0
133 assertEquals("label0", anns[1].label); // for sequence 1
134 assertEquals("iron", anns[2].label); // sequence 3 /iron
135 assertEquals("IRP", anns[3].label); // sequence 3/IRP
136 assertEquals("structure", anns[4].label); // sequence 3/structure
137 assertEquals("Quality", anns[5].label); // autocalc annotations
138 assertEquals("Consensus", anns[6].label); // retain ordering
142 * Variant with autocalculated annotations sorting to front
144 @Test(groups = { "Functional" })
145 public void testSortBySequenceAndType_autocalcFirst()
148 anns[0].sequenceRef = al.getSequenceAt(1); anns[0].label = "label0";
149 anns[1].sequenceRef = al.getSequenceAt(3); anns[1].label = "structure";
150 anns[2].sequenceRef = al.getSequenceAt(3); anns[2].label = "iron";
151 anns[3].autoCalculated = true; anns[3].label = "Quality";
152 anns[4].autoCalculated = true; anns[4].label = "Consensus";
153 anns[5].sequenceRef = al.getSequenceAt(0); anns[5].label = "label5";
154 anns[6].sequenceRef = al.getSequenceAt(3); anns[6].label = "IRP";
157 AnnotationSorter testee = new AnnotationSorter(al, true);
158 testee.sort(anns, SequenceAnnotationOrder.SEQUENCE_AND_LABEL);
159 assertEquals("Quality", anns[0].label); // autocalc annotations
160 assertEquals("Consensus", anns[1].label); // retain ordering
161 assertEquals("label5", anns[2].label); // for sequence 0
162 assertEquals("label0", anns[3].label); // for sequence 1
163 assertEquals("iron", anns[4].label); // sequence 3 /iron
164 assertEquals("IRP", anns[5].label); // sequence 3/IRP
165 assertEquals("structure", anns[6].label); // sequence 3/structure
169 * Test sorting by annotation type (label) within sequence order, including
171 * <li>annotations with no sequence reference - sort to end keeping mutual
173 * <li>annotations with sequence ref = sort in sequence order</li>
174 * <li>multiple annotations for same sequence ref - sort by label
175 * non-case-specific</li>
176 * <li>annotations with reference to sequence not in alignment - treat like no
180 @Test(groups = { "Functional" })
181 public void testSortByTypeAndSequence_autocalcLast()
184 anns[0].sequenceRef = al.getSequenceAt(1); anns[0].label = "label0";
185 anns[1].sequenceRef = al.getSequenceAt(3); anns[1].label = "structure";
186 anns[2].sequenceRef = al.getSequenceAt(3); anns[2].label = "iron";
187 anns[3].autoCalculated = true; anns[3].label = "Quality";
188 anns[4].autoCalculated = true; anns[4].label = "Consensus";
189 anns[5].sequenceRef = al.getSequenceAt(0); anns[5].label = "IRON";
190 anns[6].sequenceRef = al.getSequenceAt(2); anns[6].label = "Structure";
193 AnnotationSorter testee = new AnnotationSorter(al, false);
194 testee.sort(anns, SequenceAnnotationOrder.LABEL_AND_SEQUENCE);
195 assertEquals("IRON", anns[0].label); // IRON / sequence 0
196 assertEquals("iron", anns[1].label); // iron / sequence 3
197 assertEquals("label0", anns[2].label); // label0 / sequence 1
198 assertEquals("Structure", anns[3].label); // Structure / sequence 2
199 assertEquals("structure", anns[4].label); // structure / sequence 3
200 assertEquals("Quality", anns[5].label); // autocalc annotations
201 assertEquals("Consensus", anns[6].label); // retain ordering
205 * Variant of test with autocalculated annotations sorted to front
207 @Test(groups = { "Functional" })
208 public void testSortByTypeAndSequence_autocalcFirst()
211 anns[0].sequenceRef = al.getSequenceAt(1); anns[0].label = "label0";
212 anns[1].sequenceRef = al.getSequenceAt(3); anns[1].label = "structure";
213 anns[2].sequenceRef = al.getSequenceAt(3); anns[2].label = "iron";
214 anns[3].autoCalculated = true; anns[3].label = "Quality";
215 anns[4].autoCalculated = true; anns[4].label = "Consensus";
216 anns[5].sequenceRef = al.getSequenceAt(0); anns[5].label = "IRON";
217 anns[6].sequenceRef = al.getSequenceAt(2); anns[6].label = "Structure";
220 AnnotationSorter testee = new AnnotationSorter(al, true);
221 testee.sort(anns, SequenceAnnotationOrder.LABEL_AND_SEQUENCE);
222 assertEquals("Quality", anns[0].label); // autocalc annotations
223 assertEquals("Consensus", anns[1].label); // retain ordering
224 assertEquals("IRON", anns[2].label); // IRON / sequence 0
225 assertEquals("iron", anns[3].label); // iron / sequence 3
226 assertEquals("label0", anns[4].label); // label0 / sequence 1
227 assertEquals("Structure", anns[5].label); // Structure / sequence 2
228 assertEquals("structure", anns[6].label); // structure / sequence 3
232 * Variant of test with autocalculated annotations sorted to front but
233 * otherwise no change.
235 @Test(groups = { "Functional" })
236 public void testNoSort_autocalcFirst()
239 anns[0].sequenceRef = al.getSequenceAt(1); anns[0].label = "label0";
240 anns[1].sequenceRef = al.getSequenceAt(3); anns[1].label = "structure";
241 anns[2].sequenceRef = al.getSequenceAt(3); anns[2].label = "iron";
242 anns[3].autoCalculated = true; anns[3].label = "Quality";
243 anns[4].autoCalculated = true; anns[4].label = "Consensus";
244 anns[5].sequenceRef = al.getSequenceAt(0); anns[5].label = "IRON";
245 anns[6].sequenceRef = al.getSequenceAt(2); anns[6].label = "Structure";
248 AnnotationSorter testee = new AnnotationSorter(al, true);
249 testee.sort(anns, SequenceAnnotationOrder.NONE);
250 assertEquals("Quality", anns[0].label); // autocalc annotations
251 assertEquals("Consensus", anns[1].label); // retain ordering
252 assertEquals("label0", anns[2].label);
253 assertEquals("structure", anns[3].label);
254 assertEquals("iron", anns[4].label);
255 assertEquals("IRON", anns[5].label);
256 assertEquals("Structure", anns[6].label);
259 @Test(groups = { "Functional" })
260 public void testSort_timingPresorted()
262 testTiming_presorted(50, 100);
263 testTiming_presorted(500, 1000);
264 testTiming_presorted(5000, 10000);
268 * Test timing to sort annotations already in the sort order.
273 private void testTiming_presorted(final int numSeqs, final int numAnns)
275 Alignment alignment = buildAlignment(numSeqs);
276 AlignmentAnnotation[] annotations = buildAnnotations(numAnns);
279 * Set the annotations presorted by label
281 Random r = new Random();
282 final SequenceI[] sequences = alignment.getSequencesArray();
283 for (int i = 0; i < annotations.length; i++)
285 SequenceI randomSequenceRef = sequences[r.nextInt(sequences.length)];
286 annotations[i].sequenceRef = randomSequenceRef;
287 annotations[i].label = "label" + i;
289 long startTime = System.currentTimeMillis();
290 AnnotationSorter testee = new AnnotationSorter(alignment, false);
291 testee.sort(annotations, SequenceAnnotationOrder.LABEL_AND_SEQUENCE);
292 long endTime = System.currentTimeMillis();
293 final long elapsed = endTime - startTime;
294 System.out.println("Timing test for presorted " + numSeqs
295 + " sequences and " + numAnns + " annotations took " + elapsed
300 * Timing tests for sorting randomly sorted annotations for various sizes.
302 @Test(groups = { "Functional" })
303 public void testSort_timingUnsorted()
305 testTiming_unsorted(50, 100);
306 testTiming_unsorted(500, 1000);
307 testTiming_unsorted(5000, 10000);
311 * Generate annotations randomly sorted with respect to sequences, and time
317 private void testTiming_unsorted(final int numSeqs, final int numAnns)
319 Alignment alignment = buildAlignment(numSeqs);
320 AlignmentAnnotation[] annotations = buildAnnotations(numAnns);
323 * Set the annotations in random order with respect to the sequences
325 Random r = new Random();
326 final SequenceI[] sequences = alignment.getSequencesArray();
327 for (int i = 0; i < annotations.length; i++)
329 SequenceI randomSequenceRef = sequences[r.nextInt(sequences.length)];
330 annotations[i].sequenceRef = randomSequenceRef;
331 annotations[i].label = "label" + i;
333 long startTime = System.currentTimeMillis();
334 AnnotationSorter testee = new AnnotationSorter(alignment, false);
335 testee.sort(annotations, SequenceAnnotationOrder.SEQUENCE_AND_LABEL);
336 long endTime = System.currentTimeMillis();
337 final long elapsed = endTime - startTime;
338 System.out.println("Timing test for unsorted " + numSeqs
339 + " sequences and " + numAnns + " annotations took " + elapsed
344 * Timing test for sorting annotations with a limited range of types (labels).
346 @Test(groups = { "Functional" })
347 public void testSort_timingSemisorted()
349 testTiming_semiSorted(50, 100);
350 testTiming_semiSorted(500, 1000);
351 testTiming_semiSorted(5000, 10000);
355 * Mimic 'semi-sorted' annotations:
357 * <li>set up in sequence order, with randomly assigned labels from a limited
359 * <li>sort by label and sequence order, report timing</li>
360 * <li>resort by sequence and label, report timing</li>
361 * <li>resort by label and sequence, report timing</li>
367 private void testTiming_semiSorted(final int numSeqs, final int numAnns)
369 Alignment alignment = buildAlignment(numSeqs);
370 AlignmentAnnotation[] annotations = buildAnnotations(numAnns);
372 String[] labels = new String[] { "label1", "label2", "label3",
373 "label4", "label5", "label6" };
376 * Set the annotations in sequence order with randomly assigned labels.
378 Random r = new Random();
379 final SequenceI[] sequences = alignment.getSequencesArray();
380 for (int i = 0; i < annotations.length; i++)
382 SequenceI sequenceRef = sequences[i % sequences.length];
383 annotations[i].sequenceRef = sequenceRef;
384 annotations[i].label = labels[r.nextInt(labels.length)];
386 long startTime = System.currentTimeMillis();
387 AnnotationSorter testee = new AnnotationSorter(alignment, false);
388 testee.sort(annotations, SequenceAnnotationOrder.LABEL_AND_SEQUENCE);
389 long endTime = System.currentTimeMillis();
390 long elapsed = endTime - startTime;
391 System.out.println("Sort by label for semisorted " + numSeqs
392 + " sequences and " + numAnns + " annotations took " + elapsed
395 // now resort by sequence
396 startTime = System.currentTimeMillis();
397 testee.sort(annotations, SequenceAnnotationOrder.SEQUENCE_AND_LABEL);
398 endTime = System.currentTimeMillis();
399 elapsed = endTime - startTime;
400 System.out.println("Resort by sequence for semisorted " + numSeqs
401 + " sequences and " + numAnns + " annotations took " + elapsed
404 // now resort by label
405 startTime = System.currentTimeMillis();
406 testee.sort(annotations, SequenceAnnotationOrder.LABEL_AND_SEQUENCE);
407 endTime = System.currentTimeMillis();
408 elapsed = endTime - startTime;
409 System.out.println("Resort by label for semisorted " + numSeqs
410 + " sequences and " + numAnns + " annotations took " + elapsed