import java.util.Arrays; // for testing purposes only /* This class has a method that permutes the elements of a given array ** in accord with a given permutation. It uses threads so that the work ** is done (potentially, at least) in parallel. ** ** Author: R. McCloskey ** Date: November 27, 2020 */ public class ArrayPermuterParallel { // class constant // -------------- private static final int LENGTH_THRESHOLD = 2; // instance variable // ----------------- private int[] a; // Array whose elements were "permuted" private int[] result; // Permuted version of a[] private int[] perm; // The permutation that was applied to a[], // resulting in result[perm[k]] = a[k] for all k. // Note: The reason for the above being instance variables of this class // is so that (the many) instances of the nested class can access them // without each one needing its own instance variables referring to them. /* Returns a new array that is the result of applying the given ** permutation to the given array. Specifically, for each k, a[k] ** is placed into location perm[k] in the new array. The computation is ** carried out using a thread based upon an instance of the nested class. */ public int[] permutationOf(int[] ary, int[] perm) { this.a = ary; this.perm = perm; result = new int[a.length]; PermuteInParallel permuter = new PermuteInParallel(0, ary.length); Thread t = new Thread(permuter); t.start(); join(t); return result; } /* Permutes the elements of ary[] in accord with the given permutation, ** so that ary[perm[k]] = ARY[k], where ARY[] refers to the original state ** of ary[]. */ public void permuteAry(int[] ary, int[] perm) { int[] permutedAry = permutationOf(ary, perm); ArrayCopierParallel copier = new ArrayCopierParallel(); copier.copy(permutedAry, ary); } /* An instance of this nested class is intended to be used in constructing ** a thread that places the elements in a segment of a[], where the ** boundaries of that segment are provided as parameters to the constructor, ** into the elements of result[] in accord with perm[]. */ private class PermuteInParallel implements Runnable { // instance variables // ------------------ int low, high; // Calling permute() on this object results in the // elements of a[low..high) being placed into the // correct locations within result[] (namely, // a[k] is placed into result[perm[k]]). // constructor // ----------- /* Identifies the array segment whose elements are to be permuted by ** this object. ** pre: 0 <= floor <= ceiling <= a.length */ public PermuteInParallel(int floor, int ceiling) { low = floor; high = ceiling; } // run() method // ------------ public void run() { permute(); } // mutator // ------- /* Places the elements in a[low..high) and into the correct locations ** in result[]. */ private void permute() { //System.out.printf("Permuting of elements in range [%d..%d)\n", // low, high); if (high - low <= LENGTH_THRESHOLD) { // short segment, so permute permuteSeq(); // its elements sequentially } else { // split segment into halves and permute them in parallel int mid = (low + high) / 2; PermuteInParallel leftPIP = new PermuteInParallel(low, mid); Thread leftThread = new Thread(leftPIP); leftThread.start(); PermuteInParallel rightPIP = new PermuteInParallel(mid, high); rightPIP.permute(); // The next three lines are an alternative to the line above; // they create a new thread for the purpose of permuting the // elements in the "right" half of the array segment rather than // letting "this" thread do that job. //Thread rightThread = new Thread(rightPIP); //rightThread.start(); //join(rightThread); join(leftThread); //System.out.printf("Done permuting elements in range [%d..%d)\n", // low, high); } } /* Permute the the elements in a[low..high) sequentially, placing them ** into the correct locations in result[]. ** pre: 0 <= low <= high <= a.length */ private void permuteSeq() { for (int i = low; i != high; i++) { result[perm[i]] = a[i]; } } } // end of private class /* Applies join() to the given thread, catching InterruptedException ** if it is thrown. */ private void join(Thread t) { try { t.join(); } catch (InterruptedException e) { e.printStackTrace(System.out); } } // main() method (for testing purposes) // ------------------------------------ public static void main(String[] args) { int[] ary = new int[] { 5, 7, 3, 0, 2, 12, 8, 10, 6, 9, 1, 4, 11 }; int[] ranks = ary; System.out.printf("Array: %s\n", Arrays.toString(ary)); ArrayPermuterParallel app = new ArrayPermuterParallel(); System.out.println("Permuting ..."); int[] r = app.permutationOf(ary, ranks); System.out.printf("Result is %s\n", Arrays.toString(r)); } }