/* * 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/ * */ package org.biojava.bio.symbol; import java.io.Serializable; import java.util.AbstractList; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import org.biojava.bio.BioError; /** * A simple implementation of an Alignment. *
* This is a simple-stupid implementation that is made from a set of same-lengthed * SymbolList objects each with an associated label. It does not handle differently * lengthed sequences and doesn't contain any gap-editing concepts. * * @author Matthew Pocock * @author Greg Cox * @author Nimesh Singh */ public class SimpleAlignment extends AbstractSymbolList implements Alignment, Serializable { private static final long serialVersionUID = -1760075176220928440L; private LinkedHashMap labelToSymbolList; private List labels; private Alphabet alphabet; private int length; protected void finalize() throws Throwable { super.finalize(); // System.err.println("Finalizing a SimpleAlignement"); } public int length() { return length; } public Alphabet getAlphabet() { return alphabet; } public Symbol symbolAt(int index) { try { if (labels.size() == 1) { return symbolAt(labels.get(0), index); } else { return alphabet.getSymbol(new ColAsList(index)); } } catch (IllegalSymbolException ire) { throw new BioError( "Somehow my crossproduct alphabet is incompatible with column " + index, ire ); } } public List getLabels() { return labels; } public Symbol symbolAt(Object label, int column) { return symbolListForLabel(label).symbolAt(column); } public Alignment subAlignment(Set labels, Location loc) throws NoSuchElementException { Map labelsToResList = new LinkedHashMap(); Iterator i; if(labels != null) { i = labels.iterator(); } else { i = getLabels().iterator(); } while(i.hasNext()) { Object label = i.next(); SymbolList sym = symbolListForLabel(label); if(loc != null) { sym = loc.symbols(sym); } labelsToResList.put(label, sym); } return new SimpleAlignment(labelsToResList); } public SymbolList symbolListForLabel(Object label) throws NoSuchElementException { SymbolList rl = (SymbolList) labelToSymbolList.get(label); if(rl == null) { throw new NoSuchElementException("No symbol list associated with label " + label); } return rl; } /** * Generate an alignment from a list of SymbolLists. *
* The SymbolLists must all be of the same length. * * @param labelToResList the label-to-symbol list mapping * @throws IllegalArgumentException if the SymbolLists are not the same * length */ public SimpleAlignment(Map labelToResList) throws IllegalArgumentException { if(labelToResList.isEmpty()) { throw new IllegalArgumentException("Can't create an alignment with no sequences"); }; this.labels = Collections.unmodifiableList(new ArrayList(labelToResList.keySet())); this.labelToSymbolList =new LinkedHashMap( labelToResList); int length = -1; List alphaList = new ArrayList(); for(Iterator li = labels.iterator(); li.hasNext(); ) { Object label = li.next(); try { SymbolList rl = symbolListForLabel(label); alphaList.add(rl.getAlphabet()); if(length == -1) { length = rl.length(); } else { if(rl.length() != length) { StringBuffer sb = new StringBuffer(); for(Iterator labI = labels.iterator(); labI.hasNext(); ) { Object lab = labI.next(); sb.append("\n\t" + lab + " (" + symbolListForLabel(lab).length() + ")"); } throw new IllegalArgumentException( "All SymbolLists must be the same length: " + sb.substring(0) ); } } } catch (NoSuchElementException nsee) { if(labelToSymbolList.containsKey(label)) { throw new IllegalArgumentException( "The symbol list associated with " + label + " is null" ); } else { throw new BioError("Something is screwey - map is lying about key/values", nsee); } } } this.alphabet = AlphabetManager.getCrossProductAlphabet(alphaList); this.length = length; } public Iterator symbolListIterator() { return new Alignment.SymbolListIterator(this); } /** * Makes a column of the alignment behave like a list. * * @author Matthew Pocock */ private final class ColAsList extends AbstractList implements Serializable { private final int col; public ColAsList(int col) { this.col = col; } protected ColAsList() { this.col = 0; } public Object get(int indx) { return symbolAt(labels.get(indx), col); } public int size() { return labels.size(); } } }