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)
42 // TODO should have @Override and arg0 of type Object
47 if (obj != null && obj.fromRatio == fromRatio && obj.toRatio == toRatio
48 && obj.fromShifts != null && obj.toShifts != null)
50 int i, iSize = fromShifts.size(), j, jSize = obj.fromShifts.size();
55 for (i = 0, iSize = fromShifts.size(), j = 0, jSize = obj.fromShifts
58 int[] mi = (int[]) fromShifts.elementAt(i++);
59 int[] mj = (int[]) obj.fromShifts.elementAt(j++);
60 if (mi[0] != mj[0] || mi[1] != mj[1])
65 iSize = toShifts.size();
66 jSize = obj.toShifts.size();
71 for (i = 0, j = 0; i < iSize;)
73 int[] mi = (int[]) toShifts.elementAt(i++);
74 int[] mj = (int[]) obj.toShifts.elementAt(j++);
75 if (mi[0] != mj[0] || mi[1] != mj[1])
85 public Vector fromShifts;
87 public Vector toShifts;
89 int fromRatio; // number of steps in fromShifts to one toRatio unit
91 int toRatio; // number of steps in toShifts to one fromRatio
95 * @return series of intervals mapped in from
97 public int[] getFromRanges()
99 return getRanges(fromShifts);
102 public int[] getToRanges()
104 return getRanges(toShifts);
107 private int[] getRanges(Vector shifts)
109 int[] rnges = new int[2 * shifts.size()];
110 Enumeration e = shifts.elements();
112 while (e.hasMoreElements())
114 int r[] = (int[]) e.nextElement();
122 * lowest and highest value in the from Map
124 int[] fromRange = null;
127 * lowest and highest value in the to Map
129 int[] toRange = null;
133 * @return length of mapped phrase in from
135 public int getFromRatio()
142 * @return length of mapped phrase in to
144 public int getToRatio()
149 public int getFromLowest()
154 public int getFromHighest()
159 public int getToLowest()
164 public int getToHighest()
169 private void ensureRange(int[] limits, int pos)
181 public MapList(int from[], int to[], int fromRatio, int toRatio)
183 fromRange = new int[]
184 { from[0], from[1] };
188 fromShifts = new Vector();
189 for (int i = 0; i < from.length; i += 2)
191 ensureRange(fromRange, from[i]);
192 ensureRange(fromRange, from[i + 1]);
194 fromShifts.addElement(new int[]
195 { from[i], from[i + 1] });
197 toShifts = new Vector();
198 for (int i = 0; i < to.length; i += 2)
200 ensureRange(toRange, to[i]);
201 ensureRange(toRange, to[i + 1]);
202 toShifts.addElement(new int[]
203 { to[i], to[i + 1] });
205 this.fromRatio = fromRatio;
206 this.toRatio = toRatio;
209 public MapList(MapList map)
211 this.fromRange = new int[]
212 { map.fromRange[0], map.fromRange[1] };
213 this.toRange = new int[]
214 { map.toRange[0], map.toRange[1] };
215 this.fromRatio = map.fromRatio;
216 this.toRatio = map.toRatio;
217 if (map.fromShifts != null)
219 this.fromShifts = new Vector();
220 Enumeration e = map.fromShifts.elements();
221 while (e.hasMoreElements())
223 int[] el = (int[]) e.nextElement();
224 fromShifts.addElement(new int[]
228 if (map.toShifts != null)
230 this.toShifts = new Vector();
231 Enumeration e = map.toShifts.elements();
232 while (e.hasMoreElements())
234 int[] el = (int[]) e.nextElement();
235 toShifts.addElement(new int[]
242 * get all mapped positions from 'from' to 'to'
244 * @return int[][] { int[] { fromStart, fromFinish, toStart, toFinish }, int
245 * [fromFinish-fromStart+2] { toStart..toFinish mappings}}
247 public int[][] makeFromMap()
249 return posMap(fromShifts, fromRatio, toShifts, toRatio);
253 * get all mapped positions from 'to' to 'from'
255 * @return int[to position]=position mapped in from
257 public int[][] makeToMap()
259 return posMap(toShifts, toRatio, fromShifts, fromRatio);
263 * construct an int map for intervals in intVals
266 * @return int[] { from, to pos in range }, int[range.to-range.from+1]
267 * returning mapped position
269 private int[][] posMap(Vector intVals, int ratio, Vector toIntVals,
272 int iv = 0, ivSize = intVals.size();
277 int[] intv = (int[]) intVals.elementAt(iv++);
278 int from = intv[0], to = intv[1];
286 intv = (int[]) intVals.elementAt(iv++);
305 int mp[][] = new int[to - from + 2][];
306 for (int i = 0; i < mp.length; i++)
308 int[] m = shift(i + from, intVals, ratio, toIntVals, toRatio);
329 int[][] map = new int[][]
331 { from, to, tF, tT }, new int[to - from + 2] };
336 for (int i = 0; i < mp.length; i++)
340 map[1][i] = mp[i][0] - tF;
344 map[1][i] = -1; // indicates an out of range mapping
354 * start position for shift (in original reference frame)
358 * public void addShift(int pos, int shift) { int sidx = 0; int[]
359 * rshift=null; while (sidx<shifts.size() && (rshift=(int[])
360 * shifts.elementAt(sidx))[0]<pos) sidx++; if (sidx==shifts.size())
361 * shifts.insertElementAt(new int[] { pos, shift}, sidx); else
362 * rshift[1]+=shift; }
365 * shift from pos to To(pos)
369 * @return int shifted position in To, frameshift in From, direction of mapped
372 public int[] shiftFrom(int pos)
374 return shift(pos, fromShifts, fromRatio, toShifts, toRatio);
378 * inverse of shiftFrom - maps pos in To to a position in From
382 * @return shifted position in From, frameshift in To, direction of mapped
385 public int[] shiftTo(int pos)
387 return shift(pos, toShifts, toRatio, fromShifts, fromRatio);
398 private int[] shift(int pos, Vector fromShifts, int fromRatio,
399 Vector toShifts, int toRatio)
401 int[] fromCount = countPos(fromShifts, pos);
402 if (fromCount == null)
406 int fromRemainder = (fromCount[0] - 1) % fromRatio;
407 int toCount = 1 + (((fromCount[0] - 1) / fromRatio) * toRatio);
408 int[] toPos = countToPos(toShifts, toCount);
411 return null; // throw new Error("Bad Mapping!");
413 // System.out.println(fromCount[0]+" "+fromCount[1]+" "+toCount);
415 { toPos[0], fromRemainder, toPos[1] };
419 * count how many positions pos is along the series of intervals.
423 * @return number of positions or null if pos is not within intervals
425 private int[] countPos(Vector intVals, int pos)
427 int count = 0, intv[], iv = 0, ivSize = intVals.size();
430 intv = (int[]) intVals.elementAt(iv++);
431 if (intv[0] <= intv[1])
433 if (pos >= intv[0] && pos <= intv[1])
436 { count + pos - intv[0] + 1, +1 };
440 count += intv[1] - intv[0] + 1;
445 if (pos >= intv[1] && pos <= intv[0])
448 { count + intv[0] - pos + 1, -1 };
452 count += intv[0] - intv[1] + 1;
460 * count out pos positions into a series of intervals and return the position
464 * @return position pos in interval set
466 private int[] countToPos(Vector intVals, int pos)
468 int count = 0, diff = 0, iv = 0, ivSize = intVals.size(), intv[] =
472 intv = (int[]) intVals.elementAt(iv++);
473 diff = intv[1] - intv[0];
476 if (pos <= count + 1 + diff)
479 { pos - count - 1 + intv[0], +1 };
488 if (pos <= count + 1 - diff)
491 { intv[0] - (pos - count - 1), -1 };
499 return null;// (diff<0) ? (intv[1]-1) : (intv[0]+1);
503 * find series of intervals mapping from start-end in the From map.
509 * @return series of ranges in from map
511 public int[] locateInFrom(int start, int end)
513 // inefficient implementation
514 int fromStart[] = shiftTo(start);
515 int fromEnd[] = shiftTo(end); // needs to be inclusive of end of symbol
517 if (fromStart == null || fromEnd == null)
521 int iv[] = getIntervals(fromShifts, fromStart, fromEnd, fromRatio);
526 * find series of intervals mapping from start-end in the to map.
529 * position in from map
531 * position in from map
532 * @return series of ranges in to map
534 public int[] locateInTo(int start, int end)
536 // inefficient implementation
537 int toStart[] = shiftFrom(start);
538 int toEnd[] = shiftFrom(end);
539 if (toStart == null || toEnd == null)
543 int iv[] = getIntervals(toShifts, toStart, toEnd, toRatio);
548 * like shift - except returns the intervals in the given vector of shifts
549 * which were spanned in traversing fromStart to fromEnd
555 * @return series of from,to intervals from from first position of starting
556 * region to final position of ending region inclusive
558 private int[] getIntervals(Vector fromShifts2, int[] fromStart,
559 int[] fromEnd, int fromRatio2)
561 int startpos, endpos;
562 startpos = fromStart[0]; // first position in fromStart
563 endpos = fromEnd[0]; // last position in fromEnd
564 int endindx = (fromRatio2 - 1); // additional positions to get to last
565 // position from endpos
566 int intv = 0, intvSize = fromShifts2.size();
567 int iv[], i = 0, fs = -1, fe_s = -1, fe = -1; // containing intervals
568 // search intervals to locate ones containing startpos and count endindx
569 // positions on from endpos
570 while (intv < intvSize && (fs == -1 || fe == -1))
572 iv = (int[]) fromShifts2.elementAt(intv++);
575 endpos = iv[0]; // start counting from beginning of interval
576 endindx--; // inclusive of endpos
580 if (fs == -1 && startpos >= iv[0] && startpos <= iv[1])
584 if (endpos >= iv[0] && endpos <= iv[1])
592 if (endpos + endindx <= iv[1])
595 endpos = endpos + endindx; // end of end token is within this
600 endindx -= iv[1] - endpos; // skip all this interval too
607 if (fs == -1 && startpos <= iv[0] && startpos >= iv[1])
611 if (endpos <= iv[0] && endpos >= iv[1])
619 if (endpos - endindx >= iv[1])
622 endpos = endpos - endindx; // end of end token is within this
627 endindx -= endpos - iv[1]; // skip all this interval too
634 if (fs == fe && fe == -1)
638 Vector ranges = new Vector();
643 // truncate initial interval
644 iv = (int[]) fromShifts2.elementAt(intv++);
646 { iv[0], iv[1] };// clone
653 ranges.addElement(iv); // add initial range
654 iv = (int[]) fromShifts2.elementAt(intv++); // get next interval
656 { iv[0], iv[1] };// clone
663 ranges.addElement(iv); // add only - or final range
667 // walk from end of interval.
668 i = fromShifts2.size() - 1;
673 iv = (int[]) fromShifts2.elementAt(i);
675 { iv[1], iv[0] };// reverse and clone
676 // truncate initial interval
682 { // fix apparent logic bug when fe==-1
683 ranges.addElement(iv); // add (truncated) reversed interval
684 iv = (int[]) fromShifts2.elementAt(i);
686 { iv[1], iv[0] }; // reverse and clone
690 // interval is already reversed
693 ranges.addElement(iv); // add only - or final range
695 // create array of start end intervals.
697 if (ranges != null && ranges.size() > 0)
699 range = new int[ranges.size() * 2];
701 intvSize = ranges.size();
703 while (intv < intvSize)
705 iv = (int[]) ranges.elementAt(intv);
708 ranges.setElementAt(null, intv++); // remove
715 * get the 'initial' position of mpos in To
719 * @return position of first word in to reference frame
721 public int getToPosition(int mpos)
723 int[] mp = shiftTo(mpos);
732 * get range of positions in To frame for the mpos word in From
736 * @return null or int[] first position in To for mpos, last position in to
739 public int[] getToWord(int mpos)
741 int[] mp = shiftTo(mpos);
745 { mp[0], mp[0] + mp[2] * (getFromRatio() - 1) };
751 * get From position in the associated reference frame for position pos in the
752 * associated sequence.
757 public int getMappedPosition(int pos)
759 int[] mp = shiftFrom(pos);
767 public int[] getMappedWord(int pos)
769 int[] mp = shiftFrom(pos);
773 { mp[0], mp[0] + mp[2] * (getToRatio() - 1) };
780 * @return a MapList whose From range is this maplist's To Range, and vice
783 public MapList getInverse()
785 return new MapList(getToRanges(), getFromRanges(), getToRatio(),
790 * test for containment rather than equivalence to another mapping
793 * to be tested for containment
794 * @return true if local or mapped range map contains or is contained by this
797 public boolean containsEither(boolean local, MapList map)
801 return ((getFromLowest() >= map.getFromLowest() && getFromHighest() <= map
802 .getFromHighest()) || (getFromLowest() <= map.getFromLowest() && getFromHighest() >= map
807 return ((getToLowest() >= map.getToLowest() && getToHighest() <= map
808 .getToHighest()) || (getToLowest() <= map.getToLowest() && getToHighest() >= map