2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3 * Copyright (C) 2014 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.
23 import java.util.Enumeration;
24 import java.util.Vector;
27 * MapList Simple way of bijectively mapping a non-contiguous linear range to
28 * another non-contiguous linear range Use at your own risk! TODO: efficient
29 * implementation of private posMap method TODO: test/ensure that sense of from
30 * and to ratio start position is conserved (codon start position recovery)
31 * TODO: optimize to use int[][] arrays rather than vectors.
38 * @see java.lang.Object#equals(java.lang.Object)
40 public boolean equals(MapList obj)
46 if (obj != null && obj.fromRatio == fromRatio && obj.toRatio == toRatio
47 && obj.fromShifts != null && obj.toShifts != null)
49 int i, iSize = fromShifts.size(), j, jSize = obj.fromShifts.size();
54 for (i = 0, iSize = fromShifts.size(), j = 0, jSize = obj.fromShifts
57 int[] mi = (int[]) fromShifts.elementAt(i++);
58 int[] mj = (int[]) obj.fromShifts.elementAt(j++);
59 if (mi[0] != mj[0] || mi[1] != mj[1])
64 iSize = toShifts.size();
65 jSize = obj.toShifts.size();
70 for (i = 0, j = 0; i < iSize;)
72 int[] mi = (int[]) toShifts.elementAt(i++);
73 int[] mj = (int[]) obj.toShifts.elementAt(j++);
74 if (mi[0] != mj[0] || mi[1] != mj[1])
84 public Vector fromShifts;
86 public Vector toShifts;
88 int fromRatio; // number of steps in fromShifts to one toRatio unit
90 int toRatio; // number of steps in toShifts to one fromRatio
94 * @return series of intervals mapped in from
96 public int[] getFromRanges()
98 return getRanges(fromShifts);
101 public int[] getToRanges()
103 return getRanges(toShifts);
106 private int[] getRanges(Vector shifts)
108 int[] rnges = new int[2 * shifts.size()];
109 Enumeration e = shifts.elements();
111 while (e.hasMoreElements())
113 int r[] = (int[]) e.nextElement();
121 * lowest and highest value in the from Map
123 int[] fromRange = null;
126 * lowest and highest value in the to Map
128 int[] toRange = null;
132 * @return length of mapped phrase in from
134 public int getFromRatio()
141 * @return length of mapped phrase in to
143 public int getToRatio()
148 public int getFromLowest()
153 public int getFromHighest()
158 public int getToLowest()
163 public int getToHighest()
168 private void ensureRange(int[] limits, int pos)
180 public MapList(int from[], int to[], int fromRatio, int toRatio)
182 fromRange = new int[]
183 { from[0], from[1] };
187 fromShifts = new Vector();
188 for (int i = 0; i < from.length; i += 2)
190 ensureRange(fromRange, from[i]);
191 ensureRange(fromRange, from[i + 1]);
193 fromShifts.addElement(new int[]
194 { from[i], from[i + 1] });
196 toShifts = new Vector();
197 for (int i = 0; i < to.length; i += 2)
199 ensureRange(toRange, to[i]);
200 ensureRange(toRange, to[i + 1]);
201 toShifts.addElement(new int[]
202 { to[i], to[i + 1] });
204 this.fromRatio = fromRatio;
205 this.toRatio = toRatio;
208 public MapList(MapList map)
210 this.fromRange = new int[]
211 { map.fromRange[0], map.fromRange[1] };
212 this.toRange = new int[]
213 { map.toRange[0], map.toRange[1] };
214 this.fromRatio = map.fromRatio;
215 this.toRatio = map.toRatio;
216 if (map.fromShifts != null)
218 this.fromShifts = new Vector();
219 Enumeration e = map.fromShifts.elements();
220 while (e.hasMoreElements())
222 int[] el = (int[]) e.nextElement();
223 fromShifts.addElement(new int[]
227 if (map.toShifts != null)
229 this.toShifts = new Vector();
230 Enumeration e = map.toShifts.elements();
231 while (e.hasMoreElements())
233 int[] el = (int[]) e.nextElement();
234 toShifts.addElement(new int[]
241 * get all mapped positions from 'from' to 'to'
243 * @return int[][] { int[] { fromStart, fromFinish, toStart, toFinish }, int
244 * [fromFinish-fromStart+2] { toStart..toFinish mappings}}
246 public int[][] makeFromMap()
248 return posMap(fromShifts, fromRatio, toShifts, toRatio);
252 * get all mapped positions from 'to' to 'from'
254 * @return int[to position]=position mapped in from
256 public int[][] makeToMap()
258 return posMap(toShifts, toRatio, fromShifts, fromRatio);
262 * construct an int map for intervals in intVals
265 * @return int[] { from, to pos in range }, int[range.to-range.from+1]
266 * returning mapped position
268 private int[][] posMap(Vector intVals, int ratio, Vector toIntVals,
271 int iv = 0, ivSize = intVals.size();
276 int[] intv = (int[]) intVals.elementAt(iv++);
277 int from = intv[0], to = intv[1];
285 intv = (int[]) intVals.elementAt(iv++);
304 int mp[][] = new int[to - from + 2][];
305 for (int i = 0; i < mp.length; i++)
307 int[] m = shift(i + from, intVals, ratio, toIntVals, toRatio);
328 int[][] map = new int[][]
330 { from, to, tF, tT }, new int[to - from + 2] };
335 for (int i = 0; i < mp.length; i++)
339 map[1][i] = mp[i][0] - tF;
343 map[1][i] = -1; // indicates an out of range mapping
353 * start position for shift (in original reference frame)
357 * public void addShift(int pos, int shift) { int sidx = 0; int[]
358 * rshift=null; while (sidx<shifts.size() && (rshift=(int[])
359 * shifts.elementAt(sidx))[0]<pos) sidx++; if (sidx==shifts.size())
360 * shifts.insertElementAt(new int[] { pos, shift}, sidx); else
361 * rshift[1]+=shift; }
364 * shift from pos to To(pos)
368 * @return int shifted position in To, frameshift in From, direction of mapped
371 public int[] shiftFrom(int pos)
373 return shift(pos, fromShifts, fromRatio, toShifts, toRatio);
377 * inverse of shiftFrom - maps pos in To to a position in From
381 * @return shifted position in From, frameshift in To, direction of mapped
384 public int[] shiftTo(int pos)
386 return shift(pos, toShifts, toRatio, fromShifts, fromRatio);
397 private int[] shift(int pos, Vector fromShifts, int fromRatio,
398 Vector toShifts, int toRatio)
400 int[] fromCount = countPos(fromShifts, pos);
401 if (fromCount == null)
405 int fromRemainder = (fromCount[0] - 1) % fromRatio;
406 int toCount = 1 + (((fromCount[0] - 1) / fromRatio) * toRatio);
407 int[] toPos = countToPos(toShifts, toCount);
410 return null; // throw new Error("Bad Mapping!");
412 // System.out.println(fromCount[0]+" "+fromCount[1]+" "+toCount);
414 { toPos[0], fromRemainder, toPos[1] };
418 * count how many positions pos is along the series of intervals.
422 * @return number of positions or null if pos is not within intervals
424 private int[] countPos(Vector intVals, int pos)
426 int count = 0, intv[], iv = 0, ivSize = intVals.size();
429 intv = (int[]) intVals.elementAt(iv++);
430 if (intv[0] <= intv[1])
432 if (pos >= intv[0] && pos <= intv[1])
435 { count + pos - intv[0] + 1, +1 };
439 count += intv[1] - intv[0] + 1;
444 if (pos >= intv[1] && pos <= intv[0])
447 { count + intv[0] - pos + 1, -1 };
451 count += intv[0] - intv[1] + 1;
459 * count out pos positions into a series of intervals and return the position
463 * @return position pos in interval set
465 private int[] countToPos(Vector intVals, int pos)
467 int count = 0, diff = 0, iv = 0, ivSize = intVals.size(), intv[] =
471 intv = (int[]) intVals.elementAt(iv++);
472 diff = intv[1] - intv[0];
475 if (pos <= count + 1 + diff)
478 { pos - count - 1 + intv[0], +1 };
487 if (pos <= count + 1 - diff)
490 { intv[0] - (pos - count - 1), -1 };
498 return null;// (diff<0) ? (intv[1]-1) : (intv[0]+1);
502 * find series of intervals mapping from start-end in the From map.
508 * @return series of ranges in from map
510 public int[] locateInFrom(int start, int end)
512 // inefficient implementation
513 int fromStart[] = shiftTo(start);
514 int fromEnd[] = shiftTo(end); // needs to be inclusive of end of symbol
516 if (fromStart == null || fromEnd == null)
520 int iv[] = getIntervals(fromShifts, fromStart, fromEnd, fromRatio);
525 * find series of intervals mapping from start-end in the to map.
528 * position in from map
530 * position in from map
531 * @return series of ranges in to map
533 public int[] locateInTo(int start, int end)
535 // inefficient implementation
536 int toStart[] = shiftFrom(start);
537 int toEnd[] = shiftFrom(end);
538 if (toStart == null || toEnd == null)
542 int iv[] = getIntervals(toShifts, toStart, toEnd, toRatio);
547 * like shift - except returns the intervals in the given vector of shifts
548 * which were spanned in traversing fromStart to fromEnd
554 * @return series of from,to intervals from from first position of starting
555 * region to final position of ending region inclusive
557 private int[] getIntervals(Vector fromShifts2, int[] fromStart,
558 int[] fromEnd, int fromRatio2)
560 int startpos, endpos;
561 startpos = fromStart[0]; // first position in fromStart
562 endpos = fromEnd[0]; // last position in fromEnd
563 int endindx = (fromRatio2 - 1); // additional positions to get to last
564 // position from endpos
565 int intv = 0, intvSize = fromShifts2.size();
566 int iv[], i = 0, fs = -1, fe_s = -1, fe = -1; // containing intervals
567 // search intervals to locate ones containing startpos and count endindx
568 // positions on from endpos
569 while (intv < intvSize && (fs == -1 || fe == -1))
571 iv = (int[]) fromShifts2.elementAt(intv++);
574 endpos = iv[0]; // start counting from beginning of interval
575 endindx--; // inclusive of endpos
579 if (fs == -1 && startpos >= iv[0] && startpos <= iv[1])
583 if (endpos >= iv[0] && endpos <= iv[1])
591 if (endpos + endindx <= iv[1])
594 endpos = endpos + endindx; // end of end token is within this
599 endindx -= iv[1] - endpos; // skip all this interval too
606 if (fs == -1 && startpos <= iv[0] && startpos >= iv[1])
610 if (endpos <= iv[0] && endpos >= iv[1])
618 if (endpos - endindx >= iv[1])
621 endpos = endpos - endindx; // end of end token is within this
626 endindx -= endpos - iv[1]; // skip all this interval too
633 if (fs == fe && fe == -1)
637 Vector ranges = new Vector();
642 // truncate initial interval
643 iv = (int[]) fromShifts2.elementAt(intv++);
645 { iv[0], iv[1] };// clone
652 ranges.addElement(iv); // add initial range
653 iv = (int[]) fromShifts2.elementAt(intv++); // get next interval
655 { iv[0], iv[1] };// clone
662 ranges.addElement(iv); // add only - or final range
666 // walk from end of interval.
667 i = fromShifts2.size() - 1;
672 iv = (int[]) fromShifts2.elementAt(i);
674 { iv[1], iv[0] };// reverse and clone
675 // truncate initial interval
681 { // fix apparent logic bug when fe==-1
682 ranges.addElement(iv); // add (truncated) reversed interval
683 iv = (int[]) fromShifts2.elementAt(i);
685 { iv[1], iv[0] }; // reverse and clone
689 // interval is already reversed
692 ranges.addElement(iv); // add only - or final range
694 // create array of start end intervals.
696 if (ranges != null && ranges.size() > 0)
698 range = new int[ranges.size() * 2];
700 intvSize = ranges.size();
702 while (intv < intvSize)
704 iv = (int[]) ranges.elementAt(intv);
707 ranges.setElementAt(null, intv++); // remove
714 * get the 'initial' position of mpos in To
718 * @return position of first word in to reference frame
720 public int getToPosition(int mpos)
722 int[] mp = shiftTo(mpos);
731 * get range of positions in To frame for the mpos word in From
735 * @return null or int[] first position in To for mpos, last position in to
738 public int[] getToWord(int mpos)
740 int[] mp = shiftTo(mpos);
744 { mp[0], mp[0] + mp[2] * (getFromRatio() - 1) };
750 * get From position in the associated reference frame for position pos in the
751 * associated sequence.
756 public int getMappedPosition(int pos)
758 int[] mp = shiftFrom(pos);
766 public int[] getMappedWord(int pos)
768 int[] mp = shiftFrom(pos);
772 { mp[0], mp[0] + mp[2] * (getToRatio() - 1) };
779 * @return a MapList whose From range is this maplist's To Range, and vice
782 public MapList getInverse()
784 return new MapList(getToRanges(), getFromRanges(), getToRatio(),
789 * test for containment rather than equivalence to another mapping
792 * to be tested for containment
793 * @return true if local or mapped range map contains or is contained by this
796 public boolean containsEither(boolean local, MapList map)
800 return ((getFromLowest() >= map.getFromLowest() && getFromHighest() <= map
801 .getFromHighest()) || (getFromLowest() <= map.getFromLowest() && getFromHighest() >= map
806 return ((getToLowest() >= map.getToLowest() && getToHighest() <= map
807 .getToHighest()) || (getToLowest() <= map.getToLowest() && getToHighest() >= map