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.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
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;
public class Check3 {
private char[] str1, str2;
private int length1, length2;
private double[] lineA, lineB, lineC;
private ScoringMatrix scoringMatrix;
private AlphabetUtils alphabet;
//private bgu.bio.adt.queue.BlockingQueue<Job> jobs;
private ConcurrentLinkedQueue<Job> jobs;
private int cells;
private AtomicInteger jobsCounter; //???
private Object lock = new Object();
private boolean running = true;
private int numOfWorkers;
private Worker[] workers;
private Job[] jobsPool;
private double time1,/* time4, time3,*/ time5;
public Check3(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;
// System.out.println(capacity);
jobs = new ConcurrentLinkedQueue<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();
}
jobsCounter = new AtomicInteger(0);
}
private void buildMatrix(){
for(int i=0; i<length1+1; i++){
lineA[i] = Math.ceil(Math.random()*100);
lineB[i] = Math.ceil(Math.random()*100);
}
for(int k=0; k<numOfWorkers; k++){
workers[k].start();
}
System.out.println(new Date());
for(int i=0; i<30000; i++){
concurrent(length1+4, 4, length1+1, 'c');
/* if(i%500 == 0)
System.out.println("time spent so far on 'concurrent' 1st part: " + time1);*/
// System.out.println(i);
}
System.out.println(new Date());
System.out.println("total time spent on concurrent (without waiting) " + time1);
// System.out.println("total time spent on concurrent - first assigning " + time3);
// System.out.println("total time spent on concurrent - second assigning " + time4);
System.out.println("total time spent on concurrent - pushing to queue " + time5);
// System.out.println("total time spent on helpfill " + time4);
running = false;
double work = 0, wait = 0;
Job j = new Job();
j.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(j);
}
System.out.println("waiting average: " + wait/24 + " working average: " + work/24);
/*
for(int i=0; i<length1+1; i++){
System.out.println(lineC[i] + " ");
}*/
}
private void concurrent(int sum, int j, int numOfCellsInDiagonal, char c){
long startTime1 = System.currentTimeMillis();
jobsCounter.set(0);
int i = 1;
int columnIndex = j;
int res = numOfCellsInDiagonal/cells;
int iterations = numOfCellsInDiagonal%cells==0 ? res : res+1;
// System.out.println("main dividing a new diagonal to jobs of 100 cells");
// synchronized(lock2){
long /*startTime3, startTime4, endTime3, endTime4,*/ startTime5, endTime5;
Job job;
while(i<=iterations){
//startTime3 = System.currentTimeMillis();
job = jobsPool[i-1];
job.beginningColumn = columnIndex;
job.beginningRow = sum - columnIndex;
//endTime3 = System.currentTimeMillis();
//time3 += (double)(endTime3 - startTime3)/60000;
// startTime4 = System.currentTimeMillis();
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;
// endTime4 = System.currentTimeMillis();
// time4 += (double)(endTime3 - startTime3)/60000;
startTime5 = System.currentTimeMillis();
jobs.add(job);
endTime5 = System.currentTimeMillis();
time5 += (double)(endTime5 - startTime5)/60000;
columnIndex += cells;
i++;
}
long endTime1 = System.currentTimeMillis();
time1 += (double)(endTime1 - startTime1)/60000;
synchronized(lock){
while(jobsCounter.get()!=iterations){
try {
lock.wait();
} catch (InterruptedException e) {
System.out.println("this message should never be printed since no one interrupts main");
}
}
}
}
private final double similarity(int i, int j) {
final char c1 = i==0 ? alphabet.emptyLetter() : str1[i - 1]; //if i=0 than no letter was read from str1
final char c2 = j==0 ? alphabet.emptyLetter() : str2[j - 1]; //if j=0 than no letter was read from str2
return scoringMatrix.score(c1,c2);
}
public int getLength(int i){
if(i==1)
return length1;
else
return length2;
}
/**
* Main..............................................................................................
* @param args
*/
public static void main (String[] args){
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
Check3 alignment = new Check3(str1, str2, RnaAlphabet.getInstance(),
new IdentityScoringMatrix(RnaAlphabet.getInstance()), n, jobSize);
System.out.println("shorter string length: " + alignment.getLength(1));
System.out.println("longer string length: " + alignment.getLength(2));
System.out.println("amount of diagonals = " + (alignment.getLength(1)+alignment.getLength(2)));
alignment.buildMatrix();
//System.out.println(alignment.getAlignmentScore());
//alignment.printAlignments();
// alignment.printDPMatrix();
// alignment.printDPMatrixInLatexMatrix();
// System.out.println("The score of the alignment: " + alignment.getMaxScore());
}
private class Worker extends Thread{
/**
* 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 double time2, time3;
/**
* Constructor
* @param id the unique ID number of the worker
*/
public Worker(int id){
this.id = id;
}
/**
* 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
Job myJob = null;
// try {
long startTime2 = System.currentTimeMillis();
while(myJob == null)
myJob = jobs.poll(); //get a new job
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 < 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++;
}
// }
long endJob = System.currentTimeMillis();
time3 += (double)(endJob - endTime2)/60000;
int num = jobsCounter.incrementAndGet(); //indicates a job was done
if(num == myJob.howMany){
synchronized(lock){
lock.notify();
}
}
/* } catch (InterruptedException e1) {
return;
}*/
}
}
/**
* 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){
//long startTime4 = System.currentTimeMillis();
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>=str1.length){ //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
//long endTime4 = System.currentTimeMillis();
//time4 += (endTime4 - startTime4)/60000;
// System.out.println("indexlineC = " + indexLineC);
// lineC[indexLineC] = lineB[indexLineC];
}
/**
* Returns the higher value: a or b
*/
private final double max(double a,double b){
return a > b ? a : b;
}
private final double similarity(int i, int j) {
final char c1 = i==0 ? alphabet.emptyLetter() : str1[i - 1]; //if i=0 than no letter was read from str1
final char c2 = j==0 ? alphabet.emptyLetter() : str2[j - 1]; //if j=0 than no letter was read from str2
return scoringMatrix.score(c1,c2);
}
} //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
}