import java.util.ArrayList;
import java.util.List;
+import java.util.Random;
import org.testng.annotations.Test;
+import intervalstore.api.IntervalStoreI;
+
public class IntervalStoreTest
{
+
+ public static void main(String[] args)
+ {
+ new IntervalStoreTest().defaultTests();
+ }
+
+ private void defaultTests()
+ {
+ testAddAndQueryTiming();
+ }
+
@Test(groups = "Functional")
public void testFindOverlaps_nonNested()
{
- IntervalStore<SimpleFeature> store = new IntervalStore<>();
+ IntervalStore<SimpleFeature> store = new IntervalStoreImpl();
SimpleFeature sf1 = add(store, 10, 20);
// same range different description
SimpleFeature sf2 = new SimpleFeature(10, 20, "desc");
@Test(groups = "Functional")
public void testFindOverlaps_nested()
{
- IntervalStore<SimpleFeature> store = new IntervalStore<>();
+ IntervalStore<SimpleFeature> store = new IntervalStoreImpl();
SimpleFeature sf1 = add(store, 10, 50);
SimpleFeature sf2 = add(store, 10, 40);
SimpleFeature sf3 = add(store, 20, 30);
@Test(groups = "Functional")
public void testFindOverlaps_mixed()
{
- IntervalStore<SimpleFeature> store = new IntervalStore<>();
+ IntervalStore<SimpleFeature> store = new IntervalStoreImpl();
SimpleFeature sf1 = add(store, 10, 50);
SimpleFeature sf2 = add(store, 1, 15);
SimpleFeature sf3 = add(store, 20, 30);
@Test(groups = "Functional")
public void testRemove()
{
- IntervalStore<SimpleFeature> store = new IntervalStore<>();
+ IntervalStore<SimpleFeature> store = new IntervalStoreImpl();
SimpleFeature sf1 = add(store, 10, 20);
assertTrue(store.contains(sf1));
@Test(groups = "Functional")
public void testAdd()
{
- IntervalStore<SimpleFeature> store = new IntervalStore<>();
+ IntervalStore<SimpleFeature> store = new IntervalStoreImpl();
assertFalse(store.add(null));
@Test(groups = "Functional")
public void testAdd_noDuplicates()
{
- IntervalStore<SimpleFeature> store = new IntervalStore<>();
+ IntervalStore<SimpleFeature> store = new IntervalStoreImpl();
SimpleFeature sf1 = new SimpleFeature(10, 20, "Cath");
SimpleFeature sf2 = new SimpleFeature(10, 20, "Cath");
@Test(groups = "Functional")
public void testIsEmpty()
{
- IntervalStore<SimpleFeature> store = new IntervalStore<>();
+ IntervalStore<SimpleFeature> store = new IntervalStoreImpl();
assertTrue(store.isEmpty());
assertEquals(store.size(), 0);
/*
* add a feature and a nested feature
*/
- IntervalStore<SimpleFeature> store = new IntervalStore<>();
+ IntervalStore<SimpleFeature> store = new IntervalStoreImpl();
SimpleFeature sf1 = add(store, 10, 20);
// sf2 is nested in sf1 so will be stored in nestedFeatures
SimpleFeature sf2 = add(store, 12, 14);
@Test(groups = "Functional")
public void testContains()
{
- IntervalStore<SimpleFeature> store = new IntervalStore<>();
+ IntervalStore<SimpleFeature> store = new IntervalStoreImpl();
SimpleFeature sf1 = new SimpleFeature(10, 20, "Cath");
SimpleFeature sf2 = new SimpleFeature(10, 20, "Pfam");
@Test(groups = "Functional")
public void testFindOverlaps_resultsArg_mixed()
{
- IntervalStore<SimpleFeature> store = new IntervalStore<>();
+ IntervalStore<SimpleFeature> store = new IntervalStoreImpl();
SimpleFeature sf1 = add(store, 10, 50);
SimpleFeature sf2 = add(store, 1, 15);
SimpleFeature sf3 = add(store, 20, 30);
@Test(groups = "Functional")
public void testFindOverlaps_resultsArg_nested()
{
- IntervalStore<SimpleFeature> store = new IntervalStore<>();
+ IntervalStore<SimpleFeature> store = new IntervalStoreImpl();
SimpleFeature sf1 = add(store, 10, 50);
SimpleFeature sf2 = add(store, 10, 40);
SimpleFeature sf3 = add(store, 20, 30);
@Test(groups = "Functional")
public void testFindOverlaps_resultsArg_nonNested()
{
- IntervalStore<SimpleFeature> store = new IntervalStore<>();
+ IntervalStore<SimpleFeature> store = new IntervalStoreImpl();
SimpleFeature sf1 = add(store, 10, 20);
// same range different description
SimpleFeature sf2 = new SimpleFeature(10, 20, "desc");
assertTrue(store.findOverlaps(36, 100, overlaps).isEmpty());
assertTrue(store.findOverlaps(1, 9, overlaps).isEmpty());
}
-}
+
+ /**
+ * Compares alternative IntervalStoreI implementations for time to add an
+ * interval then query, at a range of different scales of N (the number of
+ * stored features).
+ */
+ @Test(groups = "Timing")
+ public void testAddAndQueryTiming()
+ {
+ testAddAndQuery(1, 20000000, 10, 20);
+ testAddAndQuery(0, 0, 10, 20);
+
+ testAddAndQuery(1, 20000000, 10, 200);
+ testAddAndQuery(0, 0, 10, 200);
+
+ testAddAndQuery(1, 20000000, 10, 2000);
+ testAddAndQuery(0, 0, 10, 2000);
+
+ testAddAndQuery(1, 20000000, -2000000, 2000000);
+ testAddAndQuery(0, 0, -2000000, 2000000);
+ }
+
+ private void testAddAndQuery(int addstart, int addend, int start, int end)
+ {
+ System.out.println("\nadd: " + addstart + " " + addend + " query: "
+ + start + " " + end);
+ StringBuffer sb = new StringBuffer();
+ IntervalStoreI<SimpleFeature> store;
+ store = new intervalstore.nonc.IntervalStore<>();
+ testAddAndQueryTiming(store, false, sb, addstart, addend, start, end);
+
+ store = new intervalstore.impl.IntervalStore<>();
+ testAddAndQueryTiming(store, true, sb, addstart, addend, start, end);
+
+ System.out.println(sb);
+ }
+
+ /**
+ * Populates the store with intervals, then logs the time taken to add an
+ * interval then query, at a range of different scales of N (the number of
+ * stored features).
+ *
+ * @param store
+ */
+ private void testAddAndQueryTiming(IntervalStoreI<SimpleFeature> store,
+ boolean isNCList, StringBuffer sb, int addstart, int addend,
+ int start, int end)
+ {
+ final int seqlen = 100000; // e.g. length of gene sequence
+ final int repeats = 20;
+ final int K = 1000;
+ final int warmups = 5;
+ final int[] scales = new int[] { 10 * K, 100 * K, 1000 * K };// , 10000 * K
+ // };
+
+ Random r = new Random(732); // fixed seed = repeatable test
+ int counter = 0; // to ensure a distinct description for each feature
+
+ // System.out.println("Scale\titeration\tmicrosecs");
+
+ for (int scale : scales)
+ {
+ /*
+ * add 'scale' features to the store
+ */
+ long ntimeLoad = System.nanoTime();
+ for (int i = 0; i < scale; i++)
+ {
+ SimpleFeature sf;
+ sf = makeFeature(seqlen, r, counter);
+ counter++;
+ store.add(sf);
+ }
+ if (!isNCList)
+ {
+ ((intervalstore.nonc.IntervalStore) store).revalidate();
+ }
+ String line = "time to load " + (isNCList ? "NClist " : "NCArray ")
+ + (System.nanoTime() - ntimeLoad) / K / K + " ms scale "
+ + scale;
+ // System.out.println(line);
+ sb.append(line);
+
+ /*
+ * do "add then query" and log the time taken for the query
+ * we ignore the first 5 repetitions as 'warmups'
+ */
+ long total = 0L;
+ for (int i = 0; i < repeats + warmups; i++)
+ {
+ SimpleFeature sf;
+ if (addstart == 0)
+ {
+ sf = makeFeature(seqlen, r, counter++);
+ }
+ else
+ {
+ sf = new SimpleFeature(addstart, addend, "desc" + counter++);
+ }
+ System.gc();
+ long t1 = System.nanoTime();
+ store.add(sf);
+ store.findOverlaps(start, end);
+ long elapsed = System.nanoTime() - t1;
+ if (i >= warmups)
+ {
+ total += elapsed;
+ // System.out.println(
+ // String.format("%d\t%d\t%d", scale, i - warmups,
+ // elapsed / K));
+ }
+ }
+ sb.append(
+ " add+query "
+ + (isNCList ? "NCList " : "NCArray ")
+ + (total / (K * repeats)) + " microseconds\n");
+ }
+ }
+
+ SimpleFeature makeFeature(final int seqlen, Random r, int counter)
+ {
+ int i1 = r.nextInt(seqlen);
+ int i2 = r.nextInt(seqlen);
+ int from = Math.min(i1, i2);
+ int to = Math.max(i1, i2);
+ SimpleFeature sf = new SimpleFeature(from, to, "desc" + counter);
+ return sf;
+ }
+}
\ No newline at end of file