import DPJRuntime.*;
import java.util.Random;
/**
* Sample sort program adapted from a demo in
* <A href="http://supertech.lcs.mit.edu/cilk/"> Cilk</A> and
* <A href="http://www.cs.utexas.edu/users/hood/"> Hood</A>.
*
* There are two versions of MergeSort here: One that splits the array
* into four pieces at each recursive step, and one that splits the
* array into eight pieces. This abstract class represents the common
* elements of both versions.
*
**/
public abstract class MergeSort extends Harness {
region Input, Result;
protected ArrayInt<Input> input;
protected ArrayInt<Result> result;
public MergeSort(String name, String[] args) {
super(name, args);
}
@Override
public void initialize() {
input = new ArrayInt<Input>(size);
result = new ArrayInt<Result>(size);
for (int i = 0; i < input.length; ++i) {
input[i] = i;
}
Utils.permuteInt(input);
}
@Override
public void runWork() {
sort(new ArraySliceInt<Input>(input),
new ArraySliceInt<Result>(result));
}
@Override
public void runTest() {
checkSorted(input,input.length);
}
public abstract <region R1,R2 | R1:* # R2:*>
void sort(ArraySliceInt<R1> A, ArraySliceInt<R2> B);
protected static <region P>void checkSorted
(ArrayInt<P> array, int n)
{
for (int i = 0; i < n - 1; i++) {
if (array[i] > array[i+1]) {
throw new Error("Unsorted at " + i + ": " +
array[i] + " / " + array[i+1]);
}
}
}
protected static <region R1,R2,R3 | R1:* # R3:*, R2:* # R3:*>void
merge(ArraySliceInt<R1> A, ArraySliceInt<R2> B,
ArraySliceInt<R3> out)
reads R1 : *, R2 : * writes R3 : *
{
if (A.length <= MERGE_SIZE) {
sequentialMerge(A, B, out);
}
else {
int aHalf = A.length >>> 1; /*l33t shifting h4x!!!*/
int bSplit = findSplit(A.get(aHalf), B);
final PartitionInt<R1> A_split =
new PartitionInt<R1>(A, aHalf);
final PartitionInt<R2> B_split =
new PartitionInt<R2>(B, bSplit);
final PartitionInt<R3> out_split =
new PartitionInt<R3>(out, aHalf + bSplit);
cobegin {
merge(A_split.get(0),
B_split.get(0),
out_split.get(0));
merge(A_split.get(1),
B_split.get(1),
out_split.get(1));
}
}
}
/** A standard sequential merge **/
protected static <region R1,R2,R3 | R1#R3, R2#R3>
void sequentialMerge(ArraySliceInt<R1> A,
ArraySliceInt<R2> B,
ArraySliceInt<R3> out)
reads R1 : *, R2 : * writes R3 : *
{
int a = 0;
int aFence = A.length;
int b = 0;
int bFence = B.length;
int k = 0;
while (a < aFence && b < bFence) {
if (A.get(a) < B.get(b))
out.put(k++, A.get(a++));
else
out.put(k++, B.get(b++));
}
while (a < aFence) out.put(k++, A.get(a++));
while (b < bFence) out.put(k++, B.get(b++));
}
protected static <region P>int
findSplit(int value, ArraySliceInt<P> B)
reads P {
int low = 0;
int high = B.length;
while (low < high) {
int middle = low + ((high - low) >>> 1);
if (value <= B.get(middle))
high = middle;
else
low = middle + 1;
}
return high;
}
/* Threshold values */
// Cutoff for when to do sequential versus parallel merges
public static final int MERGE_SIZE = 2048;
// Cutoff for when to do sequential quicksort versus parallel mergesort
public static final int QUICK_SIZE = 2048;
// Cutoff for when to use insertion-sort instead of quicksort
public static final int INSERTION_SIZE = 2000;
/** A standard sequential quicksort **/
protected static <region R>void
quickSort(ArraySliceInt<R> slice) writes R : * {
int lo = 0;
int hi = slice.length-1;
// If under threshold, use insertion sort
if (hi-lo+1l <= INSERTION_SIZE) {
for (int i = lo + 1; i <= hi; i++) {
int t = slice.get(i);
int j = i - 1;
while (j >= lo && slice.get(j) > t) {
slice.put(j+1, slice.get(j));
--j;
}
slice.put(j+1, t);
}
return;
}
// Use median-of-three(lo, mid, hi) to pick a partition.
// Also swap them into relative order while we are at it.
int mid = (lo + hi) >>> 1;
if (slice.get(lo) > slice.get(mid)) {
int t = slice.get(lo); slice.put(lo, slice.get(mid));
slice.put(lo, slice.get(mid)); slice.put(mid, t);
}
if (slice.get(mid) > slice.get(hi)) {
int t = slice.get(mid); slice.put(mid, slice.get(hi));
slice.put(hi, t);
if (slice.get(lo) > slice.get(mid)) {
t = slice.get(lo); slice.put(lo, slice.get(mid));
slice.put(mid, t);
}
}
int left = lo+1; // start one past lo since already handled lo
int right = hi-1; // similarly
int partition = slice.get(mid);
for (;;) {
while (slice.get(right) > partition)
--right;
while (left < right && slice.get(left) <= partition)
++left;
if (left < right) {
int t = slice.get(left);
slice.put(left, slice.get(right));
slice.put(right, t);
--right;
}
else break;
}
quickSort(slice.subslice(lo, left+1));
quickSort(slice.subslice(left+1, hi-left));
}
}