package bgu.bio.algorithms.alignment;
import gnu.trove.list.array.TCharArrayList;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Date;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicInteger;
import bgu.bio.util.IdentityScoringMatrix;
import bgu.bio.util.ScoringMatrix;
import bgu.bio.util.alphabet.AlphabetUtils;
import bgu.bio.util.alphabet.RnaAlphabet;
/* Class DiagonalSequenceAlignment - representing the object which will create an optimal alignment of 2 strings */
public class DiagonalSequenceAlignment implements SequenceAlignment {
/* Variables concerning the alignment algorithm */
/**
* The two input strings
*/
private char[] str1, str2;
private int b1 = 0, b2 = 0;
/**
* Lengths of the two strings
*/
private int length1, length2;
/**
* The matrix the program will fill The true scores should be divided by the
* normalization factor.
*/
private volatile double[][] dpTable;
/**
* The score matrix which will donate the values of deletion, insertion,
* substitution and matching
*/
private ScoringMatrix scoringMatrix;
/**
* The normalization factor. To get the true score, divide the integer score
* used in computation by the normalization factor.
*/
private double normFactor = 1.0;
private double score;
/**
* Constants of directions. Multiple directions are stored by bits. The zero
* direction is the starting point.
*/
private static final int DR_LEFT = 1; // 0001
private static final int DR_UP = 2; // 0010
private static final int DR_DIAG = 4; // 0100
private static final int DR_ZERO = 8; // 1000
/**
* The directions pointing to the cells that give the maximum score at the
* current cell. The first index is the row index. The second index is the
* column index.
*/
private int[][] prevCells;
/**
* The alphabet used for this program (DNA / RNA / any other kind)
*/
private AlphabetUtils alphabet;
private StringBuffer alignment;
/**
* Indicates whether or not the strings have been rotated to create a lying
* rectangle
*/
private boolean rotatedStrings = false;
/* Variables concerning the concurrent execution of the program */
/**
* The lock on which the working threads will wait for the main thread to
* inform them they can start work
*/
private Object lock = new Object();
/**
* Cyclic barrier which will indicate when it's possible to start working on
* a new diagonal (by indicating when all the workers are done working on a
* certain diagonal)
*/
// private CyclicBarrier barrier;
/**
*
*/
private AtomicInteger finishedCounter;
/**
* A flag indicating when the program needs to shut itself down (when all
* work on dpTable has ended). The value changes once the last cell in the
* matrix was filled, so the threads won't continue working for nothing.
*/
private boolean running = true;
/**
* A helping variable which causes the working threads to avoid entering the
* "fill-in" part of the run function, and wait for the work to be given to
* all threads. Its value is > 0 right before the main threads notifies all
* of the working threads they can start, and each worker decreases its
* value by 1.
*/
// private volatile int condition = 0; //helps preventing the Worker to
// start working before work was given to all threads
/**
* The maximal number of threads which can work simultaneously on the same
* diagonal. Receives its value from the user.
*/
private int numOfWorkers;
/**
* Array of workers who will be used to fill in dpTable when the program
* runs on concurrent mode
*/
private Worker[] workers;
/**
* The amount of cells each thread will do in its work. For any smaller
* amount of cells the program will run on sequential mode and won't use
* threads.
*/
private int cells;
private Object consumers = new Object();
private Job[] jobsPool;
private Queue<Job> jobs;
/* DiagonalSequenceAlignment methods */
/**
* Constructor according to given strings
*
* @param str1
* the first input string
* @param str2
* the second input string
* @param alphabet
* the alphabet used for this program
* @param matrix
* the scoring matrix
* @param numWorkers
* the number of threads for this program
* @param cells
* the job's size
*/
public DiagonalSequenceAlignment(String str1, String str2,
AlphabetUtils alphabet, ScoringMatrix matrix, int numWorkers,
int cells) {
// we will make sure in the next constructor that str1 will always be
// the shorter string, so we'll create a lying down rectangle
this(str1.length(), str2.length(), alphabet, matrix, numWorkers, cells,
0, 0);
this.setSequences(str1, str2);
this.buildMatrix();
this.getAlignment();
}
/**
* Constructor according to given strings
*
* @param str1
* the first input string
* @param b1
* beginning index on str1
* @param e1
* ending index on str1
* @param str2
* the second input string
* @param b2
* beginning index on str2
* @param e2
* ending index on str2
* @param alphabet
* the alphabet used for this program
* @param matrix
* the scoring matrix
* @param numWorkers
* the number of threads for this program
* @param cells
* the job's size
*/
public DiagonalSequenceAlignment(String str1, int b1, int e1, String str2,
int b2, int e2, AlphabetUtils alphabet, ScoringMatrix matrix,
int numWorkers, int cells) {
// we will make sure in the next constructor that str1 will always be
// the shorter string, so we'll create a lying down rectangle
this((e1 - b1 + 1), (e2 - b2 + 1), alphabet, matrix, numWorkers, cells,
b1, b2);
int l1 = e1 - b1 + 1;
int l2 = e2 - b2 + 1;
if (l1 > 0 && l2 > 0) {
this.setSequences(str1.toCharArray(), l1, str2.toCharArray(), l2);
this.buildMatrix();
this.getAlignment();
}
}
/**
* Constructor according to given sizes. Will be used when we don't
* necessarily need to create a specific matrix for specific strings, but a
* general matrix which will fit most strings inputs.
*
* @param size1
* the length of the first input string
* @param size2
* the length of the second input string
* @param alphabet
* the alphabet used for this program
* @param matrix
* the scoring matrix
* @param numWorkers
* the maximum number of threads (which the user entered) to be
* used on the program
*/
public DiagonalSequenceAlignment(int size1, int size2,
AlphabetUtils alphabet, ScoringMatrix matrix, int numWorkers,
int jobSize, int b1, int b2) {
if (size1 <= 0 && size2 <= 0) { // two empty strings, therefore the
// alignment itself is also empty
this.alignment = new StringBuffer("");
this.score = 0;
} else if (size1 <= 0) { // str1 is empty, therefore the alignment is
// constructed of insertions only
char[] arr = new char[size2];
for (int i = 0; i < size2; i++) {
arr[i] = 'I';
}
this.alignment = new StringBuffer(new String(arr));
this.score = 0;
} else if (size2 <= 0) { // str2 is empty, therefore the alignment is
// constructed of deletions only
char[] arr = new char[size1];
for (int i = 0; i < size1; i++) {
arr[i] = 'D';
}
this.alignment = new StringBuffer(new String(arr));
this.score = 0;
} else {
this.scoringMatrix = matrix;
this.alphabet = alphabet;
if (size1 <= size2) {
length1 = size1;
length2 = size2;
this.b1 = b1;
this.b2 = b2;
} else {
length1 = size2;
length2 = size1;
rotatedStrings = true;
this.b1 = b2;
this.b2 = b1;
}
// initializing the tables we need to fill
dpTable = new double[length1 + 1][length2 + 1];
prevCells = new int[length1 + 1][length2 + 1];
numOfWorkers = numWorkers;
// barrier = new CyclicBarrier(numOfWorkers+1); //+1 for the main
// thread
score = 0;
this.cells = jobSize;
finishedCounter = new AtomicInteger(0);
// creating the working objects which will fill in the table
workers = new Worker[numOfWorkers];
for (int i = 0; i < numOfWorkers; i++) {
workers[i] = new Worker(i);
}
int capacity = (length1 / cells) + 1;
jobs = new LinkedList<Job>(); // the maximal amount of jobs is the
// longest diagonal divided by the
// required cells
jobsPool = new Job[capacity];
for (int i = 0; i < capacity; i++) {
jobsPool[i] = new Job();
}
}
}
/**
* Given 2 strings - creates the suitable dpTable and prevCells arrays
*/
@Override
public void setSequences(String str1, String str2) {
this.setSequences(str1.toCharArray(), str2.toCharArray());
}
@Override
public void setSequences(char[] str1, char[] str2) {
setSequences(str1, str1.length, str2, str2.length);
}
/**
* Given 2 char arrays - creates the suitable dpTable and prevCells arrays
*/
@Override
public void setSequences(char[] s1, int size1, char[] s2, int size2) {
// making sure that this.str1 will be the shorter string
boolean init = false;
if (size1 <= size2) {
this.str1 = s1;
this.str2 = s2;
// if(dpTable!=null)
init = size1 > dpTable.length || size2 > dpTable[0].length;
length1 = size1;
length2 = size2;
} else {
this.str1 = s2;
this.str2 = s1;
// if(dpTable!=null)
init = size2 > dpTable.length || size1 > dpTable[0].length;
length1 = size2;
length2 = size1;
}
if (init) {
dpTable = new double[length1 + 1][length2 + 1];
prevCells = new int[length1 + 1][length2 + 1];
}
}
// /?????????????????????????????????????????????????????????????????????
/**
* Given 2 TCharArrayList-s - creates the suitable dpTable and prevCells
* arrays
*/
@Override
public void setSequences(TCharArrayList str1, TCharArrayList str2) {
if (this.str1 == null || this.str1.length < str1.size()) {
this.str1 = str1.toArray();
} else {
str1.toArray(this.str1);
}
if (this.str2 == null || this.str2.length < str2.size()) {
this.str2 = str2.toArray();
} else {
str2.toArray(this.str2);
}
boolean init = str1.size() > dpTable.length
|| str2.size() > dpTable[0].length;
length1 = str1.size();
length2 = str2.size();
if (init) {
dpTable = new double[length1 + 1][length2 + 1];
prevCells = new int[length1 + 1][length2 + 1];
}
}
/**
* Creates the dpTable matrix according to the scores in the scoring matrix
*/
@Override
public void buildMatrix() {
int i; // length of prefix substring of str1
int j; // length of prefix substring of str2
// basic conditions: filling in row 0 and column 0
// the cell [0][0]
dpTable[0][0] = 0.0;
prevCells[0][0] = DR_ZERO;
// first row - the 0 row
for (j = 1; j <= length2; j++) {
dpTable[0][j] = this.scoringMatrix.score(alphabet.emptyLetter(),
str2[j - 1]) + dpTable[0][j - 1];
prevCells[0][j] = DR_LEFT; // marks that we arrived "from left" to
// 0,j
}
// first column - the 0 column
for (i = 1; i <= length1; i++) {
dpTable[i][0] = this.scoringMatrix.score(str1[i - 1],
alphabet.emptyLetter())
+ dpTable[i - 1][0];
prevCells[i][0] = DR_UP; // marks that we arrived "from above" to
// i,0
}
/*
* 'sum' represents the sum of the indexes i & j of a certain cell [i,j]
* in the matrix. 'j' will mark the column index of the first cell in
* the diagonal
*/
int sum;
int numOfCellsInDiagonal = 1;
// int threadsNeeded = 0;
for (int k = 0; k < numOfWorkers; k++) {
workers[k].start();
}
j = 1; // for the first 'for' loop the first cell in a diagonal will
// always have the column index 1
/* first part of the matrix alignment */
for (sum = 2; sum < length1 + 1; sum++) {
/*
* //computing the needed amount of threads threadsNeeded =
* neededThreads(numOfCellsInDiagonal);
*
* if(threadsNeeded >= 2){ //we will use the amount of threads
* needed concurrent(threadsNeeded, sum, j, numOfCellsInDiagonal); }
* else sequential(sum-j, j, numOfCellsInDiagonal);
*
*
* System.out.println(
* "main thread about to move to the next step in the loop");
*/
diagonalComputation(numOfCellsInDiagonal, sum, j);
numOfCellsInDiagonal++;
}
/* mid part of the matrix alignment */
for (sum = length1 + 1; sum <= length2 + 1; sum++) {
/*
* //computing the needed amount of threads threadsNeeded =
* neededThreads(numOfCellsInDiagonal);
*
* if(threadsNeeded >= 2){ //we will use the amount of threads
* needed (not necessarily all of the workers)
* concurrent(threadsNeeded, sum, j, numOfCellsInDiagonal); } else
* //for under 2 threads it is unnecessary to operate on concurrent
* mode sequential(sum-j, j, numOfCellsInDiagonal);
*/
diagonalComputation(numOfCellsInDiagonal, sum, j);
j++;
}
numOfCellsInDiagonal--;
/* last part of the matrix alignment */
for (sum = length2 + 2; sum <= (length1 + length2); sum++) {
diagonalComputation(numOfCellsInDiagonal, sum, j);
/*
* //computing the needed amount of threads threadsNeeded =
* neededThreads(numOfCellsInDiagonal);
*
*
* if(threadsNeeded >= 2){ //we will use the amount of threads
* needed concurrent(threadsNeeded, sum, j, numOfCellsInDiagonal); }
* else sequential(sum-j, j, numOfCellsInDiagonal);
*/
numOfCellsInDiagonal--;
j++;
}
running = false;
for (int k = 0; k < numOfWorkers; k++) {
workers[k].interrupt();
}
this.score = dpTable[length1][length2];
// System.out.println("finished DSA");
}
/**
* Print the dynamic programming matrix
*/
public void printDPMatrix() {
System.out.print(" ");
for (int j = 1; j <= length2; j++)
System.out.print(" " + str2[j - 1]);
System.out.println();
for (int i = 0; i <= length1; i++) {
if (i > 0)
System.out.print(str1[i - 1] + " ");
else
System.out.print(" ");
for (int j = 0; j <= length2; j++) {
System.out.print(dpTable[i][j] / normFactor + " ");
}
System.out.println();
}
}
/**
* Set the normal factor
*/
@Override
public void setNormFactor(double factor) {
this.normFactor = factor;
}
/**
* Get the maximum value in the
*/
@Override
public double getAlignmentScore() {
return getMaxScore() / normFactor;
}
/**
* Get the maximum value (normalized) in the filled dynamic programming
* table
*/
private double getMaxScore() {
return this.score;
}
/**
* Determines the needed computation method for the current diagonal
* (sequential or concurrent) and fills the diagonal using the selected
* method.
*
* @param numOfCellsInDiagonal
* the number of cells in the current diagonal
* @param sum
* the sum of the row and column indexes of a cell in the current
* diagonal
* @param j
* the first column index in the current diagonal
*/
private void diagonalComputation(int numOfCellsInDiagonal, int sum, int j) {
// computing the needed amount of threads
// int threadsNeeded = neededThreads(numOfCellsInDiagonal);
if (numOfCellsInDiagonal >= cells) { // we will use the amount of
// threads needed (not
// necessarily all of the
// workers)
// System.out.println("going to use threads");
concurrent(sum, j, numOfCellsInDiagonal);
} else
// for under 2 threads it is unnecessary to operate on concurrent
// mode
sequential(sum - j, j, numOfCellsInDiagonal);
}
/**
* The help function that will be called to work on a specific diagonal, if
* NO use of threads is needed (on sequential mode)
*
* @param rowB
* the first row index of the diagonal
* @param colB
* the first column index of the diagonal
* @param numOfCells
* the amount of cells needed to be filled in this diagonal
*/
private void sequential(int rowB, int colB, int numOfCells) {
int k = 1; // counter for the number of filled cells
int currRow = rowB;
int currColumn = colB;
while (k <= numOfCells) {
// actually filling the table
helpFill(currRow, currColumn);
currRow--;
currColumn++;
k++;
}
}
/**
* The help function that will be called to work on a specific diagonal, if
* use of threads is needed (on concurrent mode)
*
* @param threadsNeeded
* the amounts of threads needed to work on this diagonal
* @param sum
* the sum of the row and column indexes of any cell in this
* diagonal
* @param j
* the column index of the first cell in the given diagonal, from
* which the partition of work will start
* @param numOfCellsInDiagonal
* the amount of cells in this diagonal
*/
private void concurrent(int sum, int j, int numOfCellsInDiagonal) {
finishedCounter.set(0);
int i = 1;
int columnIndex = j;
// int rowIndex = 0;
int res = numOfCellsInDiagonal / cells;
int iterations = numOfCellsInDiagonal % cells == 0 ? res : res + 1;
// long startTime5, endTime5;
Job job;
while (i <= iterations) {
job = jobsPool[i - 1];
job.beginningColumn = columnIndex;
job.beginningRow = sum - columnIndex;
// job.howMany = iterations;
// job.c = c;
if (i == iterations) // the last iteration - the last job will be
// the remaining amount of cells
job.numOfCells = numOfCellsInDiagonal - (iterations - 1)
* cells;
else
// in all iterations except the last one, the job will be the
// regular number of cells to fill
job.numOfCells = cells;
// startTime5 = System.currentTimeMillis();
jobs.add(job);
// endTime5 = System.currentTimeMillis();
// time5 += (double)(endTime5 - startTime5)/60000;
columnIndex += cells;
i++;
}
synchronized (consumers) {
// System.out.println("releasing threads");
// mainFinished = true;
for (int t = 0; t < numOfWorkers; t++)
workers[t].shouldWork = true;
// System.out.println("main releasing threads");
consumers.notifyAll();
// System.out.println("main finished inserting to queue, notifying the workers...");
}
// long endTime1 = System.currentTimeMillis();
// time1 += (double)(endTime1 - startTime1)/60000;
synchronized (lock) {
while (finishedCounter.get() != numOfWorkers) {
try {
lock.wait();
// System.out.println("main was released by the workers - moving to the next diagonal");
} catch (InterruptedException e) {
System.out
.println("this message should never be printed since no one interrupts main");
}
}
}
/*
* barrier.reset(); //+1 for the main thread
*
* int i = 1; int columnIndex = j; int rowIndex = 0; int cells =
* numOfCellsInDiagonal/threadsNeeded; while (i<=threadsNeeded){
* rowIndex = sum - columnIndex; if(i!=threadsNeeded){ //in all
* iterations except the last one, the thread will be given the minimum
* number of cells to fill workers[i-1].setIndex(rowIndex, columnIndex,
* cells); columnIndex = columnIndex + cells; } else{ //the last
* iteration - the last thread will be given the "remains" of the
* //diagonal (number of cells in this thread's work might be bigger
* than the minimum workers[i-1].setIndex(rowIndex, columnIndex,
* numOfCellsInDiagonal - ((i-1)*cells)); } i++; }
*
*
*
* //after giving work to each worker, the main thread releases the
* workers to commit their job synchronized(lock){ condition =
* numOfWorkers; //????????????????????????????????// lock.notifyAll();
* }
*
*
* //main thread counts down and will be released when all of the
* workers will finish try { barrier.await(); } catch
* (InterruptedException e){ e.printStackTrace(); } catch
* (BrokenBarrierException e){ // TODO Auto-generated catch block
* e.printStackTrace(); }
*/
}
/**
* Fill in the cells of dpTable and prevCells according to the given indexes
*
* @param i
* - row index
* @param j
* - column index
*/
private double helpFill(int i, int j) {
final double diagScore = dpTable[i - 1][j - 1] + similarity(i, j); // match
// or
// substitution
final double leftScore = dpTable[i][j - 1] + similarity(0, j); // a
// letter
// was
// read
// from
// str2
final double upScore = dpTable[i - 1][j] + similarity(i, 0); // a letter
// was
// read
// from
// str1
dpTable[i][j] = max(diagScore, max(upScore, leftScore)); // determines
// which
// option
// will give
// the
// highest
// score
// find the directions that give the maximum scores.
// the bitwise OR operator is used to record multiple
// directions.
prevCells[i][j] = 0;
if (diagScore == dpTable[i][j]) { // match or substitution
prevCells[i][j] |= DR_DIAG;
}
if (leftScore == dpTable[i][j]) { // a letter was read from str2
prevCells[i][j] |= DR_LEFT;
}
if (upScore == dpTable[i][j]) { // a letter was read from str1
prevCells[i][j] |= DR_UP;
}
return dpTable[i][j];
}
/**
* Compute the similarity score of substitution: use a substitution matrix
* if the cost model The position of the first character is 1. A position of
* 0 represents a gap.
*
* @param i
* Position of the character in str1
* @param j
* Position of the character in str2
* @return cost of substitution of the character in str1 by the one in str2
*/
private final double similarity(int i, int j) {
final char c1 = i == 0 ? alphabet.emptyLetter() : str1[i - 1 + b1]; // if
// i=0
// than
// no
// letter
// was
// read
// from
// str1
final char c2 = j == 0 ? alphabet.emptyLetter() : str2[j - 1 + b2]; // if
// j=0
// than
// no
// letter
// was
// read
// from
// str2
return scoringMatrix.score(c1, c2);
}
/**
* Returns the higher value: a or b
*/
private final double max(double a, double b) {
return a > b ? a : b;
}
/**
*
* @return
*/
public StringBuffer getAlignmentInBuffer() {
StringBuffer ans = new StringBuffer();
int i = length1;
int j = length2;
int val = 0;
while (!(i == 0 && j == 0)) {
val = prevCells[i][j];
if (val == 1) {
ans.append('I');
j--;
} else if (val == 2) {
ans.append('D');
i--;
} else if (val == 4) {
if (str1[i - 1 + b1] == str2[j - 1 + b2])
ans.append('M');
else
ans.append('R');
i--;
j--;
} else if (val == 3) {
if (Math.random() > 0.5) {
ans.append('I');
j--;
} else {
ans.append('D');
i--;
}
} else if (val == 5) {
if (Math.random() > 0.5) {
ans.append('I');
j--;
} else {
if (str1[i - 1 + b1] == str2[j - 1 + b2])
ans.append('M');
else
ans.append('R');
i--;
j--;
}
} else if (val == 6) {
if (Math.random() > 0.5) {
ans.append('D');
i--;
} else {
if (str1[i - 1 + b1] == str2[j - 1 + b2])
ans.append('M');
else
ans.append('R');
i--;
j--;
}
} else { // val = 7 (M/R or I or D)
double rand = Math.random();
if (rand < 0.3) {
ans.append('D');
i--;
} else if (rand >= 0.3 && rand < 0.6) {
ans.append('I');
j--;
} else {
if (str1[i - 1 + b1] == str2[j - 1 + b2])
ans.append('M');
else
ans.append('R');
i--;
j--;
}
}
}
ans.reverse();
if (rotatedStrings) { // the query was accepted as a standing rectangle,
// so translate the alignment to the mirror
// alignment
char[] arr = ans.toString().toCharArray();
for (int t = 0; t < arr.length; t++) {
if (arr[t] == 'I')
arr[t] = 'D';
else if (arr[t] == 'D')
arr[t] = 'I';
}
ans = new StringBuffer(new String(arr));
}
this.alignment = ans;
return ans;
}
public StringBuffer getAlignmentString() {
return this.alignment;
}
/**
* Compute the needed amount of threads for the filling of a specific
* diagonal
*
* @param cells
* the amount of cells in the diagonal
* @return the amount of needed threads
*
* private int neededThreads(int cells){ int ans = cells /
* minCellsPerWorker;
*
* //insuring that the maximal number of threads won't be bigger
* than the given amount of threads if(ans > numOfWorkers){ ans =
* numOfWorkers; } return ans; }
*/
/**
* Main
*/
public static void main(String[] args) {
// int n = 24; //need to get this from the user?
// int jobSize = 2000;
FileReader input1 = null, input2 = null;
// reading s1 from a file
StringBuffer s1 = new StringBuffer();
try {
input1 = new FileReader(args[0]); // get the argument
} catch (FileNotFoundException e) {
System.out.println("where is file 1?");
e.printStackTrace();
}
BufferedReader buf1 = new BufferedReader(input1);
String lineFromF1;
try {
lineFromF1 = buf1.readLine();
while (lineFromF1 != null) {
s1.append(lineFromF1); // connects the string to the
// StringBuffer
lineFromF1 = buf1.readLine();
}
buf1.close(); // close the buffered reader
} catch (IOException e1) {
System.out.println("IO problem in F1");
e1.printStackTrace();
}
String str1 = s1.toString(); // cast the StringBuffer to string, so we
// could handle it in the
// DiagoalSequenceAlignment class
// same process for s2...
StringBuffer s2 = new StringBuffer();
try {
input2 = new FileReader(args[1]);
} catch (FileNotFoundException e) {
System.out.println("where is file 2?");
e.printStackTrace();
}
BufferedReader buf2 = new BufferedReader(input2);
String lineFromF2;
try {
lineFromF2 = buf2.readLine();
while (lineFromF2 != null) {
s2.append(lineFromF2); // connects the string to the
// StringBuffer
lineFromF2 = buf2.readLine();
}
buf2.close(); // close the buffered reader
} catch (IOException e1) {
System.out.println("IO problem in F2");
e1.printStackTrace();
}
String str2 = s2.toString(); // cast the StringBuffer to string, so we
// could handle it in the
// DiagoalSequenceAlignment class
int n = Integer.parseInt(args[2]);
int jobSize = Integer.parseInt(args[3]);
/*
* int b1 = Integer.parseInt(args[4]); int e1 =
* Integer.parseInt(args[5]); int b2 = Integer.parseInt(args[6]); int e2
* = Integer.parseInt(args[7]); /* String str2 =
* "ACTTGAC";//"GGCTTGCACAGTGCTGACTACTGCCGTAGTGCAAATCGACTTCGAGAGGGTGAGA"
* ; String str1 =
* "CGACTAGCT";//"AGCTTGTGGCTGAAAGCTAGATTTCGGATCGCACAGGTCTGTGTCGACACTCTTC"
* ; int n = 2; int jobSize = 3;
*/
System.out.println(new Date());
DiagonalSequenceAlignment alignment = new DiagonalSequenceAlignment(
str2, 15412, 15917, str1, 15411, 16187,
RnaAlphabet.getInstance(), new IdentityScoringMatrix(
RnaAlphabet.getInstance()), n, jobSize);
System.out.println("Score is: " + alignment.getAlignmentScore());
System.out.println("alignment is:\n" + alignment.getAlignmentString());
// System.out.println(alignment.getAlignmentScore());
// alignment.printAlignments();
// alignment.printDPMatrix();
// alignment.printDPMatrixInLatexMatrix();
System.out.println(new Date());
}
/*
* Class Worker - representing the runnable object that will fill the tables
*/
private class Worker extends Thread {
/**
* Beginning and ending indexes indicating the work borders, and the
* amount of cells this worker will need to fill
*/
// private volatile int rowB , colB, numOfCells;
/**
* The Worker's ID number (for debug)
*/
private int id;
/**
* Flag which changes to 'true' only when a worker is given work to do,
* and changes back to 'false' when the Worker is done working
*/
boolean shouldWork = false;
/**
* Constructor
*
* @param id
* the unique ID number of the worker
*/
public Worker(int id) {
this.id = id;
}
/**
* Set the beginning and ending indexes of the worker's job
*
* @param rowB
* the beginning point - row index
* @param colB
* the beginning point - column index
* @param numOfCells
* the number of cells the Worker will need to fill in a
* specific "round" of work
*
* public void setIndex(int rowB, int colB, int numOfCells){
* this.rowB = rowB; this.colB = colB; this.numOfCells =
* numOfCells; shouldWork = true; }
*/
/**
* The Worker run function which actually computes and writes the
* suiting values in dpTable and prevCells
*/
@Override
public void run() {
while (running) { // the condition fails only when all of dpTable
// was filled
synchronized (consumers) {
try {
while (!shouldWork) {
consumers.wait();
// System.out.println("thread was released by main");
}
shouldWork = false;
} catch (InterruptedException e) {
return;
}
}
// System.out.println("Size of queue= " + jobs.size());
Job myJob = null;
do {
// long startTime2 = System.currentTimeMillis();
synchronized (jobs) {
myJob = jobs.poll();
}
if (myJob != null) {
if (myJob.numOfCells == -1)
return;
// long endTime2 = System.currentTimeMillis();
// time2 += (double)(endTime2 - startTime2)/60000;
// synchronized(lock2){
// fill the table
int rowB = myJob.beginningRow; // row index of the first
// cell to be filled in
// the worker's job
int colB = myJob.beginningColumn; // column index of the
// first cell to be
// filled in the
// worker's job
int count = myJob.numOfCells; // counter for the number
// of unfilled cells
// char c = myJob.c;
int k = 0;
int currRow = rowB;
int currColumn = colB;
// System.out.println("worker commiting job: from [" +
// rowB + "][" + (colB) + "], filling up " + count +
// " cells, on diagonal of sum " + (rowB+colB));
while (k < count) {
helpFill(currRow, currColumn);
currRow--;
currColumn++;
k++;
}
/*
* while(k <= numOfCells){ //actually filling the table
* double d = helpFill(currRow, currColumn);
* System.out.println("worker " + this.id +
* " filled in [" + currRow + ", " + currColumn +
* "] the value " + d); currRow--; currColumn++; k++; }
*/
// }
// long endJob = System.currentTimeMillis();
// time3 += (double)(endJob - endTime2)/60000;
}
} while (myJob != null);
int num = finishedCounter.incrementAndGet(); // indicates a job
// was done
if (num == numOfWorkers) {
// System.out.println("threads releasing main");
synchronized (lock) {
lock.notify();
// System.out.println("last thread notified and released main");
}
}
}
/*
* while(running){ //the condition fails only when all of dpTable
* was filled System.out.println("worker started");
* synchronized(lock){ //catches the lock try { while(condition==0){
* // meant for the threads to wait for every worker to receive job
* and only then start //(condition > 0 right before buildMatrix
* function calls notifyAll) lock.wait(); } condition--; //each
* worker that got work "informs" that it starts } catch
* (InterruptedException e) { return; } }
* System.out.println("worker " + this.id +
* " finished waiting on the try / catch"); if(shouldWork){ //this
* part of the function will be executed only by the workers who
* were given work to do // fill the table int k=1; //counter for
* the number of filled cells int currRow = rowB; int currColumn =
* colB; while(k <= numOfCells){ //actually filling the table double
* d = helpFill(currRow, currColumn); System.out.println("worker " +
* this.id + " filled in [" + currRow + ", " + currColumn +
* "] the value " + d); currRow--; currColumn++; k++; }
* System.out.println("worker finished his part in the diagonal");
* shouldWork = false; }
*
* //count down to mark the main thread that the worker is done
* working and waits for a new job try { barrier.await(); } catch
* (InterruptedException e){ return; }
*
* catch (BrokenBarrierException e){ // TODO Auto-generated catch
* block e.printStackTrace(); } }
*/
}
/**
* Fill in the cells of dpTable and prevCells according to the given
* indexes
*
* @param i
* - row index
* @param j
* - column index
*/
private double helpFill(int i, int j) {
final double diagScore = dpTable[i - 1][j - 1] + similarity(i, j); // match
// or
// substitution
final double leftScore = dpTable[i][j - 1] + similarity(0, j); // a
// letter
// was
// read
// from
// str2
final double upScore = dpTable[i - 1][j] + similarity(i, 0); // a
// letter
// was
// read
// from
// str1
dpTable[i][j] = max(diagScore, max(upScore, leftScore)); // determines
// which
// option
// will
// give
// the
// highest
// score
// find the directions that give the maximum scores.
// the bitwise OR operator is used to record multiple
// directions.
prevCells[i][j] = 0;
if (diagScore == dpTable[i][j]) { // match or substitution
prevCells[i][j] |= DR_DIAG;
}
if (leftScore == dpTable[i][j]) { // a letter was read from str2
prevCells[i][j] |= DR_LEFT;
}
if (upScore == dpTable[i][j]) { // a letter was read from str1
prevCells[i][j] |= DR_UP;
}
return dpTable[i][j];
}
/**
* Compute the similarity score of substitution: use a substitution
* matrix if the cost model The position of the first character is 1. A
* position of 0 represents a gap.
*
* @param i
* Position of the character in str1
* @param j
* Position of the character in str2
* @return cost of substitution of the character in str1 by the one in
* str2
*/
private final double similarity(int i, int j) {
final char c1 = i == 0 ? alphabet.emptyLetter() : str1[i - 1 + b1]; // if
// i=0
// than
// no
// letter
// was
// read
// from
// str1
final char c2 = j == 0 ? alphabet.emptyLetter() : str2[j - 1 + b2]; // if
// j=0
// than
// no
// letter
// was
// read
// from
// str2
return scoringMatrix.score(c1, c2);
}
/**
* Returns the higher value: a or b
*/
private final double max(double a, double b) {
return a > b ? a : b;
}
} // end of class Worker
/*
*
* private class ReusableBarrier{
*
* int parties;
*
*
* public ReusableBarrier(int parties){ this.parties = parties; }
*
*
* public synchronized void reset(int i){ parties = i; }
*
* public synchronized void await() throws InterruptedException // throws
* exception?? { parties--; if (parties==0){ this.notifyAll(); } else
* this.wait();
*
* }
*
* } //end of class ReusableBarrier
*/
/**
* Class Job
*/
private class Job {
private volatile int beginningRow; // the row index of the first cell in
// this job
private volatile int beginningColumn; // the column index of the first
// cell in this job
private volatile int numOfCells; // the amount of cells needs to be
// filled in this job
// private volatile int howMany; //this job is one of how many jobs?
// private volatile char c; //state of filling
} // end of class Job
@Override
public String[] getAlignment() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Need to implement");
}
@Override
public DiagonalSequenceAlignment cloneAligner() {
throw new UnsupportedOperationException("Need to implement");
}
}// end of class DiagonalSeuenceAlignment