2 * Jalview - A Sequence Alignment Editor and Viewer
3 * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 * Simple way of bijectively mapping a non-contiguous linear range to another non-contiguous linear range
26 * Use at your own risk!
27 * TODO: efficient implementation of private posMap method
28 * TODO: test/ensure that sense of from and to ratio start position is conserved (codon start position recovery)
29 * TODO: optimize to use int[][] arrays rather than vectors.
34 * @see java.lang.Object#clone()
36 protected Object clone() throws CloneNotSupportedException {
37 // TODO Auto-generated method stub
41 * @see java.lang.Object#equals(java.lang.Object)
43 public boolean equals(MapList obj) {
46 if (obj!=null && obj.fromRatio==fromRatio && obj.toRatio==toRatio
47 && obj.fromShifts!=null && obj.toShifts!=null) {
48 int i,iSize=fromShifts.size(),j,jSize=obj.fromShifts.size();
51 for (i=0,iSize=fromShifts.size(),j=0, jSize=obj.fromShifts.size(); i<iSize;) {
52 int[] mi=(int[]) fromShifts.elementAt(i++);
53 int[] mj=(int[]) obj.fromShifts.elementAt(j++);
54 if (mi[0]!=mj[0] || mi[1]!=mj[1])
57 iSize=toShifts.size();
58 jSize=obj.toShifts.size();
61 for (i=0,j=0; i<iSize;) {
62 int[] mi=(int[]) toShifts.elementAt(i++);
63 int[] mj=(int[]) obj.toShifts.elementAt(j++);
64 if (mi[0]!=mj[0] || mi[1]!=mj[1])
71 public Vector fromShifts;
72 public Vector toShifts;
73 int fromRatio; // number of steps in fromShifts to one toRatio unit
74 int toRatio; // number of steps in toShifts to one fromRatio
76 * lowest and highest value in the from Map
80 * lowest and highest value in the to Map
83 public int getFromRatio()
87 public int getToRatio()
91 public int getFromLowest() {
94 public int getFromHighest() {
97 public int getToLowest() {
100 public int getToHighest() {
103 private void ensureRange(int[] limits, int pos) {
109 public MapList(int from[], int to[], int fromRatio, int toRatio)
111 fromRange=new int[] { from[0],from[1] };
112 toRange=new int[] { to[0],to[1] };
114 fromShifts = new Vector();
115 for (int i=0;i<from.length; i+=2)
117 ensureRange(fromRange, from[i]);
118 ensureRange(fromRange, from[i+1]);
120 fromShifts.add(new int[]
121 {from[i], from[i + 1]});
123 toShifts = new Vector();
124 for (int i=0;i<to.length; i+=2)
126 ensureRange(toRange, to[i]);
127 ensureRange(toRange, to[i+1]);
128 toShifts.add(new int[]
131 this.fromRatio=fromRatio;
132 this.toRatio=toRatio;
135 * get all mapped positions from 'from' to 'to'
136 * @return int[][] { int[] { fromStart, fromFinish, toStart, toFinish }, int [fromFinish-fromStart+2] { toStart..toFinish mappings}}
138 public int[][] makeFromMap()
140 return posMap(fromShifts, fromRatio, toShifts, toRatio);
143 * get all mapped positions from 'to' to 'from'
144 * @return int[to position]=position mapped in from
146 public int[][] makeToMap()
148 return posMap(toShifts,toRatio, fromShifts, fromRatio);
151 * construct an int map for intervals in intVals
153 * @return int[] { from, to pos in range }, int[range.to-range.from+1] returning mapped position
155 private int[][] posMap(Vector intVals, int ratio, Vector toIntVals,
158 int iv=0,ivSize = intVals.size();
163 int[] intv=(int[]) intVals.elementAt(iv++);
164 int from=intv[0],to=intv[1];
172 intv = (int[]) intVals.elementAt(iv++);
191 int mp[][] = new int[to-from+2][];
192 for (int i = 0; i < mp.length; i++)
194 int[] m = shift(i+from,intVals,ratio,toIntVals, toRatio);
215 int[][] map = new int[][]
219 from, to, tF, tT}, new int[to - from + 2]};
224 for (int i = 0; i < mp.length; i++)
228 map[1][i] = mp[i][0]-tF;
232 map[1][i] = -1; // indicates an out of range mapping
239 * @param pos start position for shift (in original reference frame)
240 * @param shift length of shift
242 public void addShift(int pos, int shift)
246 while (sidx<shifts.size() && (rshift=(int[]) shifts.elementAt(sidx))[0]<pos)
248 if (sidx==shifts.size())
249 shifts.insertElementAt(new int[] { pos, shift}, sidx);
255 * shift from pos to To(pos)
258 * @return int shifted position in To, frameshift in From, direction of mapped symbol in To
260 public int[] shiftFrom(int pos)
262 return shift(pos, fromShifts, fromRatio, toShifts, toRatio);
266 * inverse of shiftFrom - maps pos in To to a position in From
268 * @return shifted position in From, frameshift in To, direction of mapped symbol in From
270 public int[] shiftTo(int pos)
272 return shift(pos, toShifts, toRatio, fromShifts, fromRatio);
282 private int[] shift(int pos, Vector fromShifts, int fromRatio,
283 Vector toShifts, int toRatio)
285 int[] fromCount = countPos(fromShifts, pos);
290 int fromRemainder=(fromCount[0]-1) % fromRatio;
291 int toCount = 1+(((fromCount[0]-1) / fromRatio) * toRatio);
292 int[] toPos = countToPos(toShifts, toCount);
295 return null; // throw new Error("Bad Mapping!");
297 //System.out.println(fromCount[0]+" "+fromCount[1]+" "+toCount);
300 toPos[0], fromRemainder, toPos[1]};
303 * count how many positions pos is along the series of intervals.
306 * @return number of positions or null if pos is not within intervals
308 private int[] countPos(Vector intVals, int pos)
310 int count=0,intv[],iv=0,ivSize=intVals.size();
313 intv = (int[])intVals.elementAt(iv++);
314 if (intv[0] <= intv[1])
316 if (pos >= intv[0] && pos <= intv[1])
320 count + pos - intv[0] + 1, +1};
324 count+=intv[1]-intv[0]+1;
329 if (pos >= intv[1] && pos <= intv[0])
333 count + intv[0] - pos + 1, -1};
337 count+=intv[0]-intv[1]+1;
344 * count out pos positions into a series of intervals and return the position
347 * @return position pos in interval set
349 private int[] countToPos(Vector intVals, int pos)
351 int count = 0, diff = 0, iv=0,ivSize=intVals.size(), intv[] =
356 intv = (int[])intVals.elementAt(iv++);
357 diff = intv[1]-intv[0];
360 if (pos <= count + 1 + diff)
364 pos - count - 1 + intv[0], +1};
373 if (pos <= count + 1 - diff)
377 intv[0] - (pos - count - 1), -1};
385 return null;//(diff<0) ? (intv[1]-1) : (intv[0]+1);
388 * find series of intervals mapping from start-end in the From map.
389 * @param start position in to map
390 * @param end position in to map
391 * @return series of ranges in from map
393 public int[] locateInFrom(int start, int end) {
394 // inefficient implementation
395 int fromStart[] = shiftTo(start);
396 int fromEnd[] = shiftTo(end);
397 if (fromStart==null || fromEnd==null)
399 int iv[] = getIntervals(fromShifts, fromStart, fromEnd,fromRatio);
404 * find series of intervals mapping from start-end in the to map.
405 * @param start position in from map
406 * @param end position in from map
407 * @return series of ranges in to map
409 public int[] locateInTo(int start, int end) {
410 // inefficient implementation
411 int toStart[] = shiftFrom(start);
412 int toEnd[] = shiftFrom(end);
413 if (toStart==null || toEnd==null)
415 int iv[] = getIntervals(toShifts, toStart, toEnd, toRatio);
419 * like shift - except returns the intervals in the given vector of shifts which were spanned
420 * in traversing fromStart to fromEnd
427 private int[] getIntervals(Vector fromShifts2, int[] fromStart, int[] fromEnd, int fromRatio2)
429 // correct for word direction for start and end
430 int startpos = fromStart[0]+fromStart[2]*(fromRatio2-1);
431 int endpos = fromEnd[0]+fromEnd[2]*(fromRatio2-1);
432 int intv=0,intvSize= fromShifts2.size();
433 int iv[],i=0,fs=-1,fe=-1; // containing intervals
434 while (intv<intvSize && (fs==-1 || fe==-1)) {
435 iv = (int[]) fromShifts2.elementAt(intv++);
437 if (fs==-1 && startpos>=iv[0] && startpos<=iv[1]) {
440 if (fe==-1 && endpos>=iv[0] && endpos<=iv[1]) {
444 if (fs==-1 && startpos<=iv[0] && startpos>=iv[1]) {
447 if (fe==-1 && endpos<=iv[0] && endpos>=iv[1]) {
453 if (fs==fe && fe==-1)
455 Vector ranges=new Vector();
459 // truncate initial interval
460 iv = (int[]) fromShifts2.elementAt(intv++);
461 iv = new int[] { iv[0], iv[1]};// clone
465 ranges.addElement(iv); // add initial range
466 iv = (int[]) fromShifts2.elementAt(intv++); // get next interval
467 iv = new int[] { iv[0], iv[1]};// clone
472 ranges.addElement(iv); // add only - or final range
474 // walk from end of interval.
475 i=fromShifts2.size()-1;
479 iv = (int[]) fromShifts2.elementAt(i);
480 iv = new int[] { iv[1], iv[0]};// reverse and clone
481 // truncate initial interval
487 ranges.addElement(iv); // add (truncated) reversed interval
488 iv = (int[]) fromShifts2.elementAt(--i);
489 iv = new int[] { iv[1], iv[0] }; // reverse and clone
492 // interval is already reversed
495 ranges.addElement(iv); // add only - or final range
497 // create array of start end intervals.
499 if (ranges!=null && ranges.size()>0)
501 range = new int[ranges.size()*2];
503 intvSize=ranges.size();
505 while (intv<intvSize)
507 iv = (int[]) ranges.elementAt(intv);
510 ranges.setElementAt(null, intv++); // remove
516 * test routine. not incremental.
521 public static void testMap(MapList ml, int fromS, int fromE)
523 for (int from = 1; from <= 25; from++)
525 int[] too=ml.shiftFrom(from);
526 System.out.print("ShiftFrom("+from+")==");
529 System.out.print("NaN\n");
533 System.out.print(too[0]+" % "+too[1]+" ("+too[2]+")");
534 System.out.print("\t+--+\t");
535 int[] toofrom=ml.shiftTo(too[0]);
538 if (toofrom[0]!=from)
540 System.err.println("Mapping not reflexive:" + from + " " + too[0] +
543 System.out.println("ShiftTo(" + too[0] + ")==" + toofrom[0] + " % " +
544 toofrom[1]+" ("+toofrom[2]+")");
548 System.out.println("ShiftTo(" + too[0] + ")==" +
549 "NaN! - not Bijective Mapping!");
553 int mmap[][] = ml.makeFromMap();
554 System.out.println("FromMap : (" + mmap[0][0] + " " + mmap[0][1] + " " +
555 mmap[0][2] + " " + mmap[0][3] + " ");
556 for (int i = 1; i <= mmap[1].length; i++)
558 if (mmap[1][i - 1] == -1)
560 System.out.print(i+"=XXX");
565 System.out.print(i+"="+(mmap[0][2]+mmap[1][i-1]));
569 System.out.print("\n");
573 System.out.print(",");
576 //test range function
577 System.out.print("\nTest locateInFrom\n");
579 int f=mmap[0][2],t=mmap[0][3];
581 System.out.println("Range "+f+" to "+t);
582 int rng[] = ml.locateInFrom(f,t);
585 for (int i=0; i<rng.length; i++) {
586 System.out.print(rng[i]+((i%2==0) ? "," : ";"));
591 System.out.println("No range!");
593 System.out.print("\nReversed\n");
594 rng = ml.locateInFrom(t,f);
597 for (int i=0; i<rng.length; i++) {
598 System.out.print(rng[i]+((i%2==0) ? "," : ";"));
603 System.out.println("No range!");
605 System.out.print("\n");
609 System.out.print("\n");
610 mmap = ml.makeToMap();
611 System.out.println("ToMap : (" + mmap[0][0] + " " + mmap[0][1] + " " +
612 mmap[0][2] + " " + mmap[0][3] + " ");
613 for (int i = 1; i <= mmap[1].length; i++)
615 if (mmap[1][i - 1] == -1)
617 System.out.print(i+"=XXX");
622 System.out.print(i+"="+(mmap[0][2]+mmap[1][i-1]));
626 System.out.print("\n");
630 System.out.print(",");
633 System.out.print("\n");
634 //test range function
635 System.out.print("\nTest locateInTo\n");
637 int f=mmap[0][2],t=mmap[0][3];
639 System.out.println("Range "+f+" to "+t);
640 int rng[] = ml.locateInTo(f,t);
642 for (int i=0; i<rng.length; i++) {
643 System.out.print(rng[i]+((i%2==0) ? "," : ";"));
648 System.out.println("No range!");
650 System.out.print("\nReversed\n");
651 rng = ml.locateInTo(t,f);
654 for (int i=0; i<rng.length; i++) {
655 System.out.print(rng[i]+((i%2==0) ? "," : ";"));
660 System.out.println("No range!");
663 System.out.print("\n");
669 public static void main(String argv[])
671 MapList ml = new MapList(new int[]
672 {1, 5, 10, 15, 25, 20},
675 MapList ml1 = new MapList(new int[]
679 MapList ml2 = new MapList(new int[] { 1, 60 },
680 new int[] { 1, 20 }, 3, 1);
681 // test internal consistency
682 int to[] = new int[51];
683 MapList.testMap(ml, 1, 60);
685 for (int from=1; from<=51; from++) {
686 int[] too=ml.shiftTo(from);
687 int[] toofrom=ml.shiftFrom(too[0]);
688 System.out.println("ShiftFrom("+from+")=="+too[0]+" % "+too[1]+"\t+-+\tShiftTo("+too[0]+")=="+toofrom[0]+" % "+toofrom[1]);
690 System.out.print("Success?\n"); // if we get here - something must be working!