/* * Genoogle: Similar DNA Sequences Searching Engine and Tools. (http://genoogle.pih.bio.br) * Copyright (C) 2008,2009,2010,2011,2012 Felipe Fernandes Albrecht (felipe.albrecht@gmail.com) * * For further information check the LICENSE file. */ package bio.pih.genoogle.alignment; public class SubstitutionMatrixSmithWaterman extends GenoogleSequenceAlignment { private final SubstitutionMatrix substitutionTable; /* * Variables needed for traceback */ int score = Integer.MIN_VALUE; String[] align = new String[2]; String path = null; int identitySize; private final int delete; private final int insert; public SubstitutionMatrixSmithWaterman(SubstitutionMatrix substitutionTable, int delete, int insert) { this.substitutionTable = substitutionTable; this.delete = delete; this.insert = insert; } int maxI = 0, maxJ = 0, queryStart = 0, targetStart = 0; /** * @param query * @param subject * @return the score of the alignment */ public int pairwiseAlignment(String query, String subject) { int[][] scoreMatrix = new int[query.length() + 1][subject.length() + 1]; int builderLength = (int) (Math.max(query.length(), subject.length()) * 1.20); StringBuilder pathBuilder = new StringBuilder(builderLength); StringBuilder[] alignBuilder = new StringBuilder[2]; alignBuilder[0] = new StringBuilder(builderLength); alignBuilder[1] = new StringBuilder(builderLength); nonAfinedGapAlignment(query, subject, scoreMatrix, pathBuilder, alignBuilder); this.score = scoreMatrix[maxI][maxJ]; this.path = pathBuilder.reverse().toString(); this.align[0] = alignBuilder[0].reverse().toString(); this.align[1] = alignBuilder[1].reverse().toString(); return this.score; } private void nonAfinedGapAlignment(String query, String subject, int[][] scoreMatrix, StringBuilder pathBuilder, StringBuilder[] alignBuilder) { int i; int j; int queryLength = query.length(); int subjectLength = subject.length(); int k = 3; for (i = 0; i <= queryLength; i++) scoreMatrix[i][0] = 0; for (j = 0; j <= subjectLength; j++) scoreMatrix[0][j] = 0; for (i = 1; i <= queryLength; i++) { int from = Math.max(1, i - k); int to = Math.min(subjectLength, i + k); for (j = from; j <= to; j++) { scoreMatrix[i][j] = max( 0, scoreMatrix[i - 1][j] + delete, scoreMatrix[i][j - 1] + insert, scoreMatrix[i - 1][j - 1] + substitutionTable.getValue(query.charAt(i-1), subject.charAt(j-1)) ); if (scoreMatrix[i][j] > scoreMatrix[maxI][maxJ]) { maxI = i; maxJ = j; } } } /* * Here starts the traceback for non-affine gap penalities */ backtrace(query, subject, scoreMatrix, pathBuilder, alignBuilder); } private void backtrace(String query, String subject, int[][] scoreMatrix, StringBuilder pathBuilder, StringBuilder[] alignBuilder) { int i; int j; j = maxJ; for (i = maxI; i > 0;) { do { // only Deletes or Inserts or Replaces possible. // That's not what // we want to have. if (scoreMatrix[i][j] == 0) { queryStart = i; targetStart = j; i = j = 0; // Match/Replace } else { char queryChar = query.charAt(i-1); char subjectChar = subject.charAt(j-1); if (scoreMatrix[i][j] - (scoreMatrix[i - 1][j - 1] + substitutionTable.getValue(queryChar, subjectChar) ) == 0) { if (queryChar == subjectChar) { pathBuilder.append(queryChar); identitySize++; } else { if (substitutionTable.getValue(queryChar, subjectChar) >= 0) { pathBuilder.append('+'); } else { pathBuilder.append(' '); } } alignBuilder[0].append(queryChar); alignBuilder[1].append(subjectChar); i--; j--; // Insert } else if (scoreMatrix[i][j] - (scoreMatrix[i][j - 1] + insert) == 0) { alignBuilder[0].append('-'); alignBuilder[1].append(subjectChar); pathBuilder.append(' '); j--; // Delete } else { alignBuilder[0].append(queryChar); alignBuilder[1].append('-'); pathBuilder.append(' '); i--; } } } while (j > 0); } } @Override public String getQueryAligned() { return align[0]; } @Override public String getTargetAligned() { return align[1]; } @Override public String getPath() { return path; } @Override public int getQueryStart() { return queryStart + 1; } @Override public int getQueryEnd() { return maxI; } @Override public int getTargetStart() { return targetStart + 1; } @Override public int getTargetEnd() { return maxJ; } @Override public int getScore() { return score; } @Override public int getIdentitySize() { return identitySize; } }