
org.snpeff.interval.tree.IntervalTreeArray Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of SnpEff Show documentation
Show all versions of SnpEff Show documentation
Variant annotation and effect prediction package.
The newest version!
package org.snpeff.interval.tree;
import java.util.Arrays;
import java.util.Iterator;
import org.snpeff.interval.Genome;
import org.snpeff.interval.Interval;
import org.snpeff.interval.Marker;
import org.snpeff.interval.Markers;
import org.snpeff.util.Gpr;
/**
* Interval tree structure using arrays
* This is slightly faster than the new IntervalTree implementation
*
* @author pcingola
*/
public class IntervalTreeArray implements Itree {
public static final int MIN_MARKERS_PER_LEAF = 4; // This number cannot be less then 3 (see comment in code below)
public static final int INITIAL_CAPACITY = 1024; // Initial capacity for arrays
protected static final Marker[] EMPTY_MARKER_ARRAY = new Marker[0];
protected boolean debug;
protected boolean verbose;
protected Markers markers; // Markers to add
protected boolean inSync; // Do we nend to build the tree?
protected int left[]; // Left subtree (index within this IntervalTreeFileChromo)
protected int right[]; // Right subtree (index within this IntervalTreeFileChromo)
protected int mid[]; // Middle position (genomic coordinate)
protected Marker intersectMarkers[][]; // Markers intersecting this node's center
protected int lastIdx; // Arrays size (index of first unused element in the arrays)
public IntervalTreeArray() {
this(null);
}
/**
* Instantiate an interval tree with a list of intervals
*/
public IntervalTreeArray(Markers markers) {
this.markers = new Markers();
if (markers != null) this.markers.add(markers);
inSync = false;
reset();
}
@Override
public void add(Marker interval) {
markers.add(interval);
inSync = false;
}
@Override
public void add(Markers markers) {
markers.add(markers);
inSync = false;
}
@Override
public void build() {
markers.sort();
reset();
build(markers);
}
/**
* Index intervals from 'start' to 'end' (index in 'markers')
* @return Index of added item (-1 if no item was added)
*/
protected int build(Markers markers) {
if (markers.isEmpty()) return -1;
int idx = nextEntry();
// Calculate median point
int center = markers.getMedian();
// Split markers to the left, to the right and intersecting 'center'
Markers left = new Markers();
Markers right = new Markers();
Markers intersecting = new Markers();
for (Marker interval : markers) {
if (interval.getEnd() < center) left.add(interval);
else if (interval.getStart() > center) right.add(interval);
else intersecting.add(interval);
}
// Convert markers to array
Marker intMarkers[] = null;
if (!intersecting.isEmpty()) intMarkers = intersecting.toArray();
// Recurse
int leftIdx = build(left);
int rightIdx = build(right);
set(idx, leftIdx, rightIdx, center, intMarkers);
return idx;
}
int capacity() {
if (left == null) return 0;
return left.length;
}
@Override
public Markers getIntervals() {
return markers;
}
void grow() {
int oldCapacity = capacity();
int newCapacity = oldCapacity + (oldCapacity >> 1);
left = Arrays.copyOf(left, newCapacity);
right = Arrays.copyOf(right, newCapacity);
mid = Arrays.copyOf(mid, newCapacity);
intersectMarkers = Arrays.copyOf(intersectMarkers, newCapacity);
}
@Override
public boolean isEmpty() {
return markers.isEmpty();
}
@Override
public boolean isInSync() {
return inSync;
}
/**
* Is node 'idx' a leaf node?
*/
boolean isLeaf(int idx) {
return (left[idx] == -1) && (right[idx] == -1);
}
@Override
public Iterator iterator() {
return markers.iterator();
}
@Override
public void load(String fileName, Genome genome) {
throw new RuntimeException("Unimplemented!");
}
/**
* Get next index for entry and make sure there
* is enough capacity to store it
*/
int nextEntry() {
if (lastIdx >= capacity()) grow();
return lastIdx++;
}
/**
* Query index to find all VCF entries intersecting 'marker'
* Store VCF entries in 'results'
*/
@Override
public Markers query(Interval marker) {
Markers results = new Markers();
query(marker, 0, results);
return results;
}
/**
* Query index to find all VCF entries intersecting 'marker', starting from node 'idx'
* Store VCF entries in 'results'
*/
protected void query(Interval marker, int idx, Markers results) {
if (debug) Gpr.debug("query( " + marker + ", " + idx + " )\t" + toString(idx));
// Negative index? Nothing to do
if (idx < 0) return;
// Check all intervals intersecting
queryIntersects(marker, idx, results);
// Recurse left or right
int midPos = mid[idx];
if (debug) Gpr.debug("midPos:" + midPos);
// Recurse left?
if ((marker.getStart() < midPos) && (left[idx] >= 0)) {
query(marker, left[idx], results);
}
// Recurse right?
if ((midPos < marker.getEnd()) && (right[idx] >= 0)) {
query(marker, right[idx], results);
}
}
/**
* Query entries intersecting 'marker' at node 'idx'
*/
protected void queryIntersects(Interval marker, int idx, Markers results) {
if (debug) Gpr.debug("queryIntersects( " + marker + ", " + idx + " )");
// Null? Nothing ti check
if (intersectMarkers[idx] == null) return;
// Check all markers in the intersect
Marker markers[] = intersectMarkers[idx];
for (Marker m : markers) {
if (m.intersects(marker)) {
results.add(m);
if (debug) Gpr.debug("\tMatches entry: " + m);
}
}
}
protected void reset() {
left = new int[INITIAL_CAPACITY];
right = new int[INITIAL_CAPACITY];
mid = new int[INITIAL_CAPACITY];
intersectMarkers = new Marker[INITIAL_CAPACITY][];
lastIdx = 0;
for (int i = 0; i < left.length; i++)
left[i] = right[i] = -1;
}
/**
* Set all parameters in one 'row'
*
* WARNING: If we don't do it this way, we get strange errors
* due to array resizing (array appears to be filled with
* zeros after being set)
*/
void set(int idx, int leftIdx, int rightIdx, int midPos, Marker intMarkers[]) {
left[idx] = leftIdx;
right[idx] = rightIdx;
mid[idx] = midPos;
intersectMarkers[idx] = intMarkers;
}
public void setDebug(boolean debug) {
this.debug = debug;
}
public void setVerbose(boolean verbose) {
this.verbose = verbose;
}
@Override
public int size() {
return markers.size();
}
@Override
public Markers stab(int point) {
Markers results = new Markers();
stab(point, 0, results);
return results;
}
protected void stab(int point, int idx, Markers results) {
if (debug) Gpr.debug("stab( " + point + ", " + idx + " )\t" + toString(idx));
// Negative index? Nothing to do
if (idx < 0) return;
// Check all intervals intersecting
stabIntersects(point, idx, results);
// Recurse left or right
int midPos = mid[idx];
if (debug) Gpr.debug("midPos:" + midPos);
if ((point < midPos) && (left[idx] >= 0)) {
stab(point, left[idx], results);
}
if ((midPos < point) && (right[idx] >= 0)) {
stab(point, right[idx], results);
}
}
/**
* Stab entries intersecting 'point' at node 'idx'
*/
protected void stabIntersects(int point, int idx, Markers results) {
if (debug) Gpr.debug("stabIntersects( " + point + ", " + idx + " )");
// Null? Nothing to check
if (intersectMarkers[idx] == null) return;
// Check all markers in the intersect
Marker markers[] = intersectMarkers[idx];
for (Marker m : markers) {
if (m.intersects(point)) {
results.add(m);
if (debug) Gpr.debug("\tMatches entry: " + m);
}
}
}
@Override
public String toString() {
return "Size: " + lastIdx //
+ ", capacity: " + capacity() //
;
}
public String toString(int idx) {
if (idx < 0) return "None";
StringBuilder sb = new StringBuilder();
sb.append(idx //
+ "\tleftIdx: " + left[idx] //
+ "\trightIdx: " + right[idx] //
+ "\tmidPos: " + mid[idx] //
);
if (intersectMarkers[idx] != null) {
sb.append("\tintersect: (" + intersectMarkers[idx].length + ")\n");
for (int i = 0; i < intersectMarkers[idx].length; i++)
sb.append("\t\t" + i + ":\t" + intersectMarkers[idx][i] + "\n");
}
return sb.toString();
}
public String toStringAll() {
StringBuilder sb = new StringBuilder();
sb.append(toString() + "\n");
for (int i = 0; i < lastIdx; i++)
sb.append("\t" + toString(i) + "\n");
return sb.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy