package edu.rice.hj.example.comp322; import edu.rice.hj.api.*; import edu.rice.hj.runtime.config.HjConfiguration; import java.io.BufferedReader; import java.io.FileReader; import java.util.Arrays; import static edu.rice.hj.Module1.*; /** * Parallel Smith-Waterman algorithm adapted for COMP 322 homework. * * @author Kyle Kurihara (khk1@rice.edu) */ public class SmithWatermanParallel { // Scoring matrix /* _ A C G T ---------------- _ |-8 -2 -2 -2 -2 A |-4 5 2 2 2 C |-4 2 5 2 2 G |-4 2 2 5 2 T |-4 2 2 2 5 */ private final static int[][] M = new int[][]{{-8, -2, -2, -2, -2}, {-4, 5, 2, 2, 2}, {-4, 2, 5, 2, 2}, {-4, 2, 2, 5, 2}, {-4, 2, 2, 2, 5}}; private static HjRuntime HJ_RUNTIME; /** * Helper for division. * * @param n The numerator. * @param d The denominator. * @return The result of the division. */ static int ceilDiv(final int n, final int d) { assert (n >= 0 && d > 0); return (n + d - 1) / d; } /** * Helper method for chunking the regions that will be done asynchronously in the compute method. * * @param region The region that requires chunking. * @param numChunks The number of chunks to split the region into. * @param chunkNum The desired chunk number. * @return A region that is the chunkNum-th chunk. */ static HjRegion getChunk(final HjRegion region, final int numChunks, final int chunkNum) { // Assume that region is a 1D region final int regionLow = region.lowerLimit(0); final int regionHigh = region.upperLimit(0); if (regionLow > regionHigh) { // Return an empty region return newRectangularRegion1D(0, -1); } assert (numChunks > 0); // numChunks must be > 0 assert (0 <= chunkNum && chunkNum < numChunks); final int chunkSize = ceilDiv(regionHigh - regionLow + 1, numChunks); final int myLow = regionLow + chunkNum * chunkSize; final int myHigh = Math.min(regionHigh, regionLow + (chunkNum + 1) * chunkSize - 1); return newRectangularRegion1D(myLow, myHigh); } /** * Compute the solution matrix and return the time it took to do the calculation. * * @param X The first string to be compared. * @param Y The second string to be compared. * @param xLength The length of the X string. * @param yLength The length of the Y string. * @param iter The current iteration. * @return The total time it took to run the computation as a long. */ public static long compute(final String X, final String Y, final int xLength, final int yLength, final int iter) throws SuspendableException { // Allocate the matrix for alignment, dimension+1 for initializations final int[][] S = new int[xLength + 1][yLength + 1]; // Initialize rows for (int ii = 1; ii < xLength + 1; ii++) { S[ii][0] = M[1][0] * ii; } // Initialize columns for (int jj = 1; jj < yLength + 1; jj++) { S[0][jj] = M[0][1] * jj; } // Initialize diagonal S[0][0] = 0; // Start of computation long time = -System.nanoTime(); final int numThreads = HJ_RUNTIME.numWorkerThreads(); // Create an async for every worker thread forallPhased(0, numThreads - 1, new HjSuspendingProcedure() { @Override public void apply(final Integer index) throws SuspendableException { for (int x = 2; x <= (xLength + yLength); x++) { final HjRegion myChunk = getChunk(newRectangularRegion1D(1, x - 1), numThreads, index); for (final HjPoint point : myChunk.toSeqIterable()) { int i = point.get(0); int j = x - i; if (i <= xLength && j <= yLength) { char xChar = X.charAt(i - 1); char yChar = Y.charAt(j - 1); int diagScore = S[i - 1][j - 1] + M[charMap(xChar)][charMap(yChar)]; int topColScore = S[i - 1][j] + M[charMap(xChar)][0]; int leftRowScore = S[i][j - 1] + M[0][charMap(yChar)]; S[i][j] = Math.max(diagScore, Math.max(leftRowScore, topColScore)); } } next(); } } } ); printMatrix(S); time += System.nanoTime(); time = time / 1000000; // convert from nanoseconds to milliseconds System.out.println(" The score = " + S[xLength][yLength] + " in iteration " + (iter + 1)); System.out.println(" The execution time = " + time + " milliseconds in iteration " + (iter + 1)); return time; } /** * Helper method for getting the index of character in scoring matrix. * * @param inputChar The character to search for. * @return The index of the requested character in the matrix. */ public static int charMap(final char inputChar) { int toBeReturned = -1; switch (inputChar) { case '_': toBeReturned = 0; break; case 'A': case 'a': toBeReturned = 1; break; case 'C': case 'c': toBeReturned = 2; break; case 'G': case 'g': toBeReturned = 3; break; case 'T': case 't': toBeReturned = 4; break; } if (toBeReturned == -1) { System.out.println("Error:Could not map character"); } return toBeReturned; } /** * Helper method for printing out a two dimensional int array, can be useful for debugging. * * @param matrix The desired int matrix to be printed. */ public static void printMatrix(final int[][] matrix) { for (int i = 0; i < matrix.length; i++) { for (int j = 0; j < matrix[0].length; j++) { System.out.printf(" %3d", matrix[i][j]); } System.out.println(); } System.out.println("--------------------------------"); } /** * Read the sequence from a given text file. * * @param fileName The file name to read text from. * @return A string containing the sequence from the file. * @throws java.io.IOException if any. */ public static String initString(final String fileName) throws java.io.IOException { final BufferedReader r = new BufferedReader(new FileReader(fileName)); final StringBuilder text = new StringBuilder(); String line; while ((line = r.readLine()) != null) { text.append(line); } return text.toString(); } /** *

main.

* * @param args an array of {@link String} objects. */ public static void main(final String[] args) { HjConfiguration.initializeRuntime(); HJ_RUNTIME = HjConfiguration.runtime(); final String filename1; final String filename2; if (args.length == 2) { filename1 = args[0]; filename2 = args[1]; } else { System.out.println("Usage: java SmithWatermanParallel fileName1 fileName2"); return; } try { final String X = initString(filename1); final String Y = initString(filename2); System.out.println("Size of input string 1 is " + X.length()); System.out.println("Size of input string 2 is " + Y.length()); final int xLength = X.length(); final int yLength = Y.length(); final int numIter = 5; final long[] times = new long[numIter]; long execTime; long totalTime = 0; for (int iter = 0; iter < numIter; iter++) { execTime = compute(X, Y, xLength, yLength, iter); totalTime += execTime; times[iter] = execTime; } Arrays.sort(times); System.out.println("Avg time of computation is " + totalTime / numIter); System.out.println("Min time of computation is " + times[0] + " milliseconds "); } catch (Throwable e) { System.err.println(e); } } }