001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 */ 021 022package org.biojava.bio.alignment; 023 024import java.io.Serializable; 025import java.util.AbstractList; 026import java.util.ArrayList; 027import java.util.Collections; 028import java.util.Iterator; 029import java.util.LinkedHashMap; 030import java.util.List; 031import java.util.Map; 032import java.util.NoSuchElementException; 033import java.util.Set; 034 035import org.biojava.bio.BioError; 036import org.biojava.bio.symbol.AbstractSymbolList; 037import org.biojava.bio.symbol.Alphabet; 038import org.biojava.bio.symbol.AlphabetManager; 039import org.biojava.bio.symbol.IllegalSymbolException; 040import org.biojava.bio.symbol.Location; 041import org.biojava.bio.symbol.Symbol; 042import org.biojava.bio.symbol.SymbolList; 043 044/** 045 * A simple implementation of an Alignment. 046 * <p> 047 * This is a simple-stupid implementation that is made from a set of 048 * same-lengthed SymbolList objects each with an associated label. It does not 049 * handle differently lengthed sequences and doesn't contain any gap-editing 050 * concepts. 051 * 052 * @author Matthew Pocock 053 * @author Greg Cox 054 * @author Nimesh Singh 055 */ 056public class SimpleAlignment extends AbstractSymbolList implements Alignment, 057 Serializable { 058 private static final long serialVersionUID = -1760075176220928440L; 059 060 /** 061 * 062 */ 063 private LinkedHashMap<String, SymbolList> labelToSymbolList; 064 /** 065 * 066 */ 067 private List<String> labels; 068 /** 069 * 070 */ 071 private Alphabet alphabet; 072 /** 073 * 074 */ 075 private int length; 076 /** 077 * 078 */ 079 private int score; 080 081 /* 082 * (non-Javadoc) 083 * 084 * @see java.lang.Object#finalize() 085 */ 086 protected void finalize() throws Throwable { 087 super.finalize(); 088 // System.err.println("Finalizing a SimpleAlignement"); 089 } 090 091 /* 092 * (non-Javadoc) 093 * 094 * @see org.biojava.bio.symbol.SymbolList#length() 095 */ 096 public int length() { 097 return length; 098 } 099 100 /* 101 * (non-Javadoc) 102 * 103 * @see org.biojava.bio.symbol.SymbolList#getAlphabet() 104 */ 105 public Alphabet getAlphabet() { 106 return alphabet; 107 } 108 109 /* 110 * (non-Javadoc) 111 * 112 * @see org.biojava.bio.symbol.SymbolList#symbolAt(int) 113 */ 114 public Symbol symbolAt(int index) { 115 try { 116 if (labels.size() == 1) { 117 return symbolAt(labels.get(0), index); 118 } else { 119 return alphabet.getSymbol(new ColAsList<Symbol>(index)); 120 } 121 } catch (IllegalSymbolException ire) { 122 throw new BioError( 123 124 "Somehow my crossproduct alphabet is incompatible with column " 125 + index, ire); 126 } 127 } 128 129 /* 130 * (non-Javadoc) 131 * 132 * @see org.biojava.bio.alignment.Alignment#getLabels() 133 */ 134 public List<String> getLabels() { 135 return labels; 136 } 137 138 /* 139 * (non-Javadoc) 140 * 141 * @see org.biojava.bio.alignment.Alignment#symbolAt(java.lang.Object, int) 142 */ 143 public Symbol symbolAt(String label, int column) { 144 return symbolListForLabel(label).symbolAt(column); 145 } 146 147 /* 148 * (non-Javadoc) 149 * 150 * @see org.biojava.bio.alignment.Alignment#subAlignment(java.util.Set, 151 * org.biojava.bio.symbol.Location) 152 */ 153 public Alignment subAlignment(Set<String> labels, Location loc) 154 throws NoSuchElementException { 155 Map<String, SymbolList> labelsToResList = new LinkedHashMap<String, SymbolList>(); 156 Iterator<String> i; 157 if (labels != null) { 158 i = labels.iterator(); 159 } else { 160 i = getLabels().iterator(); 161 } 162 while (i.hasNext()) { 163 String label = i.next(); 164 SymbolList sym = symbolListForLabel(label); 165 if (loc != null) { 166 sym = loc.symbols(sym); 167 } 168 labelsToResList.put(label, sym); 169 } 170 return new SimpleAlignment(labelsToResList); 171 } 172 173 /* 174 * (non-Javadoc) 175 * 176 * @see 177 * org.biojava.bio.alignment.Alignment#symbolListForLabel(java.lang.String) 178 */ 179 public SymbolList symbolListForLabel(String label) 180 throws NoSuchElementException { 181 SymbolList rl = labelToSymbolList.get(label); 182 if (rl == null) { 183 throw new NoSuchElementException( 184 "No symbol list associated with label " + label); 185 } 186 return rl; 187 } 188 189 /** 190 * Generate an alignment from a list of SymbolLists. 191 * <p> 192 * The SymbolLists must all be of the same length. 193 * 194 * @param labelToResList 195 * the label-to-symbol list mapping 196 * @throws IllegalArgumentException 197 * if the SymbolLists are not the same length 198 */ 199 public SimpleAlignment(Map<String, SymbolList> labelToResList) 200 throws IllegalArgumentException { 201 if (labelToResList.isEmpty()) { 202 throw new IllegalArgumentException( 203 "Can't create an alignment with no sequences"); 204 } 205 206 this.labels = Collections.unmodifiableList(new ArrayList<String>( 207 labelToResList.keySet())); 208 this.labelToSymbolList = new LinkedHashMap<String, SymbolList>( 209 labelToResList); 210 211 int length = -1; 212 List<Alphabet> alphaList = new ArrayList<Alphabet>(); 213 for (Iterator<String> li = labels.iterator(); li.hasNext();) { 214 String label = li.next(); 215 try { 216 SymbolList rl = symbolListForLabel(label); 217 alphaList.add(rl.getAlphabet()); 218 if (length == -1) { 219 length = rl.length(); 220 } else { 221 if (rl.length() != length) { 222 StringBuffer sb = new StringBuffer(); 223 for (Iterator<String> labI = labels.iterator(); labI 224 .hasNext();) { 225 String lab = labI.next(); 226 sb.append("\n\t" + lab + " (" 227 + symbolListForLabel(lab).length() + ")"); 228 } 229 throw new IllegalArgumentException( 230 "All SymbolLists must be the same length: " 231 + sb.substring(0)); 232 } 233 } 234 } catch (NoSuchElementException nsee) { 235 if (labelToSymbolList.containsKey(label)) { 236 throw new IllegalArgumentException( 237 "The symbol list associated with " + label 238 + " is null"); 239 } else { 240 throw new BioError( 241 "Something is screwey - map is lying about key/values", 242 nsee); 243 } 244 } 245 } 246 247 this.alphabet = AlphabetManager.getCrossProductAlphabet(alphaList); 248 this.length = length; 249 } 250 251 /** 252 * 253 */ 254 public Iterator<SymbolList> symbolListIterator() { 255 return new Alignment.SymbolListIterator(this); 256 } 257 258 /** 259 * Makes a column of the alignment behave like a list. 260 * 261 * @author Matthew Pocock 262 */ 263 private final class ColAsList<T extends Symbol> extends AbstractList<T> 264 implements Serializable { 265 /** 266 * Generated serial version identifier. 267 */ 268 private static final long serialVersionUID = 8254702569039851040L; 269 private final int col; 270 271 public ColAsList(int col) { 272 this.col = col; 273 } 274 275 // protected ColAsList() { 276 // this.col = 0; 277 // } 278 279 /* 280 * (non-Javadoc) 281 * 282 * @see java.util.AbstractList#get(int) 283 */ 284 @SuppressWarnings("unchecked") 285 public T get(int indx) { 286 return (T) symbolAt(labels.get(indx), col); 287 } 288 289 /* 290 * (non-Javadoc) 291 * 292 * @see java.util.AbstractCollection#size() 293 */ 294 public int size() { 295 return labels.size(); 296 } 297 } 298 299 /** 300 * 301 * @return 302 */ 303 public int getScore() { 304 return score; 305 } 306 307 /** 308 * 309 * @param score 310 */ 311 public void setScore(int score) { 312 this.score = score; 313 } 314 315}