package bgu.bio.algorithms.alignment;
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.ArrayBlockingQueue;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicInteger;
import gnu.trove.list.array.TCharArrayList;
//import bgu.bio.algorithms.alignment.DiagonalSequenceAlignmentNoMatrix.Worker;
import bgu.bio.adt.queue.BlockingQueue;
import bgu.bio.util.IdentityScoringMatrix;
import bgu.bio.util.ScoringMatrix;
import bgu.bio.util.alphabet.AlphabetUtils;
import bgu.bio.util.alphabet.RnaAlphabet;
/* Class DiagonalSequenceAlignmentNoMatrix - representing the object which will create an
* optimal alignment of 2 strings, without saving an entire matrix, but in the 3 diagonals (3 lines) method */
public class DiagonalSequenceAlignmentNoMatrix /* implements SequenceAlignment*/{
/* Variables concerning the alignment algorithm */
/**
* The two input strings
*/
private char[] str1, str2;
/**
* Lengths of the two strings
*/
private int length1, length2;
/**
* The score of this alignment
*/
private double maxScore;
/**
* The three lines the program will fill instead of the whole matrix.
* The true scores should be divided by the normalization factor.
*/
private double[] lineA, lineB, lineC;
/**
* The line which will be switched on every iteration
*/
private double[] toDelete;
/**
* 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;
/**
* The alphabet used for this program (DNA / RNA / any other kind)
*/
private AlphabetUtils alphabet;
/* 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();
private int myCounter = 0; //DEBUG
/**
* 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;
/**
* 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 minimal amount of cells one thread will do in its work. For any smaller amount of cells
* the program will run on sequential mode and won't use threads.
* Should this be received from the user as well???????????????????????????????????????????????????
*/
private final int minCellsPerWorker = 20;
/**
*
*/
private Queue<Job> jobs;
/**
*
*/
private int cells;
/**
*
*/
private AtomicInteger finishedCounter;
private Object consumers = new Object();
private Job[] jobsPool;
private double time1, time5;
private int start1=0, start2=0, e1=0, e2=0;
/* DiagonalSequenceAlignment methods */
public DiagonalSequenceAlignmentNoMatrix(String s1, int b1, int e1, String s2, int b2, int e2, AlphabetUtils alphabet, ScoringMatrix matrix, int numWorkers, int jobSize){
int l1 = e1-b1+1;
int l2 = e2-b2+1;
if(l1 <= l2){
this.start1 = b1;
this.start2 = b2;
this.e1 = e1;
this.e2 = e2;
this.str1 = s1.toCharArray();
this.str2 = s2.toCharArray();
length1 = l1;
length2 = l2;
}
else{
this.start1 = b2;
this.start2 = b1;
this.e1 = e2;
this.e2 = e1;
this.str1 = s2.toCharArray();
this.str2 = s1.toCharArray();
length1 = l2;
length2 = l1;
}
this.scoringMatrix = matrix;
this.alphabet = alphabet;
//initializing the lines which need to be filled
//the two diagonals should be in the length of the shorter string + 1:
lineA = new double[length1+1];
lineB = new double[length1+1];
lineC = new double[length1+1];
numOfWorkers = numWorkers;
cells = jobSize;
//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();
}
finishedCounter = new AtomicInteger(0);
}
/**
* Constructor according to given strings. Creates an alignment such that the supposed table would have been a lying rectangle.
* @param s1 the first input string
* @param s2 the second input string
* @param alphabet the alphabet used for this program
* @param matrix the scoring matrix
* @param numWorkers the maximal number of threads for this program
*/
public DiagonalSequenceAlignmentNoMatrix(String s1,String s2,AlphabetUtils alphabet, ScoringMatrix matrix, int numWorkers, int jobSize){
this.scoringMatrix = matrix;
this.alphabet = alphabet;
int size1 = s1.length();
int size2 = s2.length();
if(size1 <= size2){ //s1 is shorter
length1 = size1;
length2 = size2;
this.str1 = s1.toCharArray();
this.str2 = s2.toCharArray();
}
else{ //s2 is shorter
length1 = size2;
length2 = size1;
this.str1 = s2.toCharArray();
this.str2 = s1.toCharArray();
}
//initializing the lines which need to be filled
//the two diagonals should be in the length of the shorter string + 1:
lineA = new double[length1+1];
lineB = new double[length1+1];
lineC = new double[length1+1];
numOfWorkers = numWorkers;
cells = jobSize;
//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();
}
finishedCounter = new AtomicInteger(0);
}
/**
* Fills up the DP table values, in 3 diagonals form.
*/
public void buildMatrix(){
int j; // length of prefix substring of str2
/*
* Indicates the current state of filling - according to which cells the current cell (position i
* in lineC) needs to be filled (will be sent to the filling function - helpFill):
* case a:
* diagScore (i-1), upScore (i), leftScore (i-1)
* case b:
* diagScore (i), upScore (i+1), leftScore (i)
* case c:
* diagScore (i+1), upScore (i+1), leftScore (i)
*/
char state;
/*
* '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;
//counter for the number of cells which need to be filled in the current diagonal
int numOfCellsInDiagonal = 2;
//initialize the worker threads
for(int k=0; k<numOfWorkers; k++){
workers[k].start();
}
j=0; //for the first 'for' loop the first cell in a diagonal will always have the column index 0
state = 'a';
// int k;
/* first part of the matrix alignment */
for(sum = 1; sum < length1; sum++){
//computing the values in the current diagonal
diagonalComputation(numOfCellsInDiagonal, sum, j, state);
/*
//in the second iteration only - print specifically the first 3 diagonals
if(sum==2){
System.out.println(0.0);
//print the next diagonal
for(k=0; k<=1; k++){
System.out.print(lineA[k] + " ");
}
System.out.println("");
//print the next diagonal
for(k=0; k<=2; k++){
System.out.print(lineB[k] + " ");
}
System.out.println("");
}
if(sum>=3){
//print the next diagonal
for(k=0; k<=numOfCellsInDiagonal-1; k++){
System.out.print(lineC[k] + " ");
}
System.out.println("");
}
*/
//recycling the 3 lines
if(sum>2){ //sum >= 3 (starting from the 4th diagonal)
swapAndDelete();
}
numOfCellsInDiagonal++;
}
/* mid part of the matrix alignment */
for(sum = length1; sum < length2+1; sum++){
state = 'c'; //from now on (except for 2 cases), the state is always c
if(j==0){ //on the first iteration where j=0 the state is a
state = 'a';
}
if(j==1){ //on the second iteration where j=1 the state is b
state = 'b';
}
//computing the values in the current diagonal
diagonalComputation(numOfCellsInDiagonal, sum, j, state);
/*
//print the next diagonal
for(k=0; k<=numOfCellsInDiagonal-1; k++){
System.out.print(lineC[k] + " ");
}
System.out.println("");
*/
//recycle diagonals
if(sum>2)
swapAndDelete();
j++;
}
numOfCellsInDiagonal--;
/* last part of the matrix alignment */
for(sum = length2+1; sum <= (length1+length2); sum++){
state = 'c';
if(j==1 && length1==length2){
state = 'b';
}
//computing the values in the current diagonal
diagonalComputation(numOfCellsInDiagonal, sum, j, state);
/*
//print the next diagonal
for(k=0; k<=numOfCellsInDiagonal-1; k++){
System.out.print(lineC[k] + " ");
}
System.out.println("");
*/
if(sum == length1+length2){ //last iteration sets the score of the alignment
setMaxScore(lineC[0]);
if(length1==1) //s1 is a very short string
setMaxScore(lineB[0]);
}
//recycle the diagonals
if(sum!=length1+length2){ //all except the last iteration
swapAndDelete();
}
numOfCellsInDiagonal--;
j++;
}
//stop the threads activity
running = false;
/*for(int m=0; m<numOfWorkers; m++){
workers[m].interrupt();
}*/
// double work = 0, wait = 0;
Job job = new Job();
job.numOfCells = -1;
for(int m=0; m<numOfWorkers; m++){
// System.out.println("thread " + m + " waiting time = " + workers[m].time2 + " working time = " + workers[m].time3);
// work += workers[m].time3;
// wait += workers[m].time2;
//workers[m].interrupt();
jobs.add(job);
}
synchronized (consumers) {
//System.out.println("releasing threads");
//mainFinished = true;
for(int t=0; t<numOfWorkers; t++)
workers[t].shouldWork = true;
consumers.notifyAll();
// System.out.println("finishing job: main notified workers");
}
// System.out.println("waiting average: " + wait/24 + " working average: " + work/24);
}
/**
* Swaps between the 3 diagonals lineA, lineB and lineC such that each of them will be
* pointing towards the "next" diagonal. Also, deletes the "old" diagonal (the previously line
* pointed by lineA) so that it can be recycled as the new diagonal which needs to be filled.
*/
private void swapAndDelete(){
toDelete = lineA;
lineA = lineB;
lineB = lineC;
lineC = toDelete;
}
/**
* Sets the maximal score of the alignment
*/
private void setMaxScore(double d){
this.maxScore = d;
}
/**
* Gets the maximal score of the alignment
*/
public double getMaxScore(){
return this.maxScore;
}
/**
* 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
* @param c the character representing the mode of computation
*/
private void diagonalComputation(int numOfCellsInDiagonal, int sum, int j, char c) {
if(numOfCellsInDiagonal >= cells){ //we will use the amount of threads needed (not necessarily all of the workers)
concurrent(sum, j, numOfCellsInDiagonal, c);
}
else //for under 2 threads it is unnecessary to operate on concurrent mode
sequential(sum-j, j, numOfCellsInDiagonal, c);
}
/**
* Set the normal factor
*/
public void SetNormFactor(double factor) {
this.normFactor = factor;
}
/**
* 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
* @param c the state of computation (a, b or c) according to which we will fill lineC
*/
private void sequential(int rowB, int colB, int numOfCells, char c){
int k=0; //counter for the number of filled cells
int col = colB;
int sum = colB+rowB;
while(k < numOfCells){
//actually filling the table
helpFill(k, col, sum, c);
if(sum==1 || sum==2)
break;
k++;
col++;
}
}
/**
* The help function that will be called to work on a specific diagonal, if use of threads is needed (on concurrent mode)
* @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
* @param c the state of computation (a, b or c) according to which we will fill lineC
*/
private void concurrent(int sum, int j, int numOfCellsInDiagonal, char c){
// long startTime1 = System.currentTimeMillis();
// System.out.println("entering concurrent");
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");
}
}
}
// System.out.println("arrived to this line?");
//dividing the work for the threads
/*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, c);
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)*cellsToFill), c);
}
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){
e.printStackTrace();
}
*/
}
/**
* Fill in one cell of the C diagonal according to the given indexes
* @param indexLineC - location on diagonal C - the cell which needs to be filled
* @param j - the current index in str2
* @param sum the sum of j (index on str2) and the index on str1 (would have been i+j on a table)
* @param c the state of computation (a, b or c) according to which we will fill lineC
*/
private void helpFill(int indexLineC, int j, int sum, char c){
double diagScore = Double.NEGATIVE_INFINITY; //match or substitution
double leftScore = Double.NEGATIVE_INFINITY; //a letter was read from str2
double upScore = Double.NEGATIVE_INFINITY; //a letter was read from str1
/* special case used for the first time the diagonals are filled
* lineA is actually the second diagonal (2 cells), lineB is the third diagonal (3 cells)
* and they are filled according to the [0,0] cell (where necessary)
*/
if(sum==1){
lineA[0] = 0.0 + similarity(1,0); //up
lineA[1] = 0.0 + similarity(0,1); //left
return;
}
else if(sum==2){
diagScore = 0.0 + similarity(1,1);
upScore = lineA[1] + similarity(1,0);
leftScore = lineA[0] + similarity(0,1);
if(length1==1){
lineB[0] = max(diagScore, max(upScore, leftScore));
}
else if(length1>=2){
lineB[0] = lineA[0] + similarity(2,0); //up
lineB[1] = max(diagScore, max(upScore, leftScore));
lineB[2] = lineA[1] + similarity(0,2); //left
}
return;
}
//the rest of the cases (sum>=3), beginning with edge cases:
if(j==0){ //the first column - score can only be computed according to upScore
if(c == 'a'){
upScore = lineB[indexLineC] + similarity(sum-j, 0);
}
else if(c == 'b'){
upScore = lineB[indexLineC+1] + similarity(sum-j, 0);
}
}
else if(indexLineC == sum || indexLineC>=length1){ //the first row - score can only be computed according to leftScore
if(c == 'a'){
leftScore = lineB[indexLineC-1] + similarity(0, j);
}
else if(c == 'b'|| c == 'c'){
leftScore = lineB[indexLineC] + similarity(0, j);
}
}
else{ //j!=0 && indexLineC isn't on the first row => no problems, score is computed from all 3 directions
if(c == 'a'){
diagScore = lineA[indexLineC-1] + similarity(sum-j, j);
upScore = lineB[indexLineC] + similarity(sum-j, 0);
leftScore = lineB[indexLineC-1] + similarity(0, j);
}
else if(c == 'b'){
diagScore = lineA[indexLineC] + similarity(sum-j, j);
upScore = lineB[indexLineC+1] + similarity(sum-j, 0);
leftScore = lineB[indexLineC] + similarity(0, j);
}
else{ //c == 'c'
diagScore = lineA[indexLineC+1] + similarity(sum-j, j);
upScore = lineB[indexLineC+1] + similarity(sum-j, 0);
leftScore = lineB[indexLineC] + similarity(0, j);
}
}
lineC[indexLineC] = max(diagScore, max(upScore, leftScore)); //determines which option will give the highest score
//lineC[indexLineC] = 1.0;
}
/**
* 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 + start1]; //if i=0 than no letter was read from str1
final char c2 = j==0 ? alphabet.emptyLetter() : str2[j - 1 + start2]; //if j=0 than no letter was read from str2
//return scoringMatrix.score(c1,c2);
if(c1 == c2)
return 1;
else
return 0;
}
/**
* Returns the higher value: a or b
*/
private final double max(double a,double b){
return a > b ? a : b;
}
/**
* 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) {
System.out.println(new Date());
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]); //number of workers
int jobSize = Integer.parseInt(args[3]); //amount of cells for each thread to fill
DiagonalSequenceAlignmentNoMatrix alignment = new DiagonalSequenceAlignmentNoMatrix(str1, str2, RnaAlphabet.getInstance(),
new IdentityScoringMatrix(RnaAlphabet.getInstance()), n, jobSize);
alignment.buildMatrix();
//System.out.println(alignment.getAlignmentScore());
//alignment.printAlignments();
// alignment.printDPMatrix();
// alignment.printDPMatrixInLatexMatrix();
System.out.println("The score of the alignment: " + alignment.getMaxScore());
System.out.println(new Date());
}//main
/*
* 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 state
*/
private volatile char c;
/**
* 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
*/
volatile boolean shouldWork = false;
private long time2, time3;
/**
* 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
* @param c the state of computation (a, b or c) according to which we will fill lineC
*/
/*public void setIndex(int rowB, int colB, int numOfCells, char c){
this.rowB = rowB;
this.colB = colB;
this.numOfCells = numOfCells;
this.c = c;
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;
// System.out.println("worker commiting job: from [" + rowB + "][" + (colB) + "], filling up " + count + " cells, on diagonal of sum " + (rowB+colB));
while(k < count){
//actually filling the table
if((colB+rowB < length1)){ //the first thread on the matrix, and the diagonal is on part 1
helpFill(colB+k, colB+k, colB+rowB, c);
}
else{
helpFill(length1-rowB+k, colB+k, colB+rowB, c);
}
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");
}
}
/*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
if (myCounter % 30000 == 0)
System.out.println("counter is: " + myCounter + " worker " + id + " starting work. doing job: row-index = " + rowB + " column-index = " + colB + " num of cells = " + numOfCells);
myCounter++;
} catch (InterruptedException e) {
return; //return - in case the worker thread was faster than the main thread and the simulation is over
}
}*/
/*
Job myJob;
try {
myJob = jobs.take(); //get a new job
// 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;
// System.out.println("worker commiting job: from [" + rowB + "][" + (colB) + "], filling up " + count + " cells, on diagonal of sum " + (rowB+colB));
while(k < count){
//actually filling the table
if((colB+rowB < str1.length)){ //the first thread on the matrix, and the diagonal is on part 1
helpFill(colB+k, colB+k, colB+rowB, c);
}
else{
helpFill(str1.length-rowB+k, colB+k, colB+rowB, c);
}
k++;
}
// }
int num = jobsCounter.incrementAndGet(); //indicates a job was done
if(num == myJob.howMany){
synchronized(lock){
if (myCounter % 30000 == 0) //print every 30,000 diaonals
System.out.println("counter is: " + myCounter);
myCounter++;
lock.notify();
}
}
} catch (InterruptedException e1) {
//System.out.println("couldn't take a new job from queue");
return;
}
*/
/*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=0; //counter for the number of filled cells
while(k < numOfCells){
//actually filling the table
if((colB+rowB < str1.length)){ //the first thread on the matrix, and the diagonal is on part 1
helpFill(colB+k, colB+k, colB+rowB, c);
}
else{
helpFill(str1.length-rowB+k, colB+k, colB+rowB, c);
}
k++;
}
shouldWork = false; //finished working
}*/
//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){
e.printStackTrace();
return;
}
catch (BrokenBarrierException e){
// TODO Auto-generated catch block
e.printStackTrace();
}*/
}
}
/**
* Fill in one cell of the C diagonal according to the given indexes
* @param indexLineC - location on diagonal C - the cell which needs to be filled
* @param j - the current index in str2
* @param sum the sum of j (index on str2) and the index on str1 (would have been i+j on a table)
* @param c the state of computation (a, b or c) according to which we will fill lineC
*/
private void helpFill(int indexLineC, int j, int sum, char c){
double diagScore = Double.NEGATIVE_INFINITY; //match or substitution
double leftScore = Double.NEGATIVE_INFINITY; //a letter was read from str2
double upScore = Double.NEGATIVE_INFINITY; //a letter was read from str1
/* special case used for the first time the diagonals are filled
* lineA is actually the second diagonal (2 cells), lineB is the third diagonal (3 cells)
* and they are filled according to the [0,0] cell (where necessary)
*/
if(sum==1){
lineA[0] = 0.0 + similarity(1,0); //up
lineA[1] = 0.0 + similarity(0,1); //left
return;
}
else if(sum==2){
diagScore = 0.0 + similarity(1,1);
upScore = lineA[1] + similarity(1,0);
leftScore = lineA[0] + similarity(0,1);
lineB[0] = lineA[0] + similarity(2,0); //up
lineB[1] = max(diagScore, max(upScore, leftScore));
lineB[2] = lineA[1] + similarity(0,2); //left
return;
}
//the rest of the cases (sum>=3), beginning with edge cases:
if(j==0){ //the first column - score can only be computed according to upScore
if(c == 'a'){
upScore = lineB[indexLineC] + similarity(sum-j, 0);
}
else if(c == 'b'){
upScore = lineB[indexLineC+1] + similarity(sum-j, 0);
}
}
else if(indexLineC == sum || indexLineC>=(length1)){ //the first row - score can only be computed according to leftScore
if(c == 'a'){
leftScore = lineB[indexLineC-1] + similarity(0, j);
}
else if(c == 'b'|| c == 'c'){
if(indexLineC==48034)
System.out.println("b1 = " + start1 + " e1= " + e1 + " length1= " + length1 + " j=" + j + " sum= " + sum);
leftScore = lineB[indexLineC] + similarity(0, j);
}
}
else{ //j!=0 && indexLineC isn't on the first row => no problems, score is computed from all 3 directions
if(c == 'a'){
diagScore = lineA[indexLineC-1] + similarity(sum-j, j);
upScore = lineB[indexLineC] + similarity(sum-j, 0);
leftScore = lineB[indexLineC-1] + similarity(0, j);
}
else if(c == 'b'){
diagScore = lineA[indexLineC] + similarity(sum-j, j);
/*if(indexLineC==48033)
System.out.println("b1 = " + start1 + " e1= " + e1 + " length1= " + length1 + " j=" + j + " sum= " + sum);*/
upScore = lineB[indexLineC+1] + similarity(sum-j, 0);
leftScore = lineB[indexLineC] + similarity(0, j);
}
else{ //c == 'c'
diagScore = lineA[indexLineC+1] + similarity(sum-j, j);
upScore = lineB[indexLineC+1] + similarity(sum-j, 0);
leftScore = lineB[indexLineC] + similarity(0, j);
}
}
lineC[indexLineC] = max(diagScore, max(upScore, leftScore)); //determines which option will give the highest score
}
/**
* Returns the higher value: a or b
*/
private final double max(double a,double b){
return a > b ? a : b;
}
} //end of class Worker
/**
* 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
} //end of class DiagonalSequenceAlignmentNoMatrix