ranges)
+ {
+ boolean forwardStrand = true;
+ for (int[] range : ranges)
{
- System.err.println("Failed test locate from " + i + " to " + j);
- for (int c = 0; c < frm.length; c++)
+ if (range[1] > range[0])
{
- System.err.print(frm[c] + ((c % 2 == 0) ? "," : ";"));
+ break; // forward strand confirmed
}
- System.err.println("Expected");
- for (int c = 0; c < ks.length; c++)
+ else if (range[1] < range[0])
{
- System.err.print(ks[c] + ((c % 2 == 0) ? "," : ";"));
+ forwardStrand = false;
+ break; // reverse strand confirmed
}
}
+ return forwardStrand;
}
/**
*
- * @return a MapList whose From range is this maplist's To Range, and vice
- * versa
+ * @return true if from, or to is a three to 1 mapping
*/
- public MapList getInverse()
+ public boolean isTripletMap()
{
- return new MapList(getToRanges(), getFromRanges(), getToRatio(),
- getFromRatio());
+ return (toRatio == 3 && fromRatio == 1)
+ || (fromRatio == 3 && toRatio == 1);
}
/**
- * test for containment rather than equivalence to another mapping
+ * Returns a map which is the composite of this one and the input map. That
+ * is, the output map has the fromRanges of this map, and its toRanges are the
+ * toRanges of this map as transformed by the input map.
+ *
+ * Returns null if the mappings cannot be traversed (not all toRanges of this
+ * map correspond to fromRanges of the input), or if this.toRatio does not
+ * match map.fromRatio.
+ *
+ *
+ * Example 1:
+ * this: from [1-100] to [501-600]
+ * input: from [10-40] to [60-90]
+ * output: from [10-40] to [560-590]
+ * Example 2 ('reverse strand exons'):
+ * this: from [1-100] to [2000-1951], [1000-951] // transcript to loci
+ * input: from [1-50] to [41-90] // CDS to transcript
+ * output: from [10-40] to [1960-1951], [1000-971] // CDS to gene loci
+ *
*
* @param map
- * to be tested for containment
- * @return true if local or mapped range map contains or is contained by this
- * mapping
+ * @return
*/
- public boolean containsEither(boolean local, MapList map)
+ public MapList traverse(MapList map)
{
- if (local)
+ if (map == null)
{
- return ((getFromLowest() >= map.getFromLowest() && getFromHighest() <= map
- .getFromHighest()) || (getFromLowest() <= map.getFromLowest() && getFromHighest() >= map
- .getFromHighest()));
+ return null;
}
- else
+
+ /*
+ * compound the ratios by this rule:
+ * A:B with M:N gives A*M:B*N
+ * reduced by greatest common divisor
+ * so 1:3 with 3:3 is 3:9 or 1:3
+ * 1:3 with 3:1 is 3:3 or 1:1
+ * 1:3 with 1:3 is 1:9
+ * 2:5 with 3:7 is 6:35
+ */
+ int outFromRatio = getFromRatio() * map.getFromRatio();
+ int outToRatio = getToRatio() * map.getToRatio();
+ int gcd = MathUtils.gcd(outFromRatio, outToRatio);
+ outFromRatio /= gcd;
+ outToRatio /= gcd;
+
+ List toRanges = new ArrayList<>();
+ for (int[] range : getToRanges())
{
- return ((getToLowest() >= map.getToLowest() && getToHighest() <= map
- .getToHighest()) || (getToLowest() <= map.getToLowest() && getToHighest() >= map
- .getToHighest()));
+ int[] transferred = map.locateInTo(range[0], range[1]);
+ if (transferred == null || transferred.length % 2 != 0)
+ {
+ return null;
+ }
+
+ /*
+ * convert [start1, end1, start2, end2, ...]
+ * to [[start1, end1], [start2, end2], ...]
+ */
+ for (int i = 0; i < transferred.length;)
+ {
+ toRanges.add(new int[] { transferred[i], transferred[i + 1] });
+ i += 2;
+ }
}
+
+ return new MapList(getFromRanges(), toRanges, outFromRatio, outToRatio);
+ }
+
+ /**
+ * Answers true if the mapping is from one contiguous range to another, else
+ * false
+ *
+ * @return
+ */
+ public boolean isContiguous()
+ {
+ return fromShifts.size() == 1 && toShifts.size() == 1;
}
}