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.symbol; 023 024/** 025 * Factory methods for constructing useful views onto SymbolLists. 026 * 027 * @author Thomas Down 028 * @author Matthew Pocock 029 * @since 1.1 030 */ 031 032import java.util.ArrayList; 033import java.util.Collections; 034import java.util.Iterator; 035import java.util.List; 036import java.util.Map; 037import java.util.Set; 038 039import org.biojava.bio.alignment.Alignment; 040import org.biojava.bio.alignment.SimpleAlignment; 041import org.biojava.bio.seq.SequenceIterator; 042import org.biojava.utils.ChangeVetoException; 043import org.biojava.utils.Unchangeable; 044 045/** 046 * Tools class for constructing views of <code>SymbolList</code> objects. 047 * 048 * @since 1.2 049 */ 050 051public final class SymbolListViews { 052 private SymbolListViews() {} 053 054 /** 055 * An n-th order view of another SymbolList. 056 * <p> 057 * In practice, what this means is that you can view a DNA sequence into an 058 * overlapping dinucleotide sequence without having to do any work yourself. 059 * </p> 060 * 061 * @param source The underlying SymbolList to view 062 * @param order The window size 063 */ 064 065 public static SymbolList orderNSymbolList(SymbolList source, int order) 066 throws IllegalAlphabetException 067 { 068 if (order == 1) 069 return source; 070 071 return new OrderNSymbolList(source, order); 072 } 073 074 /** 075 * A view of windows onto another SymbolList. 076 * <p> 077 * In practice, what this means is that you can view a DNA sequence as codons which 078 * do not overlap. 079 * </p> 080 * 081 * @param source The underlying SymbolList to view 082 * @param wsize The window size. 083 * @throws IllegalArgumentException if the symbollist length isn't an integer multiple of wsize. 084 */ 085 086 public static SymbolList windowedSymbolList(SymbolList source, int wsize) 087 throws IllegalArgumentException 088 { 089 return new WindowedSymbolList(source, wsize); 090 } 091 092 /** 093 * A reversed view onto a SymbolList. 094 * 095 * @param symbols the SymbolList to reverse. 096 */ 097 098 public static SymbolList reverse(SymbolList symbols) { 099 return new ReverseSymbolList(symbols); 100 } 101 102 /** 103 * Provides a 'translated' view of an underlying SymbolList. 104 * <p> 105 * This method allows you to translate from one alphabet into another, so 106 * for example, you could translate from DNA-triplets into amino-acids. You 107 * could also translate from DNA-dinucleotide into the 'twist' structural 108 * metric, or any other translation that takes your fancy. 109 * </p> 110 * <p> 111 * The actual mapping from source to view Symbol is encapsulated in a 112 * TranslationTable object. 113 * </p> 114 * <p> 115 * The translated SymbolList will be the same length as the source, and each 116 * Symbol in the view will correspond to a single Symbol in the source. 117 * </p> 118 * 119 * @param symbols a SymbolList to translate. 120 * @param table a translation table for mapping symbols. 121 */ 122 123 public static SymbolList translate(SymbolList symbols, 124 TranslationTable table) 125 throws IllegalAlphabetException 126 { 127 return new TranslatedSymbolList(symbols, table); 128 } 129 130 /** 131 * Construct an alignment of the SymbolLists contained in the values collection 132 * of <code>labelToSymList</code>. 133 * 134 * @param labelToSymList A Map containing label -> SymbolList mappings 135 */ 136 137 public static Alignment alignment(Map labelToSymList) 138 throws IllegalArgumentException { 139 return new SimpleAlignment(labelToSymList); 140 } 141 142 /** 143 * View a SymbolList over a cross-product Alphabet as an Alignment. 144 * 145 * @param labels a List of labels, which should be the same length 146 * as the order <code>symList</code>'s Alphabet. 147 * @param symList a SymbolList over a cross-product alphabet. 148 */ 149 150 151 public static Alignment alignment(List labels, SymbolList symList) 152 throws IllegalArgumentException { 153 return new SymListAsAlignment(labels, symList); 154 } 155 156 /** 157 * View a portion of a SymbolList. Unlike SymbolList.subList, this 158 * method is guarenteed to return a view, which will change when 159 * the underlying SymbolList is modified. 160 * 161 * @param parent the SymbolList to view 162 * @param start the first index to include in the view 163 * @param end the last index to include in the view 164 * @throws IllegalArgumentException if the start or end points fall outside the parent SymbolList. 165 * @since 1.4 166 */ 167 168 public static SymbolList subList(SymbolList parent, int start, int end) 169 throws IllegalArgumentException 170 { 171 if (start < 1 || end > parent.length()) { 172 throw new IndexOutOfBoundsException( 173 "Sublist index out of bounds " + parent.length() + ":" + start + "," + end 174 ); 175 } 176 177 if (end < start) { 178 throw new IllegalArgumentException( 179 "end must not be lower than start: start=" + start + ", end=" + end 180 ); 181 } 182 return new SubList(parent, start, end); 183 } 184 185 /** 186 * Get a new immutable, empty symbol list with the given alphabet. 187 * 188 * @since 1.4 189 * @param alpha the Alphabet this symbol list is over 190 * @return a new empty SymbolList 191 */ 192 public static SymbolList emptyList(Alphabet alpha) 193 { 194 return new EmptySymbolList(alpha); 195 } 196 197 private static class SymListAsAlignment 198 extends Unchangeable 199 implements Alignment { 200 private final SymbolList symList; 201 private final List<String> labels; 202 203 public SymListAsAlignment(List<String> labels, SymbolList symList) { 204 if(labels.size() != symList.getAlphabet().getAlphabets().size()) { 205 throw new IllegalArgumentException("There must be one label per symbol list"); 206 } 207 208 this.labels = Collections.unmodifiableList(new ArrayList<String>(labels)); 209 this.symList = symList; 210 } 211 212 public List<String> getLabels() { 213 return labels; 214 } 215 216 public SequenceIterator sequenceIterator() { 217 throw new UnsupportedOperationException("This method sucks"); 218 } 219 220 public Iterator symbolListIterator() { 221 return new Alignment.SymbolListIterator(this); 222 } 223 224 public Symbol symbolAt(String label, int column) { 225 BasisSymbol sym = (BasisSymbol) symList.symbolAt(column); 226 return (Symbol) sym.getSymbols().get(labels.indexOf(label)); 227 } 228 229 public SymbolList symbolListForLabel(String label) { 230 return new IndexedSymbolList(symList, labels.indexOf(label)); 231 } 232 233 public Alphabet getAlphabet() { 234 return symList.getAlphabet(); 235 } 236 237 public Iterator iterator() { 238 return symList.iterator(); 239 } 240 241 public int length() { 242 return symList.length(); 243 } 244 245 public String seqString() { 246 return symList.seqString(); 247 } 248 249 public SymbolList subList(int start, int end) 250 throws IndexOutOfBoundsException { 251 return symList.subList(start, end); 252 } 253 254 public String subStr(int start, int end) 255 throws IndexOutOfBoundsException { 256 return symList.subStr(start, end); 257 } 258 259 public void edit(Edit edit) 260 throws 261 IndexOutOfBoundsException, 262 IllegalAlphabetException, 263 ChangeVetoException 264 { 265 symList.edit(edit); 266 } 267 268 public List toList() { 269 return symList.toList(); 270 } 271 272 public Symbol symbolAt(int indx) 273 throws IndexOutOfBoundsException { 274 return symList.symbolAt(indx); 275 } 276 277 public Alignment subAlignment(Set labels, Location loc) { 278 throw new UnsupportedOperationException("Fixme: this needs to be implemented"); 279 } 280 } 281 282 private static class IndexedSymbolList 283 extends AbstractSymbolList { 284 private final int indx; 285 private final SymbolList symList; 286 287 public IndexedSymbolList(SymbolList symList, int indx) 288 throws IllegalArgumentException { 289 if(indx >= symList.getAlphabet().getAlphabets().size()) { 290 throw new IllegalArgumentException("index too high"); 291 } 292 293 this.indx = indx; 294 this.symList = symList; 295 } 296 297 public Alphabet getAlphabet() { 298 return (Alphabet) symList.getAlphabet().getAlphabets().get(indx); 299 } 300 301 public int length() { 302 return symList.length(); 303 } 304 305 public Symbol symbolAt(int indx) 306 throws IndexOutOfBoundsException { 307 return (Symbol) ((BasisSymbol) symList.symbolAt(indx)).getSymbols().get(this.indx); 308 } 309 } 310}