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 */ 021package org.biojava.nbio.core.sequence.template; 022 023import org.biojava.nbio.core.sequence.compound.NucleotideCompound; 024 025import java.util.*; 026import java.util.stream.Collectors; 027 028/** 029 * 030 * @author Andy Yates 031 * @param <C> Type of compound this set will contain but must extend 032 * NucleotideCompound 033 */ 034public abstract class AbstractNucleotideCompoundSet<C extends NucleotideCompound> 035 extends AbstractCompoundSet<C> { 036 037 protected void addNucleotideCompound(String base, String complement, String... equivalents) { 038 039 String[] upperEquivalents = new String[equivalents.length]; 040 String[] lowerEquivalents = new String[equivalents.length]; 041 for(int i=0; i<equivalents.length; i++) { 042 upperEquivalents[i] = equivalents[i].toUpperCase(); 043 lowerEquivalents[i] = equivalents[i].toLowerCase(); 044 } 045 046 C upper = newNucleotideCompound(base.toUpperCase(), complement.toUpperCase(), upperEquivalents); 047 C lower = newNucleotideCompound(base.toLowerCase(), complement.toLowerCase(), lowerEquivalents); 048 049 List<C> equivalentCompounds = new ArrayList<C>(); 050 051 for(int i=0; i<equivalents.length; i++) { 052 equivalentCompounds.add(getCompoundForString(upperEquivalents[i])); 053 equivalentCompounds.add(getCompoundForString(lowerEquivalents[i])); 054 } 055 056 addCompound(upper, lower, equivalentCompounds); 057 } 058 059 protected abstract C newNucleotideCompound(String base, String complement, String... equivalents); 060 061 /** 062 * Loops through all known nucleotides and attempts to find which are 063 * equivalent to each other. Also takes into account lower casing 064 * nucleotides as well as upper-cased ones. 065 */ 066 @SuppressWarnings("unchecked") 067 protected void calculateIndirectAmbiguities() { 068 Map<NucleotideCompound, List<NucleotideCompound>> equivalentsMap = new HashMap<NucleotideCompound, List<NucleotideCompound>>(); 069 070 List<NucleotideCompound> ambiguousCompounds = getAllCompounds().stream() 071 .filter(compound -> compound.isAmbiguous()) 072 .collect(Collectors.toCollection(ArrayList::new)); 073 074 075 for(NucleotideCompound sourceCompound: ambiguousCompounds) { 076 Set<NucleotideCompound> compoundConstituents = sourceCompound.getConstituents(); 077 for(NucleotideCompound targetCompound: ambiguousCompounds) { 078 Set<NucleotideCompound> targetConstituents = targetCompound.getConstituents(); 079 if(targetConstituents.containsAll(compoundConstituents)) { 080 NucleotideCompound lcSourceCompound = toLowerCase(sourceCompound); 081 NucleotideCompound lcTargetCompound = toLowerCase(targetCompound); 082 083 //equivalentsMap.put(sourceCompound, targetCompound); 084 // equivalentsMap.put(sourceCompound, lcTargetCompound); 085 086 087 checkAdd(equivalentsMap, sourceCompound, targetCompound); 088 checkAdd(equivalentsMap, sourceCompound, lcTargetCompound); 089 090 checkAdd(equivalentsMap,targetCompound,sourceCompound); 091 checkAdd(equivalentsMap, lcTargetCompound, sourceCompound); 092 093 checkAdd(equivalentsMap, lcSourceCompound, targetCompound); 094 checkAdd(equivalentsMap, lcSourceCompound, lcTargetCompound); 095 096 } 097 } 098 } 099 100 //And once it's all done start adding them to the equivalents map 101 102 for ( NucleotideCompound key: equivalentsMap.keySet()){ 103 List<NucleotideCompound> vals = equivalentsMap.get(key); 104 for (NucleotideCompound value: vals){ 105 addEquivalent((C)key,(C)value); 106 addEquivalent((C)value,(C)key); 107 } 108 } 109 } 110 111 private void checkAdd( 112 Map<NucleotideCompound, List<NucleotideCompound>> equivalentsMap, 113 NucleotideCompound key, 114 NucleotideCompound value) { 115 116 117 List<NucleotideCompound> listS = equivalentsMap.get(key); 118 if ( listS == null){ 119 listS = new ArrayList<NucleotideCompound>(); 120 equivalentsMap.put(key, listS); 121 } 122 listS.add(value); 123 124 125} 126 127private NucleotideCompound toLowerCase(NucleotideCompound compound) { 128 return getCompoundForString(compound.getBase().toLowerCase()); 129 } 130 131 /** 132 * Calculates the best symbol for a collection of compounds. For example 133 * if you gave this method a AC it will return a M which is the ambiguity 134 * symbol for these compounds. 135 * 136 * @param compounds Compounds to calculate ambiguity for 137 * @return The ambiguity symbol which represents this set of nucleotides best 138 */ 139 public NucleotideCompound getAmbiguity(NucleotideCompound... compounds) { 140 Set<NucleotideCompound> settedCompounds = new HashSet<NucleotideCompound>(); 141 for(NucleotideCompound compound: compounds) { 142 for(NucleotideCompound subCompound: compound.getConstituents()) { 143 settedCompounds.add(getCompoundForString(subCompound.getBase().toUpperCase())); 144 } 145 } 146 for(NucleotideCompound compound: getAllCompounds()) { 147 if(compound.getConstituents().equals(settedCompounds)) { 148 return compound; 149 } 150 } 151 return null; 152 } 153 154 /** 155 * NucleotideCompounds can always complement 156 */ 157 @Override 158 public boolean isComplementable() { 159 return true; 160 } 161}