/* * BioJava development code * * This code may be freely distributed and modified under the * terms of the GNU Lesser General Public Licence. This should * be distributed with the code. If you do not have a copy, * see: * * http://www.gnu.org/copyleft/lesser.html * * Copyright for this code is held jointly by the individual * authors. These should be listed in @author doc comments. * * For more information on the BioJava project and its aims, * or to join the biojava-l mailing list, visit the home page * at: * * http://www.biojava.org/ * */ /** *

AbstractULAlignment is an abstract base class for alignments * where the constituent sequences have unequal lengths.

* * @author David Waring * @author Mark Schreiber (docs and some minor changes) */ package org.biojava.bio.alignment; import java.io.Serializable; import java.util.AbstractList; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import java.util.Vector; import org.biojava.bio.BioError; import org.biojava.bio.symbol.AbstractSymbolList; import org.biojava.bio.symbol.Alignment; import org.biojava.bio.symbol.Alphabet; import org.biojava.bio.symbol.IllegalSymbolException; import org.biojava.bio.symbol.Location; import org.biojava.bio.symbol.LocationTools; import org.biojava.bio.symbol.RangeLocation; import org.biojava.bio.symbol.Symbol; import org.biojava.bio.symbol.SymbolList; public abstract class AbstractULAlignment extends AbstractSymbolList implements UnequalLengthAlignment{ protected Alphabet alphabet; /** this will return the ambiguity symbol associated with all symbols in that column */ public Symbol symbolAt(int index) { try { return alphabet.getSymbol(new ColAsList(index)); } catch (IllegalSymbolException ire) { throw new BioError( "Somehow my crossproduct alphabet is incompatible with column " + index, ire ); } } public List labelsAt(int column){ return labelsInRange(new RangeLocation(column,column)); } public List labelsInRange(Location loc){ List labels = getLabels(); Location seqLoc; Object label; List labelList = new Vector(); for (Iterator labelIterator = labels.iterator();labelIterator.hasNext();){ label = labelIterator.next(); seqLoc = locInAlignment(label); if (LocationTools.overlaps(loc,seqLoc)){ labelList.add(label); } } return labelList; } public Iterator symbolListIterator() { return new Alignment.SymbolListIterator(this); } protected void debug(String s){ System.out.println(s); } /** * leftMost and rightMost return labels. If there are more than one * that start at the same location it returns the longest, if they are * the same length it returns the first one it found; */ public Object leftMost(){ List labels = getLabels(); Object leftMost = null; Object label; Location leftLoc= null; Location loc = null; for (Iterator labelIterator = labels.iterator();labelIterator.hasNext();){ label = labelIterator.next(); loc = locInAlignment(label); if (leftMost == null){ leftMost = label; leftLoc= loc; //loc = loc; } if (loc.getMin() < leftLoc.getMin()){ leftMost = label; leftLoc = loc; }else if (loc.getMin() == leftLoc.getMin()){ if ((loc.getMax() - loc.getMin()) > (leftLoc.getMax() - leftLoc.getMin())){ leftMost = label; leftLoc = loc; } } } return leftMost(); } public Object rightMost(){ List labels = getLabels(); Object rightMost = null; Object label; Location rightLoc= null; Location loc= null; for (Iterator labelIterator = labels.iterator();labelIterator.hasNext();){ label = labelIterator.next(); loc = locInAlignment(label); if (rightMost == null){ rightMost = label; rightLoc= loc; //loc= loc; } if (loc.getMin() > rightLoc.getMin()){ rightMost = label; rightLoc = loc; }else if (loc.getMin() == rightLoc.getMin()){ if ((loc.getMax() - loc.getMin()) > (rightLoc.getMax() - rightLoc.getMin())){ rightMost = label; rightLoc = loc; } } } return rightMost(); } /** * Retrieves a subalignment specified by the location. *

WARNING: It is assumed that the location is contiguous. If * the location is non-contiguous it may be preferable to use a block iterator * to retrieve each sub location independently. * @see #subAlignment(Set labels, int min, int max) */ public Alignment subAlignment(Set labels, Location loc) throws IndexOutOfBoundsException{ return new SubULAlignment(labels,loc); } /** * Retreives a subAlignment * @param labels the labels of the SymbolLists to be in the Alignment * @param min the left most coordinate * @param max the right most coordinate * @return an Alignment * @throws NoSuchElementException if one of the values in labels is not in the parent alignment */ public Alignment subAlignment(Set labels, int min, int max) throws NoSuchElementException{ return subAlignment(labels, LocationTools.makeLocation(min, max)); } public SortedSet orderedLables(Comparator comp){ TreeSet orderedSet = new TreeSet(comp); orderedSet.addAll(getLabels()); return orderedSet; } ////////////////////////////////////////////// ////////////////////////////////////////////// // INNER CLASSES ////////////////////////////////////////////// ////////////////////////////////////////////// private final class ColAsList extends AbstractList implements Serializable { private final int col; private List labels; public ColAsList(int col) { this.col = col; labels = getLabels(); } protected ColAsList() { this.col = 0; } public Object get(int indx) { return symbolAt(labels.get(indx), col); } public int size() { return labels.size(); } } /** * Orders by location left to right. If they both start at the same location (o1.getMin() == o2.getMin()) * it the larger of the two considered to the Left */ public class LeftRightLocationComparator implements Comparator{ public int compare(Object o1, Object o2){ int ret = 1; Location loc1,loc2; loc1 = locInAlignment(o1); loc2 = locInAlignment(o2); if (loc1.getMin() > loc2.getMin()){ ret = 1; }else if (loc1.getMin() < loc2.getMin()){ ret = -1; }else if (loc1.getMin() == loc2.getMin()){ int s1 = (loc1.getMax() - loc1.getMin()) + 1; int s2 = (loc2.getMax() - loc2.getMin()) + 1; if (s1 == s2){ ret = 1; }else{ ret = s2 - s1; } } // debug (" result " + ret); return ret; } } /////////////// // This inner class should take care of all subAlignments /////////////// public class SubULAlignment extends AbstractSymbolList implements UnequalLengthAlignment{ private int start,end; private List subLabels; // will be left null if constructed with null Set of labels // this allows labels added to underlying Alignment to be seen // unless it was constructed with a Set of labels NOT protected SubULAlignment (Set labels, Location loc) throws IndexOutOfBoundsException{ this.start = loc.getMin(); this.end = loc.getMax(); if (start < 1 || end > AbstractULAlignment.this.length()){ throw new IndexOutOfBoundsException(); } if (labels != null){ subLabels = new ArrayList(); subLabels.addAll(labels); }else{ subLabels = AbstractULAlignment.this.labelsInRange(new RangeLocation(start,end)); } } /** * realPosition is the position in the underlying Alignment corresponding to * a position in the subAlignment */ private int realPosition(int pos){ return pos + start - 1; } ///////////////////////// // methods from Interface UnequalLengthAlignment //////////////////////// public int length(){ return end - start + 1; } /** * The location of an individual SymbolList relative to overall Alignment */ public Location locInAlignment(Object label){ Location origLoc = AbstractULAlignment.this.locInAlignment(label); int min = origLoc.getMin() - start + 1; int max = origLoc.getMax() - start + 1; return new RangeLocation(min,max); } public Alignment subAlignment(Set labels, Location loc) throws NoSuchElementException{ int min = realPosition(loc.getMin()); int max = realPosition(loc.getMax()); // if the Subalignment has a limited subLabel we want to keep labels of the sub sub aligment limited to that list too if (labels == null){ labels = new TreeSet(subLabels); }else{ Vector l = new Vector(labels); labels = new TreeSet(listIntersection(l,subLabels)); } // debug (" labels now " + labels); return new SubULAlignment(labels,new RangeLocation(min,max)); } protected List listIntersection(List s1,List s2){ List common = new Vector(s1); for (Iterator i = s1.iterator();i.hasNext();){ Object label = i.next(); if ( ! s2.contains(label)){ common.remove(label); } } return common; } public List labelsAt(int column) throws IndexOutOfBoundsException { return labelsInRange(new RangeLocation(column,column)); } public List labelsInRange(Location loc) throws IndexOutOfBoundsException { // debug ("looking for labelsInRange " + loc.getMin() + "-" + loc.getMax()); int min = realPosition(loc.getMin()); int max = realPosition(loc.getMax()); if (min < start || max > end){ throw new IndexOutOfBoundsException(); } return listIntersection(subLabels,AbstractULAlignment.this.labelsInRange(new RangeLocation(min,max))); // List aLabels = AbstractULAlignment.this.labelsInRange(new RangeLocation(min,max)); // List sLabels = AbstractULAlignment.this.labelsInRange(new RangeLocation(min,max)); // for (Iterator i = aLabels.iterator();i.hasNext();){ // Object label = i.next(); // if ( ! subLabels.contains(label)){ // sLabels.remove(label); // } // } // return sLabels; } ///////////////////////// // methods from Interface Alignment //////////////////////// public List getLabels(){ return subLabels; } public Symbol symbolAt(Object label, int column) throws NoSuchElementException{ return AbstractULAlignment.this.symbolAt(label,realPosition(column)); } public Symbol symbolAt(int column) throws NoSuchElementException{ return AbstractULAlignment.this.symbolAt(realPosition(column)); } public SymbolList symbolListForLabel(Object label) throws NoSuchElementException{ return AbstractULAlignment.this.symbolListForLabel(label); } public Alphabet getAlphabet(){ return AbstractULAlignment.this.getAlphabet(); } public Iterator symbolListIterator() { return new Alignment.SymbolListIterator(this); } } }