diff --git a/src/main/java/edu/cvut/fit/kw/vmm/backend/sequences_comparement/AbstractSequenceComparator.java b/src/main/java/edu/cvut/fit/kw/vmm/backend/sequences_comparement/AbstractSequenceComparator.java new file mode 100644 index 0000000000000000000000000000000000000000..542382976c19a8d9da31678a1859c2e685cb6fa8 --- /dev/null +++ b/src/main/java/edu/cvut/fit/kw/vmm/backend/sequences_comparement/AbstractSequenceComparator.java @@ -0,0 +1,183 @@ +package edu.cvut.fit.kw.vmm.backend.sequences_comparement; + +import edu.cvut.fit.kw.vmm.alignment_solution.AlignmentSolution; + +import java.io.PrintStream; + +/** + * Contains methods and variables useful for both Needleman-Wunsch and Smith-Waterman algorithms + */ +abstract class AbstractSequenceComparator implements SequenceComparator { + + protected static final int DISTANCE_PENALTY = -1; + protected int[][] scores; + protected NeedlemanWunsch.TableDirection[][] directions; + protected String str0; + protected String str1; + + protected AbstractSequenceComparator(String str0, String str1) { + this.str0 = str0; + this.str1 = str1; + } + + /** + * Solves the problem and finds similarity + * @return best score + */ + public AlignmentSolution solve() { + initScoreMatrix(); + initDirectionMatrix(); + for(int y = 0; y < str0.length(); y++) { + for(int x = 0; x < str1.length(); x++) { + solveItem(y,x); + } + } + return getAlignmentSolution(); + } + + /** + * Computes item of the scores and stores it. It also stores how this value were achieved (which direction came the + * value from) in direction matrix. + * @param pos0 position of cahr in fist string + * @param pos1 position of char in second string + * @return score of the computed solution + */ + + protected int solveItem(int pos0, int pos1) { + char char0 = str0.charAt(pos0); + char char1 = str1.charAt(pos1); + int scoreTop = scores[pos0][pos1 + 1] + DISTANCE_PENALTY; + int scoreLeft = scores[pos0 + 1][pos1] + DISTANCE_PENALTY; + int scoreDiagonal = scores[pos0][pos1] + getSimilarity(char0, char1); + int bestScore = scoreLeft; + TableDirection bestDirection = TableDirection.HORIZONTAL; + if(scoreDiagonal >= scoreLeft && scoreDiagonal >= scoreTop) { + bestScore = scoreDiagonal; + bestDirection = TableDirection.DIAGONAL; + } + else if(scoreTop >= scoreDiagonal && scoreTop >= scoreLeft) { + bestScore = scoreTop; + bestDirection = TableDirection.VERTICAL; + } + scores[pos0 + 1][pos1 + 1] = bestScore; + directions[pos0 + 1][pos1 + 1] = bestDirection; + return bestScore; + } + + /** + * Initializes matrix of partial similarity scores. + * Allocates it and fills first row and column. + */ + protected abstract void initScoreMatrix(); + + /** + * Initializes directions of steps in score matrix + * Allocates it and fills first row and column. + */ + private void initDirectionMatrix() { + directions = new NeedlemanWunsch.TableDirection[str0.length() + 1][str1.length() + 1]; + directions[0][0] = null; + for(int i = 1; i <= str0.length(); i++) { + directions[i][0] = NeedlemanWunsch.TableDirection.VERTICAL; + } + for(int i = 1; i <= str1.length(); i++) { + directions[0][i] = NeedlemanWunsch.TableDirection.HORIZONTAL; + } + } + /** + * Generates Alignment solution instance from the solution stored in the matrices. + * @return Alignment solution of the two strings (those which are set up during class construction) + */ + protected abstract AlignmentSolution getAlignmentSolution(); + + /** + * Prints score and direction matrices to stdout (useful for debugging) + */ + public void printMatrices() { + printScoreMatrix(); + printDirectionMatrix(); + } + + /** + * Prints score matrix to stdout (useful for debugging) + */ + public void printScoreMatrix() { + PrintStream stream = System.out; + // Print header (first string) + stream.format(" "); + for(int i = 0; i < str1.length(); i++) { + stream.format("%5c", str1.charAt(i)); + } + stream.println(); + // Print actual matrix + for(int y = 0; y <= str0.length(); y++) { + if(y != 0) { + stream.format("%c", str0.charAt(y - 1)); + } + else { + stream.format(" "); + } + for(int x = 0; x <= str1.length(); x++) { + stream.format("%4d ", scores[y][x]); + } + stream.println(); + } + } + + /** + * Prints score matrix to stdout (useful for debugging) + */ + public void printDirectionMatrix() { + PrintStream stream = System.out; + // Print header (first string) + stream.format(" "); + for(int i = 0; i < str1.length(); i++) { + stream.format("%c ", str1.charAt(i)); + } + stream.println(); + // Print actual matrix + for(int y = 0; y <= str0.length(); y++) { + if(y != 0) { + stream.format("%c", str0.charAt(y - 1)); + } + else { + stream.format(" "); + } + for(int x = 0; x <= str1.length(); x++) { + NeedlemanWunsch.TableDirection direction = directions[y][x]; + if (direction == null) { + stream.format(" "); + } + else{ + switch (direction) { + case DIAGONAL: + stream.format("\\ "); + break; + case VERTICAL: + stream.format("| "); + break; + case HORIZONTAL: + stream.format("– "); + break; + } + } + } + stream.println(); + } + } + + /** + * Returns similarity score between two specified characters + * @param a first character to compare + * @param b another character to compare + * @return similarity - positive or negative value or zero + */ + protected int getSimilarity(char a, char b) { + return a == b ? 1 : -1; + } + + protected enum TableDirection { + HORIZONTAL, VERTICAL, DIAGONAL + } + +} diff --git a/src/main/java/edu/cvut/fit/kw/vmm/backend/sequences_comparement/NeedlemanWunsch.java b/src/main/java/edu/cvut/fit/kw/vmm/backend/sequences_comparement/NeedlemanWunsch.java index bb800e317ccaab860f5918c50bb7d7fd00c9f5cb..5501caede1763512327d78a597c8a056d36ababd 100644 --- a/src/main/java/edu/cvut/fit/kw/vmm/backend/sequences_comparement/NeedlemanWunsch.java +++ b/src/main/java/edu/cvut/fit/kw/vmm/backend/sequences_comparement/NeedlemanWunsch.java @@ -3,71 +3,16 @@ package edu.cvut.fit.kw.vmm.backend.sequences_comparement; import edu.cvut.fit.kw.vmm.alignment_solution.AlignmentSolution; import edu.cvut.fit.kw.vmm.alignment_solution.StringOperation; -import java.io.PrintStream; import java.util.LinkedList; import java.util.List; -public class NeedlemanWunsch { - - private static final int DISTANCE_PENALTY = -1; - private int[][] scores; - private TableDirection[][] directions; - private String str0; - private String str1; +public class NeedlemanWunsch extends AbstractSequenceComparator implements SequenceComparator { public NeedlemanWunsch(String str0, String str1) { - this.str0 = str0; - this.str1 = str1; - } - - /** - * Solves the problem and finds simliarity - * @return best score - */ - public AlignmentSolution solve() { - initScoreMatrix(); - initDirectionMatrix(); - for(int y = 0; y < str0.length(); y++) { - for(int x = 0; x < str1.length(); x++) { - solveItem(y,x); - } - } - return getAlignmentSolution(); + super(str0, str1); } - /** - * Computes item of the scores and stores it. It also stores how this value were achieved (which direction came the - * value from) in direction matrix. - * @param pos0 position of cahr in fist string - * @param pos1 position of char in second string - * @return score of the computed solution - */ - private int solveItem(int pos0, int pos1) { - char char0 = str0.charAt(pos0); - char char1 = str1.charAt(pos1); - int scoreTop = scores[pos0][pos1 + 1] + DISTANCE_PENALTY; - int scoreLeft = scores[pos0 + 1][pos1] + DISTANCE_PENALTY; - int scoreDiagonal = scores[pos0][pos1] + getSimilarity(char0, char1); - int bestScore = scoreLeft; - TableDirection bestDirection = TableDirection.HORIZONTAL; - if(scoreDiagonal >= scoreLeft && scoreDiagonal >= scoreTop) { - bestScore = scoreDiagonal; - bestDirection = TableDirection.DIAGONAL; - } - else if(scoreTop >= scoreDiagonal && scoreTop >= scoreLeft) { - bestScore = scoreTop; - bestDirection = TableDirection.VERTICAL; - } - scores[pos0 + 1][pos1 + 1] = bestScore; - directions[pos0 + 1][pos1 + 1] = bestDirection; - return bestScore; - } - - /** - * Initializes matrix of partial similarity scores. - * Allocates it and fills first row and column. - */ - private void initScoreMatrix() { + protected void initScoreMatrix() { scores = new int[str0.length() + 1][str1.length() + 1]; scores[0][0] = 0; for(int i = 1; i <= str0.length(); i++) { @@ -78,26 +23,7 @@ public class NeedlemanWunsch { } } - /** - * Initializes directions of steps in score matrix - * Allocates it and fills first row and column. - */ - private void initDirectionMatrix() { - directions = new TableDirection[str0.length() + 1][str1.length() + 1]; - directions[0][0] = null; - for(int i = 1; i <= str0.length(); i++) { - directions[i][0] = TableDirection.VERTICAL; - } - for(int i = 1; i <= str1.length(); i++) { - directions[0][i] = TableDirection.HORIZONTAL; - } - } - - /** - * Generates Alignment solution instance from the solution stored in the matrices. - * @return Alignment solution of the two strings (those which are set up during class construction) - */ - private AlignmentSolution getAlignmentSolution() { + protected AlignmentSolution getAlignmentSolution() { int bestScore = scores[str0.length()][str1.length()]; List<StringOperation> operations = getStringTransformations(); return new AlignmentSolution(operations, bestScore); @@ -112,7 +38,7 @@ public class NeedlemanWunsch { int y = str0.length(); int x = str1.length(); while(y > 0 || x > 0) { - TableDirection direction = directions[y][x]; + NeedlemanWunsch.TableDirection direction = directions[y][x]; switch (direction) { case DIAGONAL: if(str0.charAt(y - 1) == str1.charAt(x - 1)) { @@ -137,95 +63,4 @@ public class NeedlemanWunsch { return operations; } - /** - * Prints score and direction matrices to stdout (useful for debugging) - */ - public void printMatrices() { - printScoreMatrix(); - printDirectionMatrix(); - } - - /** - * Prints score matrix to stdout (useful for debugging) - */ - public void printScoreMatrix() { - PrintStream stream = System.out; - // Print header (first string) - stream.format(" "); - for(int i = 0; i < str1.length(); i++) { - stream.format("%5c", str1.charAt(i)); - } - stream.println(); - // Print actual matrix - for(int y = 0; y <= str0.length(); y++) { - if(y != 0) { - stream.format("%c", str0.charAt(y - 1)); - } - else { - stream.format(" "); - } - for(int x = 0; x <= str1.length(); x++) { - stream.format("%4d ", scores[y][x]); - } - stream.println(); - } - } - - /** - * Prints score matrix to stdout (useful for debugging) - */ - public void printDirectionMatrix() { - PrintStream stream = System.out; - // Print header (first string) - stream.format(" "); - for(int i = 0; i < str1.length(); i++) { - stream.format("%c ", str1.charAt(i)); - } - stream.println(); - // Print actual matrix - for(int y = 0; y <= str0.length(); y++) { - if(y != 0) { - stream.format("%c", str0.charAt(y - 1)); - } - else { - stream.format(" "); - } - for(int x = 0; x <= str1.length(); x++) { - TableDirection direction = directions[y][x]; - if (direction == null) { - stream.format(" "); - } - else{ - switch (direction) { - case DIAGONAL: - stream.format("\\ "); - break; - case VERTICAL: - stream.format("| "); - break; - case HORIZONTAL: - stream.format("– "); - break; - } - } - } - stream.println(); - } - } - - - /** - * Returns similarity score between two specified characters - * @param a first character to compare - * @param b another character to compare - * @return similarity - positive or negative value or zero - */ - private int getSimilarity(char a, char b) { - return a == b ? 1 : -1; - } - - protected enum TableDirection { - HORIZONTAL, VERTICAL, DIAGONAL - } - } diff --git a/src/main/java/edu/cvut/fit/kw/vmm/backend/sequences_comparement/SequenceComparator.java b/src/main/java/edu/cvut/fit/kw/vmm/backend/sequences_comparement/SequenceComparator.java new file mode 100644 index 0000000000000000000000000000000000000000..731fc578a4dae3b5d5d9a91b8116d75e2ed79704 --- /dev/null +++ b/src/main/java/edu/cvut/fit/kw/vmm/backend/sequences_comparement/SequenceComparator.java @@ -0,0 +1,13 @@ +package edu.cvut.fit.kw.vmm.backend.sequences_comparement; + +import edu.cvut.fit.kw.vmm.alignment_solution.AlignmentSolution; + +/** + * Compares sequences and aligns them. The sequences to compare are passed as constructor parameter or any another way + * (it depends on the actual class). + */ +public interface SequenceComparator { + + AlignmentSolution solve(); + +}