/* * Jalview - A Sequence Alignment Editor and Viewer * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ package jalview.util; import java.util.*; /** * MapList * Simple way of bijectively mapping a non-contiguous linear range to another non-contiguous linear range * Use at your own risk! * TODO: efficient implementation of private posMap method * TODO: test/ensure that sense of from and to ratio start position is conserved (codon start position recovery) * TODO: optimize to use int[][] arrays rather than vectors. */ public class MapList { /* (non-Javadoc) * @see java.lang.Object#clone() */ protected Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub return super.clone(); } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(MapList obj) { if (obj==this) return true; if (obj!=null && obj.fromRatio==fromRatio && obj.toRatio==toRatio && obj.fromShifts!=null && obj.toShifts!=null) { Iterator i,j; for (i=fromShifts.iterator(),j=obj.fromShifts.iterator(); i.hasNext();) { int[] mi=(int[]) i.next(); if (!j.hasNext()) return false; int[] mj=(int[]) j.next(); if (mi[0]!=mj[0] || mi[1]!=mj[1]) return false; } if (j.hasNext()) return false; for (i=toShifts.iterator(),j=obj.toShifts.iterator(); i.hasNext();) { int[] mi=(int[]) i.next(); if (!j.hasNext()) return false; int[] mj=(int[]) j.next(); if (mi[0]!=mj[0] || mi[1]!=mj[1]) return false; } if (j.hasNext()) return false; return true; } return false; } public Vector fromShifts; public Vector toShifts; int fromRatio; // number of steps in fromShifts to one toRatio unit int toRatio; // number of steps in toShifts to one fromRatio /** * lowest and highest value in the from Map */ int[] fromRange=null; /** * lowest and highest value in the to Map */ int[] toRange=null; public int getFromRatio() { return fromRatio; } public int getToRatio() { return toRatio; } public int getFromLowest() { return fromRange[0]; } public int getFromHighest() { return fromRange[1]; } public int getToLowest() { return toRange[0]; } public int getToHighest() { return toRange[1]; } private void ensureRange(int[] limits, int pos) { if (limits[0]>pos) limits[0]=pos; if (limits[1] to) { from = intv[1]; to=intv[0]; } while (iv.hasNext()) { intv = (int[]) iv.next(); if (intv[0]to) { to=intv[0]; } if (intv[1]>to) { to=intv[1]; } } int tF=0,tT=0; int mp[][] = new int[to-from+2][]; for (int i = 0; i < mp.length; i++) { int[] m = shift(i+from,intVals,ratio,toIntVals, toRatio); if (m != null) { if (i == 0) { tF=tT=m[0]; } else { if (m[0] < tF) { tF=m[0]; } if (m[0] > tT) { tT=m[0]; } } } mp[i] = m; } int[][] map = new int[][] { new int[] { from, to, tF, tT}, new int[to - from + 2]}; map[0][2] = tF; map[0][3] = tT; for (int i = 0; i < mp.length; i++) { if (mp[i] != null) { map[1][i] = mp[i][0]-tF; } else { map[1][i] = -1; // indicates an out of range mapping } } return map; } /** * addShift * @param pos start position for shift (in original reference frame) * @param shift length of shift * public void addShift(int pos, int shift) { int sidx = 0; int[] rshift=null; while (sidx= intv[0] && pos <= intv[1]) { return new int[] { count + pos - intv[0] + 1, +1}; } else { count+=intv[1]-intv[0]+1; } } else { if (pos >= intv[1] && pos <= intv[0]) { return new int[] { count + intv[0] - pos + 1, -1}; } else { count+=intv[0]-intv[1]+1; } } } return null; } /** * count out pos positions into a series of intervals and return the position * @param intVals * @param pos * @return position pos in interval set */ private int[] countToPos(Iterator intVals, int pos) { int count = 0, diff = 0, intv[] = { 0, 0}; while (intVals.hasNext()) { intv = (int[])intVals.next(); diff = intv[1]-intv[0]; if (diff >= 0) { if (pos <= count + 1 + diff) { return new int[] { pos - count - 1 + intv[0], +1}; } else { count+=1+diff; } } else { if (pos <= count + 1 - diff) { return new int[] { intv[0] - (pos - count - 1), -1}; } else { count+=1-diff; } } } return null;//(diff<0) ? (intv[1]-1) : (intv[0]+1); } /** * find series of intervals mapping from start-end in the From map. * @param start position in to map * @param end position in to map * @return series of ranges in from map */ public int[] locateInFrom(int start, int end) { // inefficient implementation int fromStart[] = shiftTo(start); int fromEnd[] = shiftTo(end); if (fromStart==null || fromEnd==null) return null; int iv[] = getIntervals(fromShifts, fromStart, fromEnd,fromRatio); return iv; } /** * find series of intervals mapping from start-end in the to map. * @param start position in from map * @param end position in from map * @return series of ranges in to map */ public int[] locateInTo(int start, int end) { // inefficient implementation int toStart[] = shiftFrom(start); int toEnd[] = shiftFrom(end); if (toStart==null || toEnd==null) return null; int iv[] = getIntervals(toShifts, toStart, toEnd, toRatio); return iv; } /** * like shift - except returns the intervals in the given vector of shifts which were spanned * in traversing fromStart to fromEnd * @param fromShifts2 * @param fromStart * @param fromEnd * @param fromRatio2 * @return */ private int[] getIntervals(Vector fromShifts2, int[] fromStart, int[] fromEnd, int fromRatio2) { // correct for word direction for start and end int startpos = fromStart[0]+fromStart[2]*(fromRatio2-1); int endpos = fromEnd[0]+fromEnd[2]*(fromRatio2-1); Iterator intv = fromShifts2.iterator(); int iv[],i=0,fs=-1,fe=-1; // containing intervals while (intv.hasNext() && (fs==-1 || fe==-1)) { iv = (int[]) intv.next(); if (iv[0]<=iv[1]) { if (fs==-1 && startpos>=iv[0] && startpos<=iv[1]) { fs = i; } if (fe==-1 && endpos>=iv[0] && endpos<=iv[1]) { fe = i; } } else { if (fs==-1 && startpos<=iv[0] && startpos>=iv[1]) { fs = i; } if (fe==-1 && endpos<=iv[0] && endpos>=iv[1]) { fe = i; } } i++; } if (fs==fe && fe==-1) return null; Vector ranges=new Vector(); if (fs<=fe) { intv = fromShifts2.iterator(); i=0; while (ifs) { i--; } iv = (int[]) fromShifts2.elementAt(i); iv = new int[] { iv[1], iv[0]};// reverse and clone // truncate initial interval if (i==fs) { iv[0] = startpos; } while (i!=fe) { ranges.addElement(iv); // add (truncated) reversed interval iv = (int[]) fromShifts2.elementAt(--i); iv = new int[] { iv[1], iv[0] }; // reverse and clone } if (i==fe) { // interval is already reversed iv[1] = endpos; } ranges.addElement(iv); // add only - or final range } // create array of start end intervals. int[] range = null; if (ranges!=null && ranges.size()>0) { range = new int[ranges.size()*2]; intv = ranges.iterator(); i=0; while (intv.hasNext()) { iv = (int[]) intv.next(); range[i++] = iv[0]; range[i++] = iv[1]; intv.remove(); } } return range; } /** * test routine. not incremental. * @param ml * @param fromS * @param fromE */ public static void testMap(MapList ml, int fromS, int fromE) { for (int from = 1; from <= 25; from++) { int[] too=ml.shiftFrom(from); System.out.print("ShiftFrom("+from+")=="); if (too==null) { System.out.print("NaN\n"); } else { System.out.print(too[0]+" % "+too[1]+" ("+too[2]+")"); System.out.print("\t+--+\t"); int[] toofrom=ml.shiftTo(too[0]); if (toofrom != null) { if (toofrom[0]!=from) { System.err.println("Mapping not reflexive:" + from + " " + too[0] + "->" + toofrom[0]); } System.out.println("ShiftTo(" + too[0] + ")==" + toofrom[0] + " % " + toofrom[1]+" ("+toofrom[2]+")"); } else { System.out.println("ShiftTo(" + too[0] + ")==" + "NaN! - not Bijective Mapping!"); } } } int mmap[][] = ml.makeFromMap(); System.out.println("FromMap : (" + mmap[0][0] + " " + mmap[0][1] + " " + mmap[0][2] + " " + mmap[0][3] + " "); for (int i = 1; i <= mmap[1].length; i++) { if (mmap[1][i - 1] == -1) { System.out.print(i+"=XXX"); } else { System.out.print(i+"="+(mmap[0][2]+mmap[1][i-1])); } if (i % 20==0) { System.out.print("\n"); } else { System.out.print(","); } } //test range function System.out.print("\nTest locateInFrom\n"); { int f=mmap[0][2],t=mmap[0][3]; while (f