import edu.rice.hj.api.HjCallable; import edu.rice.hj.api.HjFuture; import edu.rice.hj.api.HjMetrics; import edu.rice.hj.runtime.config.HjSystemProperty; import edu.rice.hj.runtime.metrics.AbstractMetricsManager; import edu.rice.hj.runtime.util.Pair; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import static edu.rice.hj.Module1.*; /** * Pascal's Triangle --- Computes (n C k) using futures *

* The purpose of this example is to illustrate effects on memoization with abstract metrics while using futures. * C(n, k) = C(n - 1, k - 1) + C(n - 1, k) * * @author Shams Imam (shams@rice.edu) * @author Vivek Sarkar (vsarkar@rice.edu) */ public class PascalsTriangleMemoized { public static void main(final String[] args) { final int n = args.length > 0 ? Integer.parseInt(args[0]) : 8; final int k = args.length > 1 ? Integer.parseInt(args[1]) : (n - 3); System.out.println(" N = " + n); System.out.println(" K = " + k); kernel("Recursive Version (Sequential)", n, k, () -> chooseRecursiveSeq(n, k)); kernel("Recursive Version (Parallel)", n, k, () -> chooseRecursivePar(n, k)); kernel("Memoized Version (Sequential)", n, k, () -> chooseMemoizedSeq(n, k)); kernel("Memoized Version (Parallel)", n, k, () -> chooseMemoizedPar(n, k)); } private static void kernel(final String mode, final int N, final int K, final HjCallable hjProcedure) { System.out.println("==============================================="); System.out.println("\n Running: " + mode); System.setProperty(HjSystemProperty.abstractMetrics.propertyKey(), "true"); initializeHabanero(); finish(() -> { try { final int res = hjProcedure.call(); System.out.println(N + " choose " + K + " = " + res); } catch (final Exception e) { e.printStackTrace(); } }); finalizeHabanero(); final HjMetrics actualMetrics = abstractMetrics(); AbstractMetricsManager.dumpStatistics(actualMetrics); System.out.println("==============================================="); } private static int computeSum(final int left, final int right) { doWork(1); return left + right; } private static int computeBaseCaseResult() { doWork(1); return 1; } private static int chooseRecursiveSeq(final int N, final int K) { if (N == 0 || K == 0 || N == K) { return computeBaseCaseResult(); } final int left = chooseRecursiveSeq(N - 1, K - 1); final int right = chooseRecursiveSeq(N - 1, K); return computeSum(left, right); } private static int chooseRecursivePar(final int N, final int K) { if (N == 0 || K == 0 || N == K) { return computeBaseCaseResult(); } // TODO Introduce futures to parallelize the computation of left and right final int left = chooseRecursivePar(N - 1, K - 1); final int right = chooseRecursivePar(N - 1, K); // TODO Use future.get() to retrieve the results of the futures final Integer leftValue = left; final Integer rightValue = right; return computeSum(leftValue, rightValue); } private static final Map, Integer> chooseMemoizedSeqCache = new ConcurrentHashMap<>(); private static int chooseMemoizedSeq(final int N, final int K) { final Pair key = Pair.factory(N, K); if (chooseMemoizedSeqCache.containsKey(key)) { final Integer result = chooseMemoizedSeqCache.get(key); return result; } if (N == 0 || K == 0 || N == K) { final Integer result = computeBaseCaseResult(); chooseMemoizedSeqCache.put(key, result); return result; } final int left = chooseMemoizedSeq(N - 1, K - 1); final int right = chooseMemoizedSeq(N - 1, K); final int result = computeSum(left, right); chooseMemoizedSeqCache.put(key, result); return result; } private static final Map, HjFuture> chooseMemoizedParCache = new ConcurrentHashMap<>(); private static int chooseMemoizedPar(final int N, final int K) { final Pair key = Pair.factory(N, K); if (chooseMemoizedParCache.containsKey(key)) { final Integer result = 0; // TODO chooseMemoizedParCache.get(key); return result; } if (N == 0 || K == 0 || N == K) { // TODO Introduce futures to parallelize the computation of the base case final Integer result = computeBaseCaseResult(); // TODO chooseMemoizedParCache.put(key, result); return result; } // TODO Introduce futures to parallelize the computation of left and right final int left = chooseMemoizedPar(N - 1, K - 1); final int right = chooseMemoizedPar(N - 1, K); // TODO Use future.get() to retrieve the results of the futures final int result = computeSum(left, right); // TODO chooseMemoizedParCache.put(key, result); return result; } }