Package bgu.bio.algorithms.alignment

Source Code of bgu.bio.algorithms.alignment.DiagonalSequenceAlignmentNoMatrix$Job

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
TOP

Related Classes of bgu.bio.algorithms.alignment.DiagonalSequenceAlignmentNoMatrix$Job

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.