package com.compomics.util.experiment.biology.mutations; import com.compomics.util.experiment.biology.AminoAcid; import java.io.Serializable; import java.util.HashMap; import java.util.HashSet; import java.util.Set; /** * This class stores and provides mutations expected for amino acids. This class * is its own factory. * * @deprecated replaced by com.compomics.util.experiment.biology.variants.AaSubstitutionMatrix * * @author Marc Vaudel */ public class MutationMatrix implements Serializable { /** * The name of this mutation matrix. */ private String name; /** * The description of the mutation matrix. */ private String description; /** * Map of the possible amino acid mutations: original aa > mutated aa. */ private final HashMap<Character, HashSet<Character>> mutations = new HashMap<Character, HashSet<Character>>(26); /** * Map of the possible amino acid mutations: original aa > delta mass * (mutated - original) > mutated aa. */ private final HashMap<Character, HashMap<Double, HashSet<Character>>> mutationsMasses = new HashMap<Character, HashMap<Double, HashSet<Character>>>(26); /** * The minimum difference between an original amino acid and the mutated version. */ private Double minDelta = null; /** * The maximum difference between an original amino acid and the mutated version. */ private Double maxDelta = null; /** * Reverse map of the possible amino acid mutations: mutated aa > * original aa. */ private final HashMap<Character, HashSet<Character>> mutationsReverse = new HashMap<Character, HashSet<Character>>(26); /** * Mutation matrix allowing for a single base mutation. */ public static final MutationMatrix singleBaseSubstitution = singleBaseSubstitution(); /** * Mutation matrix allowing for a single base transitions mutation. */ public static final MutationMatrix transitionsSingleBaseSubstitution = transitionsSingleBaseSubstitution(); /** * Mutation matrix allowing for a single base transversion mutation. */ public static final MutationMatrix transversalSingleBaseSubstitution = transversalSingleBaseSubstitution(); /** * Mutation matrix grouping synonymous amino acids. Amino acids are grouped * according to their side chain properties: - Non-polar aliphatic groups: * {'G', 'A', 'V', 'L', 'M', 'I'} - Aromatic groups: {'F', 'Y', 'W'} - Polar * neutral groups: {'S', 'T', 'C', 'P', 'N', 'Q'} - Basic groups: {'K', 'R', * 'H'} - Acidic groups: {'D', 'E'}. */ public static final MutationMatrix synonymousMutation = synonymousMutation(); /** * Returns the implemented default mutation matrices. */ public static final MutationMatrix[] defaultMutationMatrices = new MutationMatrix[]{singleBaseSubstitution, transitionsSingleBaseSubstitution, transversalSingleBaseSubstitution, synonymousMutation}; /** * Constructor. * * @param name the name of this mutation matrix * @param description the description of the mutation matrix */ public MutationMatrix(String name, String description) { this.name = name; this.description = description; } /** * Adds a possible mutation. * * @param originalAa the original amino acid represented by its single * letter code * @param mutatedAa the mutated amino acid represented by its single letter * code */ public void addMutation(Character originalAa, Character mutatedAa) { HashSet<Character> mutatedAas = mutations.get(originalAa); if (mutatedAas == null) { mutatedAas = new HashSet<Character>(); mutations.put(originalAa, mutatedAas); } mutatedAas.add(mutatedAa); HashMap<Double, HashSet<Character>> deltaMasses = mutationsMasses.get(originalAa); if (deltaMasses == null) { deltaMasses = new HashMap<Double, HashSet<Character>>(1); mutationsMasses.put(originalAa, deltaMasses); } double deltaMass = AminoAcid.getAminoAcid(mutatedAa).getMonoisotopicMass() - AminoAcid.getAminoAcid(originalAa).getMonoisotopicMass(); if (minDelta == null || deltaMass < minDelta) { minDelta = deltaMass; } if (maxDelta == null || deltaMass > maxDelta) { maxDelta = deltaMass; } mutatedAas = deltaMasses.get(deltaMass); if (mutatedAas == null) { mutatedAas = new HashSet<Character>(); deltaMasses.put(deltaMass, mutatedAas); } mutatedAas.add(mutatedAa); HashSet<Character> originalAas = mutationsReverse.get(originalAa); if (originalAas == null) { originalAas = new HashSet<Character>(); mutationsReverse.put(mutatedAa, originalAas); } originalAas.add(originalAa); } /** * Returns the possible mutated amino acids for the given amino acid as a * map where the list of their single letter code is indexed by the delta mass to the original amino acid. Null if none found. * * @param originalAminoAcid the amino acid of interest * * @return the possible mutated amino acids */ public HashMap<Double, HashSet<Character>> getMutatedMasses(Character originalAminoAcid) { return mutationsMasses.get(originalAminoAcid); } /** * Returns the possible mutated amino acids for the given amino acid as a * list of their single letter code. Null if none found. * * @param originalAminoAcid the amino acid of interest * * @return the possible mutated amino acids */ public HashSet<Character> getMutatedAminoAcids(Character originalAminoAcid) { return mutations.get(originalAminoAcid); } /** * Returns the possible original amino acids for the given mutated amino * acid as a list of their single letter code. Null if none found. * * @param mutatedAminoAcid the mutated amino acid of interest * * @return the possible original amino acids for the given mutated amino * acid */ public HashSet<Character> getOriginalAminoAcids(Character mutatedAminoAcid) { return mutationsReverse.get(mutatedAminoAcid); } /** * Returns the amino acids where a mutation has been registered. * * @return the amino acids where a mutation has been registered */ public Set<Character> getOriginalAminoAcids() { return mutations.keySet(); } /** * Returns the possible mutated amino acids. * * @return the possible mutated amino acids */ public Set<Character> getMutatedAminoAcids() { return mutations.keySet(); } /** * Adds the content of a mutation matrix in this matrix. * * @param otherMatrix the other matrix to add */ public void add(MutationMatrix otherMatrix) { for (Character originalAa : otherMatrix.getOriginalAminoAcids()) { for (Character mutatedAa : otherMatrix.getMutatedAminoAcids(originalAa)) { addMutation(originalAa, mutatedAa); } } } /** * Returns the mutation matrix allowing for a single base mutation. * * @return the mutation matrix allowing for a single base mutation */ private static MutationMatrix singleBaseSubstitution() { MutationMatrix result = new MutationMatrix("Single Base Mutation", "Single base substitutions"); char[] bases = {'A', 'T', 'G', 'C'}; for (char originalAa : AminoAcid.getAminoAcids()) { if (originalAa != 'X') { AminoAcid aminoAcid = AminoAcid.getAminoAcid(originalAa); for (String geneCode : aminoAcid.getStandardGeneticCode()) { StringBuilder geneCodeStringBuilder = new StringBuilder(geneCode); for (int i = 0; i < geneCode.length(); i++) { char originalBase = geneCode.charAt(i); for (char base : bases) { geneCodeStringBuilder.setCharAt(i, base); String newCode = geneCodeStringBuilder.toString(); AminoAcid mutatedAminoAcid = AminoAcid.getAminoAcidFromGeneticCode(newCode); if (mutatedAminoAcid != null) { char mutatedAa = mutatedAminoAcid.getSingleLetterCodeAsChar(); if (originalAa != mutatedAa) { result.addMutation(originalAa, mutatedAa); } } } geneCodeStringBuilder.setCharAt(i, originalBase); } } } } return result; } /** * Returns the mutation matrix allowing for a single base transitions * mutation. * * @return the mutation matrix allowing for a single base transitions * mutation */ private static MutationMatrix transitionsSingleBaseSubstitution() { MutationMatrix result = new MutationMatrix("Transition Mutation", "Single base transitions substitutions."); char[] purines = {'A', 'G'}, pyrimidines = {'T', 'C'}; for (char originalAa : AminoAcid.getAminoAcids()) { if (originalAa != 'X') { AminoAcid aminoAcid = AminoAcid.getAminoAcid(originalAa); for (String geneCode : aminoAcid.getStandardGeneticCode()) { StringBuilder geneCodeStringBuilder = new StringBuilder(geneCode); for (int i = 0; i < geneCode.length(); i++) { char originalBase = geneCode.charAt(i); char[] bases; if (originalBase == purines[0] || originalBase == purines[1]) { bases = purines; } else if (originalBase == pyrimidines[0] || originalBase == pyrimidines[1]) { bases = pyrimidines; } else { throw new IllegalArgumentException(originalBase + " not recognized for transitions substitution."); } for (char base : bases) { geneCodeStringBuilder.setCharAt(i, base); String newCode = geneCodeStringBuilder.toString(); AminoAcid mutatedAminoAcid = AminoAcid.getAminoAcidFromGeneticCode(newCode); if (mutatedAminoAcid != null) { char mutatedAa = mutatedAminoAcid.getSingleLetterCodeAsChar(); if (originalAa != mutatedAa) { result.addMutation(originalAa, mutatedAa); } } } geneCodeStringBuilder.setCharAt(i, originalBase); } } } } return result; } /** * Returns the mutation matrix allowing for a single base transversion * mutation. * * @return the mutation matrix allowing for a single base transversion * mutation */ private static MutationMatrix transversalSingleBaseSubstitution() { MutationMatrix result = new MutationMatrix("Transversion Mutation", "Single base transversion substitutions."); char[] purines = {'A', 'G'}, pyrimidines = {'T', 'C'}; for (char originalAa : AminoAcid.getAminoAcids()) { if (originalAa != 'X') { AminoAcid aminoAcid = AminoAcid.getAminoAcid(originalAa); for (String geneCode : aminoAcid.getStandardGeneticCode()) { StringBuilder geneCodeStringBuilder = new StringBuilder(geneCode); for (int i = 0; i < geneCode.length(); i++) { char originalBase = geneCode.charAt(i); char[] bases; if (originalBase == purines[0] || originalBase == purines[1]) { bases = pyrimidines; } else if (originalBase == pyrimidines[0] || originalBase == pyrimidines[1]) { bases = purines; } else { throw new IllegalArgumentException(originalBase + " not recognized for transversion substitutions."); } for (char base : bases) { geneCodeStringBuilder.setCharAt(i, base); String newCode = geneCodeStringBuilder.toString(); AminoAcid mutatedAminoAcid = AminoAcid.getAminoAcidFromGeneticCode(newCode); if (mutatedAminoAcid != null) { char mutatedAa = mutatedAminoAcid.getSingleLetterCodeAsChar(); if (originalAa != mutatedAa) { result.addMutation(originalAa, mutatedAa); } } } geneCodeStringBuilder.setCharAt(i, originalBase); } } } } return result; } /** * Returns a mutation matrix grouping synonymous amino acids. Amino acids * are grouped according to their side chain properties: - Non-polar * aliphatic groups: {'G', 'A', 'V', 'L', 'M', 'I'} - Aromatic groups: {'F', * 'Y', 'W'} - Polar neutral groups: {'S', 'T', 'C', 'P', 'N', 'Q'} - Basic * groups: {'K', 'R', 'H'} - Acidic groups: {'D', 'E'}. * * @return a mutation matrix grouping synonymous amino acids */ private static MutationMatrix synonymousMutation() { MutationMatrix result = new MutationMatrix("Synonymous Mutation", "Mutations keeping amino acid properties."); char[] nonPolarAliphatic = new char[]{'G', 'A', 'V', 'L', 'M', 'I'}; for (char originalAminoAcid : nonPolarAliphatic) { for (char mutatedAminoAcid : nonPolarAliphatic) { if (originalAminoAcid != mutatedAminoAcid) { result.addMutation(originalAminoAcid, mutatedAminoAcid); } } result.addMutation('J', originalAminoAcid); } char[] aromatic = new char[]{'F', 'Y', 'W'}; for (char originalAminoAcid : aromatic) { for (char mutatedAminoAcid : aromatic) { if (originalAminoAcid != mutatedAminoAcid) { result.addMutation(originalAminoAcid, mutatedAminoAcid); } } } char[] polarNeutral = new char[]{'S', 'T', 'C', 'P', 'N', 'Q'}; for (char originalAminoAcid : polarNeutral) { for (char mutatedAminoAcid : polarNeutral) { if (originalAminoAcid != mutatedAminoAcid) { result.addMutation(originalAminoAcid, mutatedAminoAcid); } } result.addMutation('B', originalAminoAcid); result.addMutation('Z', originalAminoAcid); } char[] basic = new char[]{'K', 'R', 'H'}; for (char originalAminoAcid : basic) { for (char mutatedAminoAcid : basic) { if (originalAminoAcid != mutatedAminoAcid) { result.addMutation(originalAminoAcid, mutatedAminoAcid); } } } char[] acidic = new char[]{'D', 'E'}; for (char originalAminoAcid : acidic) { for (char mutatedAminoAcid : acidic) { if (originalAminoAcid != mutatedAminoAcid) { result.addMutation(originalAminoAcid, mutatedAminoAcid); } } result.addMutation('B', originalAminoAcid); result.addMutation('Z', originalAminoAcid); } return result; } /** * Returns the name of this mutation matrix. * * @return the name of this mutation matrix */ public String getName() { return name; } /** * Sets the name of this mutation matrix. * * @param name the name of this mutation matrix */ public void setName(String name) { this.name = name; } /** * Returns the description of this mutation matrix. * * @return the description of this mutation matrix */ public String getDescription() { return description; } /** * Sets the description of this mutation matrix. * * @param description the description of this mutation matrix */ public void setDescription(String description) { this.description = description; } /** * Returns the minimum difference between an original amino acid and the mutated version. * * @return the minimum difference between an original amino acid and the mutated version */ public Double getMinDelta() { return minDelta; } /** * Returns the maximum difference between an original amino acid and the mutated version. * * @return the maximum difference between an original amino acid and the mutated version */ public Double getMaxDelta() { return maxDelta; } /** * Indicates whether the two MutationMatrix are the same. * * @param mutationMatrix the mutation matrix * @return whether the two MutationMatrix are the same */ public boolean isSameAs(MutationMatrix mutationMatrix) { if (this.equals(mutationMatrix)) { return true; } if (!name.equals(mutationMatrix.getName())) { return false; } if (!description.equals(mutationMatrix.getDescription())) { return false; } for (Character aa : mutations.keySet()) { HashSet<Character> aaMutations = mutations.get(aa); HashSet<Character> otherMutations = mutationMatrix.getMutatedAminoAcids(aa); if (otherMutations == null || aaMutations.size() != otherMutations.size()) { return false; } for (Character mutatedAa : aaMutations) { if (!otherMutations.contains(mutatedAa)) { return false; } } } return true; } }