diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..7e05835 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,20 @@ +name: Test sorts +on: [push, pull_request] + +jobs: + test_java: + runs-on: ubuntu-latest + defaults: + run: + working-directory: "Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft" + steps: + - uses: actions/checkout@v2 + - name: Setup Java + uses: actions/setup-java@v2.1.0 + with: + java-version: 8 + distribution: zulu + - name: Build Tester + run: javac -d bin src/holygrail/*.java + - name: Run Tester + run: java -cp bin holygrail.Tester diff --git a/Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft/.project b/Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft/.project index 4510e5a..eda8f51 100644 --- a/Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft/.project +++ b/Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft/.project @@ -14,4 +14,15 @@ org.eclipse.jdt.core.javanature + + + 1635186492658 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + diff --git a/Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft/src/holygrail/HolyGrailSort.java b/Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft/src/holygrail/HolyGrailSort.java index 8439eb6..3a84633 100644 --- a/Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft/src/holygrail/HolyGrailSort.java +++ b/Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft/src/holygrail/HolyGrailSort.java @@ -4,20 +4,20 @@ /* * MIT License - * + * * Copyright (c) 2013 Andrey Astrelin * Copyright (c) 2020-2021 The Holy Grail Sort Project - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -85,7 +85,7 @@ enum Subarray { private int currBlockLen; private Subarray currBlockOrigin; - + public HolyGrailSort(Comparator cmp) { this.cmp = cmp; } @@ -95,27 +95,27 @@ private static void swap(T[] array, int a, int b) { array[a] = array[b]; array[b] = temp; } - + private static void swapBlocksForwards(T[] array, int a, int b, int blockLen) { for(int i = 0; i < blockLen; i++) { swap(array, a + i, b + i); } } - + private static void swapBlocksBackwards(T[] array, int a, int b, int blockLen) { for(int i = blockLen - 1; i >= 0; i--) { swap(array, a + i, b + i); } } - + // Shift elements [start + 1, start + length + 1) to the left by 1 // and paste copied element at start + length - 1. private static void insertForwards(T[] array, int start, int length) { T item = array[start]; System.arraycopy(array, start + 1, array, start, length); - array[start + length] = item; + array[start + length] = item; } - + // Shift elements [start, start + length) to the right by 1 // and paste copied element at start. private static void insertBackwards(T[] array, int start, int length) { @@ -123,10 +123,10 @@ private static void insertBackwards(T[] array, int start, int length) { System.arraycopy(array, start, array, start + 1, length); array[start] = item; } - + private static void rotate(T[] array, int start, int leftLen, int rightLen) { int minLen = leftLen <= rightLen ? leftLen : rightLen; - + while(minLen > 1) { if(leftLen <= rightLen) { do { @@ -134,7 +134,7 @@ private static void rotate(T[] array, int start, int leftLen, int rightLen) start += leftLen; rightLen -= leftLen; } while(leftLen <= rightLen); - + minLen = rightLen; } else { @@ -142,7 +142,7 @@ private static void rotate(T[] array, int start, int leftLen, int rightLen) swapBlocksBackwards(array, start + leftLen - rightLen, start + leftLen, rightLen); leftLen -= rightLen; } while(leftLen > rightLen); - + minLen = leftLen; } } @@ -156,18 +156,18 @@ private static void rotate(T[] array, int start, int leftLen, int rightLen) } } } - + // unguarded insertion sort // implementation thanks to Control and Scandum! private static void insertSort(T[] array, int start, int length, Comparator cmp) { for(int item = 1; item < length; item++) { T temp = array[start + item]; int index = start + item; - + if(cmp.compare(array[index - 1], temp) <= 0) { continue; } - + if(cmp.compare(array[start], temp) > 0) { insertBackwards(array, start, item); continue; @@ -177,16 +177,16 @@ private static void insertSort(T[] array, int start, int length, Comparator< array[index] = array[index - 1]; index--; } while(cmp.compare(array[index - 1], temp) > 0); - + array[index] = temp; } } - + private static void shellPass(T[] array, int start, int length, int gap, Comparator cmp) { for(int item = gap; item < length; item++) { T temp = array[start + item]; int index = start + item; - + if(cmp.compare(array[index - gap], temp) < 0) { continue; } @@ -199,7 +199,7 @@ private static void shellPass(T[] array, int start, int length, int gap, Com array[index] = temp; } } - + // implementation of Shellsort using a modified version of // Sedgewick's '82 gap sequence: 1, *3*, 8, 23, 77, 281, ... // [4^k + 3*2^(k-1) + 1] with an added penultimate gap of 3 @@ -209,7 +209,7 @@ private static void shellSort(T[] array, int start, int length, Comparator 0) { int gap = (4 << (2*k)) + (3 << k) + 1; shellPass(array, start, length, gap, cmp); @@ -218,7 +218,7 @@ private static void shellSort(T[] array, int start, int length, Comparator int binarySearchLeft(T[] array, int start, int length, T target, Comparator cmp) { int left = 0; @@ -227,7 +227,7 @@ private static int binarySearchLeft(T[] array, int start, int length, T targ while(left < right) { // equivalent to (left + right) / 2 with added overflow protection int middle = (left + right) >>> 1; - + if(cmp.compare(array[start + middle], target) < 0) { left = middle + 1; } @@ -237,7 +237,7 @@ private static int binarySearchLeft(T[] array, int start, int length, T targ } return left; } - + // Technically a "upper bound" search private static int binarySearchRight(T[] array, int start, int length, T target, Comparator cmp) { int left = 0; @@ -246,7 +246,7 @@ private static int binarySearchRight(T[] array, int start, int length, T tar while(left < right) { // equivalent to (left + right) / 2 with added overflow protection int middle = (left + right) >>> 1; - + if(cmp.compare(array[start + middle], target) > 0) { right = middle; } @@ -256,7 +256,7 @@ private static int binarySearchRight(T[] array, int start, int length, T tar } return right; } - + // Returns -1 if an equal key is found, cutting off the search early // FUTURE TODO: first & last key best-cases private static int binarySearchExclusive(T[] array, int start, int length, T target, Comparator cmp) { @@ -266,7 +266,7 @@ private static int binarySearchExclusive(T[] array, int start, int length, T while(left < right) { // equivalent to (left + right) / 2 with added overflow protection int middle = (left + right) >>> 1; - + int comp = cmp.compare(array[start + middle], target); if(comp == 0) { return -1; @@ -280,7 +280,7 @@ else if(comp < 0) { } return left; } - + // cost: 2 * length + idealKeys^2 / 2 private static int collectKeys(T[] array, int start, int length, int idealKeys, Comparator cmp) { int keysFound = 1; // by itself, the first item in the array is our first unique key @@ -308,7 +308,7 @@ private static int collectKeys(T[] array, int start, int length, int idealKe if(keysFound != insertPos) { insertBackwards(array, start + firstKey + insertPos, keysFound - insertPos); } - + // One step closer to idealKeys. keysFound++; } @@ -327,16 +327,16 @@ private static void sortPairsWithKeys(T[] array, int start, int length, Comp // first, save the keys to stack memory T firstKey = array[start - 1]; T secondKey = array[start - 2]; - + // move all the items down two indices, sorting them simultaneously sortPairs(array, start, length, cmp); - + // finally, stamp the saved keys (remember: order doesn't matter!) // to the end of the array array[start + length - 2] = firstKey; array[start + length - 1] = secondKey; } - + private static void sortPairs(T[] array, int start, int length, Comparator cmp) { int index; for(index = 1; index < length; index += 2) { @@ -358,9 +358,9 @@ private static void sortPairs(T[] array, int start, int length, Comparator "scrolling buffer" - // + // // "scrolling buffer" + array[start, middle - 1] + array[middle, end - 1] // --> array[buffer, buffer + end - 1] + "scrolling buffer" private static void mergeForwards(T[] array, int start, int leftLen, int rightLen, @@ -416,7 +416,7 @@ private static void mergeBackwards(T[] array, int start, int leftLen, int ri } } - // array[buffer .. start - 1] <=> "free space" + // array[buffer .. start - 1] <=> "free space" // // "free space" + array[start, middle - 1] + array[middle, end - 1] // --> array[buffer, buffer + end - 1] + "free space" @@ -445,9 +445,9 @@ private static void mergeForwardsOutOfPlace(T[] array, int start, int leftLe if(buffer != left) { System.arraycopy(array, left, array, buffer, middle - left); - + // swapBlocksForwards(array, buffer, left, middle - left); - + /* while(left < middle) { array[buffer] = array[left]; @@ -457,7 +457,7 @@ private static void mergeForwardsOutOfPlace(T[] array, int start, int leftLe */ } } - + private static void mergeBackwardsOutOfPlace(T[] array, int start, int leftLen, int rightLen, int bufferOffset, Comparator cmp) { int end = start - 1; @@ -481,9 +481,9 @@ private static void mergeBackwardsOutOfPlace(T[] array, int start, int leftL if(right != buffer) { System.arraycopy(array, right, array, buffer, right - middle); - + // swapBlocksBackwards(array, right, buffer, right - middle); - + /* while(right > middle) { array[buffer] = array[right]; @@ -493,7 +493,7 @@ private static void mergeBackwardsOutOfPlace(T[] array, int start, int leftL */ } } - + private static void buildInPlace(T[] array, int start, int length, int currentLen, int bufferLen, Comparator cmp) { for(int mergeLen = currentLen; mergeLen < bufferLen; mergeLen *= 2) { int fullMerge = 2 * mergeLen; @@ -518,7 +518,7 @@ private static void buildInPlace(T[] array, int start, int length, int curre start -= mergeLen; } - int fullMerge = 2 * bufferLen; + int fullMerge = 2 * bufferLen; int lastBlock = length % fullMerge; int lastOffset = start + length - lastBlock; @@ -533,7 +533,7 @@ private static void buildInPlace(T[] array, int start, int length, int curre mergeBackwards(array, mergeIndex, bufferLen, bufferLen, bufferLen, cmp); } } - + private void buildOutOfPlace(T[] array, int start, int length, int bufferLen, int extLen, Comparator cmp) { System.arraycopy(array, start - extLen, this.extBuffer, 0, extLen); @@ -565,7 +565,7 @@ private void buildOutOfPlace(T[] array, int start, int length, int bufferLen, in } if(extLen == bufferLen) { - int fullMerge = 2 * bufferLen; + int fullMerge = 2 * bufferLen; int lastBlock = length % fullMerge; int lastOffset = start + length - lastBlock; @@ -585,7 +585,7 @@ private void buildOutOfPlace(T[] array, int start, int length, int bufferLen, in buildInPlace(array, start, length, mergeLen, bufferLen, cmp); } } - + // build blocks of length 'bufferLen' // input: [start - mergeLen, start - 1] elements are buffer // output: first 'bufferLen' elements are buffer, blocks (2 * bufferLen) and last subblock sorted @@ -611,7 +611,7 @@ private void buildBlocks(T[] array, int start, int length, int bufferLen, Compar buildInPlace(array, start - 2, length, 2, bufferLen, cmp); } } - + // implementation of "smart block selection" sort // code inspired by Anonymous0726 private static void sortBlocks(T[] array, int firstKey, int start, int blockCount, @@ -619,17 +619,17 @@ private static void sortBlocks(T[] array, int firstKey, int start, int block boolean sortByTail, Comparator cmp) { // this check might be unnecessary with the new "combine blocks" control flow if(blockCount == leftBlocks) return; - + int cmpIndex = sortByTail ? blockLen - 1 : 0; - + int blockIndex = start; int keyIndex = firstKey; - + int rightBlock = start + (leftBlocks * blockLen); int rightKey = firstKey + leftBlocks; - + boolean sorted = true; - + // phase one: find first index in left subarray where a smaller right block can be swapped; // if no swaps occur, the subarrays are already in order do { @@ -643,9 +643,9 @@ private static void sortBlocks(T[] array, int firstKey, int start, int block } while(sorted && keyIndex < rightKey); if(sorted) return; - + // consider anonymous' suggestion - + int lastKey = firstKey + blockCount - 1; int scrambledEnd = rightKey < lastKey ? rightKey + 1 : rightKey; @@ -674,7 +674,7 @@ private static void sortBlocks(T[] array, int firstKey, int start, int block blockIndex += blockLen; keyIndex++; } - + // phase three: after the left subarray has been sorted, keep finding the next block in order // from the scrambled area until either (a) the scrambled area runs out of blocks, // meaning the rest are sorted, or (b) the scrambled area hits the end of the right @@ -703,17 +703,17 @@ private static void sortBlocks(T[] array, int firstKey, int start, int block blockIndex += blockLen; keyIndex++; - + if(keyIndex == scrambledEnd) return; } - + // phase four: sort the remainder blocks from the scrambled area do { int selectBlock = blockIndex; int selectKey = keyIndex; - + int currBlock = blockIndex + blockLen; - + for(int currKey = keyIndex + 1; currKey <= lastKey; currKey++, currBlock += blockLen) { int compare = cmp.compare(array[currBlock + cmpIndex], array[selectBlock + cmpIndex]); if (compare < 0 || (compare == 0 && cmp.compare(array[ currKey], @@ -722,32 +722,32 @@ private static void sortBlocks(T[] array, int firstKey, int start, int block selectKey = currKey; } } - + if(selectKey != keyIndex) { swapBlocksForwards(array, blockIndex, selectBlock, blockLen); swap(array, keyIndex, selectKey); } - + blockIndex += blockLen; keyIndex++; } while(keyIndex < lastKey); - + /* for(int blockIndex = 0, keyIndex = 0; keyIndex < keyCount; blockIndex += blockLen, keyIndex++) { int selectBlock = blockIndex; int selectKey = keyIndex; - + for(int currBlock = selectBlock + blockLen, currKey = keyIndex + 1; currKey < keyCount; currBlock += blockLen, currKey++) { - - int compare = cmp.compare(array[start + currBlock], array[start + selectBlock]); + + int compare = cmp.compare(array[start + currBlock], array[start + selectBlock]); if (compare < 0 || (compare == 0 && cmp.compare(array[firstKey + currKey], array[firstKey + selectKey]) < 0)) { selectBlock = currBlock; selectKey = currKey; } } - + if(selectKey != keyIndex) { swapBlocksForwards(array, start + blockIndex, start + selectBlock, blockLen); swap(array, firstKey + keyIndex, firstKey + selectKey); @@ -755,7 +755,7 @@ private static void sortBlocks(T[] array, int firstKey, int start, int block } */ } - + /* private static void rewindBuffer(T[] array, int start, int leftBlock, int buffer) { while(leftBlock >= start) { @@ -772,7 +772,7 @@ private static void rewindOutOfPlace(T[] array, int start, int leftBlock, in buffer--; } } - + private static void fastForwardBuffer(T[] array, int buffer, int rightBlock, int end) { while(rightBlock <= end) { swap(array, rightBlock, buffer); @@ -780,7 +780,7 @@ private static void fastForwardBuffer(T[] array, int buffer, int rightBlock, buffer++; } } - + private static void fastForwardOutOfPlace(T[] array, int buffer, int rightBlock, int end) { while(rightBlock <= end) { array[buffer] = array[rightBlock]; @@ -788,13 +788,13 @@ private static void fastForwardOutOfPlace(T[] array, int buffer, int rightBl buffer++; } } - + // Swaps Grailsort's "scrolling buffer" from the right side of the array all the way back to 'start'. // Costs O(n) swaps. private static void resetBuffer(T[] array, int start, int length, int bufferOffset) { int buffer = start + length - 1; int index = buffer - bufferOffset; - + while(buffer >= start) { swap(array, index, buffer); buffer--; @@ -802,7 +802,7 @@ private static void resetBuffer(T[] array, int start, int length, int buffer } } */ - + private static Subarray getSubarray(T[] array, int currentKey, T medianKey, Comparator cmp) { if(cmp.compare(array[currentKey], medianKey) < 0) { return Subarray.LEFT; @@ -811,7 +811,7 @@ private static Subarray getSubarray(T[] array, int currentKey, T medianKey, return Subarray.RIGHT; } } - + // FUNCTION RE-RENAMED: last/final left blocks are used to calculate the length of the final merge private static int countLastMergeBlocks(T[] array, int offset, int blockCount, int blockLen, Comparator cmp) { @@ -828,7 +828,7 @@ private static int countLastMergeBlocks(T[] array, int offset, int blockCoun return blocksToMerge; } - + private void localMergeForwards(T[] array, int start, int leftLen, Subarray leftOrigin, int rightLen, int bufferOffset, Comparator cmp) { int buffer = start - bufferOffset; @@ -861,14 +861,14 @@ private void localMergeForwards(T[] array, int start, int leftLen, Subarray left right++; } buffer++; - } + } } if(left < middle) { int leftFrag = middle - left; swapBlocksBackwards(array, left, end - leftFrag, leftFrag); this.currBlockLen = leftFrag; - + //this.currBlockLen = leftFrag; //rewindBuffer(array, left, middle - 1, end - 1); } @@ -890,7 +890,7 @@ private void localMergeBackwards(T[] array, int start, int leftLen, int rightLen int middle = left; int right = middle + rightLen; int buffer = right + bufferOffset; - + if(rightOrigin == Subarray.RIGHT) { while(left > end && right > middle) { if(cmp.compare(array[left], array[right]) > 0) { @@ -917,12 +917,12 @@ private void localMergeBackwards(T[] array, int start, int leftLen, int rightLen buffer--; } } - + if(right > middle) { int rightFrag = right - middle; swapBlocksForwards(array, end + 1, middle + 1, rightFrag); this.currBlockLen = rightFrag; - + //this.currBlockLen = right - middle; //fastForwardBuffer(array, end + 1, middle + 1, right); } @@ -936,11 +936,11 @@ private void localMergeBackwards(T[] array, int start, int leftLen, int rightLen } } } - + private void localLazyMerge(T[] array, int start, int leftLen, Subarray leftOrigin, int rightLen, Comparator cmp) { int middle = start + leftLen; - + if(leftOrigin == Subarray.LEFT) { if(cmp.compare(array[middle - 1], array[middle]) > 0) { while(leftLen != 0) { @@ -948,12 +948,12 @@ private void localLazyMerge(T[] array, int start, int leftLen, Subarray leftOrig if(mergeLen != 0) { rotate(array, start, leftLen, mergeLen); - + start += mergeLen; middle += mergeLen; rightLen -= mergeLen; } - + if(rightLen == 0) { this.currBlockLen = leftLen; return; @@ -975,12 +975,12 @@ private void localLazyMerge(T[] array, int start, int leftLen, Subarray leftOrig if(mergeLen != 0) { rotate(array, start, leftLen, mergeLen); - + start += mergeLen; middle += mergeLen; rightLen -= mergeLen; } - + if(rightLen == 0) { this.currBlockLen = leftLen; return; @@ -1004,7 +1004,7 @@ private void localLazyMerge(T[] array, int start, int leftLen, Subarray leftOrig this.currBlockOrigin = Subarray.LEFT; } } - + // FUNCTION RENAMED: more consistent with other "out-of-place" merges private void localMergeForwardsOutOfPlace(T[] array, int start, int leftLen, Subarray leftOrigin, int rightLen, int bufferOffset, @@ -1039,18 +1039,18 @@ private void localMergeForwardsOutOfPlace(T[] array, int start, int leftLen, Sub right++; } buffer++; - } + } } if(left < middle) { int leftFrag = middle - left; System.arraycopy(array, left, array, end - leftFrag, leftFrag); this.currBlockLen = leftFrag; - + //int leftFrag = middle - left; //swapBlocksBackwards(array, left, end - leftFrag, leftFrag); //this.currBlockLen = leftFrag; - + //this.currBlockLen = middle - left; //rewindOutOfPlace(array, left, middle - 1, end - 1); } @@ -1064,7 +1064,7 @@ private void localMergeForwardsOutOfPlace(T[] array, int start, int leftLen, Sub } } } - + private void localMergeBackwardsOutOfPlace(T[] array, int start, int leftLen, int rightLen, Subarray rightOrigin, int bufferOffset, Comparator cmp) { int end = start - 1; @@ -1104,11 +1104,11 @@ private void localMergeBackwardsOutOfPlace(T[] array, int start, int leftLen, in int rightFrag = right - middle; System.arraycopy(array, middle + 1, array, end + 1, rightFrag); this.currBlockLen = rightFrag; - + //int rightFrag = right - middle; //swapBlocksForwards(array, end + 1, middle + 1, rightFrag); //this.currBlockLen = rightFrag; - + //this.currBlockLen = right - middle; //fastForwardOutOfPlace(array, end + 1, middle + 1, right); } @@ -1142,7 +1142,7 @@ private void mergeBlocksForwards(T[] array, int firstKey, T medianKey, int start if(nextBlockOrigin != this.currBlockOrigin) { this.localMergeForwards(array, currBlock, this.currBlockLen, this.currBlockOrigin, - blockLen, blockLen, cmp); + blockLen, blockLen, cmp); } else { buffer = currBlock - blockLen; @@ -1216,18 +1216,18 @@ private void lazyMergeBlocks(T[] array, int firstKey, T medianKey, int start, private void mergeBlocksBackwards(T[] array, int firstKey, T medianKey, int start, int blockCount, int blockLen, int lastLen, Comparator cmp) { - + int nextBlock = start + (blockCount * blockLen) - 1; int buffer = nextBlock + lastLen + blockLen; - + // The last fragment (lastLen) came from the right subarray, // although it may be empty (lastLen == 0) this.currBlockLen = lastLen; this.currBlockOrigin = Subarray.RIGHT; - + for(int keyIndex = blockCount - 1; keyIndex >= 0; keyIndex--, nextBlock -= blockLen) { Subarray nextBlockOrigin = getSubarray(array, firstKey + keyIndex, medianKey, cmp); - + if(nextBlockOrigin != this.currBlockOrigin) { // TODO: buffer length *should* always be equivalent to: // right block length - forwards merge blocks @@ -1242,10 +1242,10 @@ private void mergeBlocksBackwards(T[] array, int firstKey, T medianKey, int star this.currBlockLen = blockLen; } } - + swapBlocksBackwards(array, start, start + blockLen, this.currBlockLen); } - + private void mergeBlocksForwardsOutOfPlace(T[] array, int firstKey, T medianKey, int start, int blockCount, int blockLen, int lastMergeBlocks, int lastLen, Comparator cmp) { @@ -1260,12 +1260,12 @@ private void mergeBlocksForwardsOutOfPlace(T[] array, int firstKey, T medianKey, for(int keyIndex = 1; keyIndex < blockCount; keyIndex++, nextBlock += blockLen) { Subarray nextBlockOrigin; - currBlock = nextBlock - this.currBlockLen; + currBlock = nextBlock - this.currBlockLen; nextBlockOrigin = getSubarray(array, firstKey + keyIndex, medianKey, cmp); if(nextBlockOrigin != this.currBlockOrigin) { this.localMergeForwardsOutOfPlace(array, currBlock, this.currBlockLen, this.currBlockOrigin, - blockLen, blockLen, cmp); + blockLen, blockLen, cmp); } else { buffer = currBlock - blockLen; @@ -1297,20 +1297,20 @@ private void mergeBlocksForwardsOutOfPlace(T[] array, int firstKey, T medianKey, System.arraycopy(array, currBlock, array, buffer, this.currBlockLen); } } - + private void mergeBlocksBackwardsOutOfPlace(T[] array, int firstKey, T medianKey, int start, int blockCount, int blockLen, int lastLen, Comparator cmp) { int nextBlock = start + (blockCount * blockLen) - 1; int buffer = nextBlock + lastLen + blockLen; - + // The last fragment (lastLen) came from the right subarray, // although it may be empty (lastLen == 0) this.currBlockLen = lastLen; this.currBlockOrigin = Subarray.RIGHT; - + for(int keyIndex = blockCount - 1; keyIndex >= 0; keyIndex--, nextBlock -= blockLen) { Subarray nextBlockOrigin = getSubarray(array, firstKey + keyIndex, medianKey, cmp); - + if(nextBlockOrigin != this.currBlockOrigin) { this.localMergeBackwardsOutOfPlace(array, nextBlock - blockLen + 1, blockLen, this.currBlockLen, this.currBlockOrigin, blockLen, cmp); @@ -1321,10 +1321,10 @@ private void mergeBlocksBackwardsOutOfPlace(T[] array, int firstKey, T medianKey this.currBlockLen = blockLen; } } - + System.arraycopy(array, start, array, start + blockLen, this.currBlockLen); } - + // a novel, elegant, and incredibly efficient 1.5 sqrt n key sort, courtesy of Control // only works if a) median key is known and b) keys were permutated by "sortBlocks" // (keys < medianKey and >= medianKey are each in relative sorted order, resembling a final radix sort pass) @@ -1332,7 +1332,7 @@ private static void sortKeys(T[] array, int firstKey, T medianKey, int keyCo int currKey = firstKey; int keysEnd = firstKey + keyCount; int bufferSwaps = 0; - + while(currKey < keysEnd) { if(cmp.compare(array[currKey], medianKey) < 0) { if(bufferSwaps != 0) { @@ -1345,13 +1345,13 @@ private static void sortKeys(T[] array, int firstKey, T medianKey, int keyCo } currKey++; } - + swapBlocksBackwards(array, currKey - bufferSwaps, buffer, bufferSwaps); } - + private static void groupKeys(T[] array, int left, int right, T medianKey, Comparator cmp) { while(left < right && cmp.compare(array[left], medianKey) < 0) left++; - + for(int i = left + 1; i < right; i++) { if(cmp.compare(array[i], medianKey) < 0) { insertBackwards(array, left, i - left); @@ -1363,10 +1363,10 @@ private static void groupKeys(T[] array, int left, int right, T medianKey, C private static void mergeGroups(T[] array, int left, int middle, int right, T medianKey, Comparator cmp) { int leftLen = middle - left; int rightLen = right - middle; - + int mergeStart = left + binarySearchLeft(array, left, leftLen, medianKey, cmp); int mergeLen = binarySearchLeft(array, middle, rightLen, medianKey, cmp); - + rotate(array, mergeStart, middle - mergeStart, mergeLen); } @@ -1377,41 +1377,41 @@ private static void mergeGroups(T[] array, int left, int middle, int right, private static void lazySortKeys(T[] array, int firstKey, int keyCount, T medianKey, Comparator cmp) { int runLen = 8; int keysEnd = firstKey + keyCount; - + int i; for(i = firstKey; i + runLen < keysEnd; i += runLen) { groupKeys(array, i, i + runLen, medianKey, cmp); } groupKeys(array, i, keysEnd, medianKey, cmp); - + while(runLen < keyCount) { int fullMerge = 2 * runLen; - + int mergeIndex; int mergeEnd = keysEnd - fullMerge; - + for(mergeIndex = firstKey; mergeIndex <= mergeEnd; mergeIndex += fullMerge) { mergeGroups(array, mergeIndex, mergeIndex + runLen, mergeIndex + fullMerge, medianKey, cmp); } - + int leftOver = keysEnd - mergeIndex; if(leftOver > runLen) { mergeGroups(array, mergeIndex, mergeIndex + runLen, keysEnd, medianKey, cmp); } - + runLen *= 2; } } - + private void combineForwards(T[] array, int firstKey, int start, int length, int subarrayLen, int blockLen) { Comparator cmp = this.cmp; // local variable for performance à la Timsort // TODO: Double-check names and change all other functions to match int mergeLen = 2 * subarrayLen; - int fullMerges = length / mergeLen; + int fullMerges = length / mergeLen; int blockCount = mergeLen / blockLen; int lastSubarrays = length - (mergeLen * fullMerges); - + int fastForwardLen = 0; if(lastSubarrays <= subarrayLen) { if(fullMerges % 2 != 0) { @@ -1420,26 +1420,26 @@ private void combineForwards(T[] array, int firstKey, int start, int length, int length -= lastSubarrays; lastSubarrays = 0; } - + int leftBlocks = subarrayLen / blockLen; T medianKey = array[firstKey + leftBlocks]; - + for(int mergeIndex = 0; mergeIndex < fullMerges; mergeIndex++) { int offset = start + (mergeIndex * mergeLen); - + sortBlocks(array, firstKey, offset, blockCount, leftBlocks, blockLen, false, cmp); this.mergeBlocksForwards(array, firstKey, medianKey, offset, blockCount, blockLen, 0, 0, cmp); - + // TODO: Replace with Control's key sort sortKeys(array, firstKey, medianKey, blockCount, offset + mergeLen - blockLen, cmp); //insertSort(array, firstKey, blockCount, cmp); } int offset = start + (fullMerges * mergeLen); - + if(lastSubarrays != 0) { blockCount = lastSubarrays / blockLen; - + sortBlocks(array, firstKey, offset, blockCount, leftBlocks, blockLen, false, cmp); int lastFragment = lastSubarrays - (blockCount * blockLen); @@ -1462,10 +1462,10 @@ private void combineForwards(T[] array, int firstKey, int start, int length, int //TODO: Why is this 'blockCount + 1'??? sortKeys(array, firstKey, medianKey, blockCount, offset + lastSubarrays - blockLen, cmp); //insertSort(array, firstKey, blockCount, cmp); - + if(fullMerges % 2 == 0 && fullMerges != 0) { swapBlocksBackwards(array, offset - blockLen, offset, lastSubarrays); - + // lastSubarrays--; // rewindBuffer(array, offset - blockLen, offset + lastSubarrays - blockLen, offset + lastSubarrays); } @@ -1475,7 +1475,7 @@ private void combineForwards(T[] array, int firstKey, int start, int length, int if(fullMerges % 2 != 0 && fullMerges != 1) { // TODO: Double-check if this is equivalent to the rewindBuffer version... swapBlocksBackwards(array, offset - blockLen - mergeLen, offset - blockLen, mergeLen); - + // TODO: check arguments // rewindBuffer(array, offset - mergeLen - blockLen, offset - blockLen - 1, offset - 1); } @@ -1485,21 +1485,21 @@ private void combineForwards(T[] array, int firstKey, int start, int length, int // fastForwardBuffer(array, offset - blockLen, offset, offset + fastForwardLen - 1); } } - + /* // ceil division of length over subarrayLen mod 4 int mergeCount = ((length - 1) / subarrayLen) + 1; int bufferControl = mergeCount % 4; - + if(bufferControl == 1) { - + } else if(bufferControl == 2) { - + } */ } - + private void lazyCombine(T[] array, int firstKey, int start, int length, int subarrayLen, int blockLen) { Comparator cmp = this.cmp; // local variable for performance à la Timsort @@ -1507,27 +1507,27 @@ private void lazyCombine(T[] array, int firstKey, int start, int length, int sub int fullMerges = length / mergeLen; int blockCount = mergeLen / blockLen; int lastSubarrays = length - (mergeLen * fullMerges); - + if(lastSubarrays <= subarrayLen) { length -= lastSubarrays; lastSubarrays = 0; } - + int leftBlocks = subarrayLen / blockLen; T medianKey = array[firstKey + leftBlocks]; - + for(int mergeIndex = 0; mergeIndex < fullMerges; mergeIndex++) { int offset = start + (mergeIndex * mergeLen); - + sortBlocks(array, firstKey, offset, blockCount, leftBlocks, blockLen, false, cmp); this.lazyMergeBlocks(array, firstKey, medianKey, offset, blockCount, blockLen, 0, 0, cmp); - + lazySortKeys(array, firstKey, blockCount, medianKey, cmp); //insertSort(array, firstKey, blockCount, cmp); } int offset = start + (fullMerges * mergeLen); - + if(lastSubarrays != 0) { blockCount = lastSubarrays / blockLen; @@ -1555,26 +1555,26 @@ private void lazyCombine(T[] array, int firstKey, int start, int length, int sub lazySortKeys(array, firstKey, blockCount, medianKey, cmp); } } - + private void combineBackwards(T[] array, int firstKey, int start, int length, int subarrayLen, int blockLen) { Comparator cmp = this.cmp; // local variable for performance à la Timsort int mergeLen = 2 * subarrayLen; int fullMerges = length / mergeLen; int lastSubarrays = length - (mergeLen * fullMerges); - + if(lastSubarrays <= subarrayLen) { length -= lastSubarrays; lastSubarrays = 0; } - + int blockCount = lastSubarrays / blockLen; int leftBlocks = subarrayLen / blockLen; T medianKey = array[firstKey + leftBlocks]; - + if(lastSubarrays != 0) { int offset = start + (fullMerges * mergeLen); - + sortBlocks(array, firstKey, offset, blockCount, leftBlocks, blockLen, true, cmp); int lastFragment = lastSubarrays - (blockCount * blockLen); @@ -1588,20 +1588,20 @@ private void combineBackwards(T[] array, int firstKey, int start, int length, in sortKeys(array, firstKey, medianKey, blockCount, offset, cmp); //insertSort(array, firstKey, blockCount, cmp); } - + blockCount = mergeLen / blockLen; - + for(int mergeIndex = fullMerges - 1; mergeIndex >= 0; mergeIndex--) { int offset = start + (mergeIndex * mergeLen); - + sortBlocks(array, firstKey, offset, blockCount, leftBlocks, blockLen, true, cmp); this.mergeBlocksBackwards(array, firstKey, medianKey, offset, blockCount, blockLen, 0, cmp); - + sortKeys(array, firstKey, medianKey, blockCount, offset, cmp); //insertSort(array, firstKey, blockCount, cmp); } } - + private void combineForwardsOutOfPlace(T[] array, int firstKey, int start, int length, int subarrayLen, int blockLen) { Comparator cmp = this.cmp; // local variable for performance à la Timsort @@ -1609,7 +1609,7 @@ private void combineForwardsOutOfPlace(T[] array, int firstKey, int start, int l int fullMerges = length / mergeLen; int blockCount = mergeLen / blockLen; int lastSubarrays = length - (mergeLen * fullMerges); - + int fastForwardLen = 0; if(lastSubarrays <= subarrayLen) { if(fullMerges % 2 != 0) { @@ -1618,21 +1618,21 @@ private void combineForwardsOutOfPlace(T[] array, int firstKey, int start, int l length -= lastSubarrays; lastSubarrays = 0; } - + int leftBlocks = subarrayLen / blockLen; T medianKey = array[firstKey + leftBlocks]; - + for(int mergeIndex = 0; mergeIndex < fullMerges; mergeIndex++) { int offset = start + (mergeIndex * mergeLen); - + sortBlocks(array, firstKey, offset, blockCount, leftBlocks, blockLen, false, cmp); this.mergeBlocksForwardsOutOfPlace(array, firstKey, medianKey, offset, blockCount, blockLen, 0, 0, cmp); - + insertSort(array, firstKey, blockCount, cmp); } int offset = start + (fullMerges * mergeLen); - + if(lastSubarrays != 0) { blockCount = lastSubarrays / blockLen; @@ -1657,12 +1657,12 @@ private void combineForwardsOutOfPlace(T[] array, int firstKey, int start, int l //TODO: Why is this 'blockCount + 1'??? insertSort(array, firstKey, blockCount, cmp); - + if(fullMerges % 2 == 0 && fullMerges != 0) { System.arraycopy(array, offset - blockLen, array, offset, lastSubarrays); - + // swapBlocksBackwards(array, offset - blockLen, offset, lastSubarrays); - + // lastSubarrays--; // rewindOutOfPlace(array, offset - blockLen, offset + lastSubarrays - blockLen, offset + lastSubarrays); } @@ -1672,42 +1672,42 @@ private void combineForwardsOutOfPlace(T[] array, int firstKey, int start, int l if(fullMerges % 2 != 0 && fullMerges != 1) { // TODO: Double-check if this is equivalent to the rewindBuffer version... System.arraycopy(array, offset - blockLen - mergeLen, array, offset - blockLen, mergeLen); - + // swapBlocksBackwards(array, offset - blockLen - mergeLen, offset - blockLen, mergeLen); - + // TODO: check arguments // rewindOutOfPlace(array, offset - fullMerge - blockLen, offset - blockLen - 1, offset - 1); } } else { System.arraycopy(array, offset, array, offset - blockLen, fastForwardLen); - + // swapBlocksForwards(array, offset - blockLen, offset, fastForwardLen); - + // fastForwardOutOfPlace(array, offset - blockLen, offset, offset + fastForwardLen - 1); } } } - + private void combineBackwardsOutOfPlace(T[] array, int firstKey, int start, int length, int subarrayLen, int blockLen) { Comparator cmp = this.cmp; // local variable for performance à la Timsort int mergeLen = 2 * subarrayLen; int fullMerges = length / mergeLen; int lastSubarrays = length - (mergeLen * fullMerges); - + if(lastSubarrays <= subarrayLen) { length -= lastSubarrays; lastSubarrays = 0; } - + int blockCount = lastSubarrays / blockLen; int leftBlocks = subarrayLen / blockLen; T medianKey = array[firstKey + leftBlocks]; - + if(lastSubarrays != 0) { int offset = start + (fullMerges * mergeLen); - + if(lastSubarrays - subarrayLen <= blockLen) { mergeBackwards(array, offset, subarrayLen, lastSubarrays - subarrayLen, blockLen, cmp); } @@ -1725,28 +1725,28 @@ private void combineBackwardsOutOfPlace(T[] array, int firstKey, int start, int insertSort(array, firstKey, blockCount, cmp); } } - + blockCount = mergeLen / blockLen; - + for(int mergeIndex = fullMerges - 1; mergeIndex >= 0; mergeIndex--) { int offset = start + (mergeIndex * mergeLen); - + sortBlocks(array, firstKey, offset, blockCount, leftBlocks, blockLen, true, cmp); this.mergeBlocksBackwardsOutOfPlace(array, firstKey, medianKey, offset, blockCount, blockLen, 0, cmp); - + insertSort(array, firstKey, blockCount, cmp); } } - + // 'keys' are on the left side of array. Blocks of length 'subarrayLen' combined. We'll combine them in pairs // 'subarrayLen' is a power of 2. (2 * subarrayLen / blockLen) keys are guaranteed private LocalMerge combineBlocks(T[] array, int start, int length, int bufferLen, int subarrayLen, int blockLen, int keyLen, boolean idealBuffer) { LocalMerge direction = LocalMerge.FORWARDS; subarrayLen *= 2; - + T[] extBuffer = this.extBuffer; - + if(idealBuffer) { if(extBuffer == null) { while((length - bufferLen) > subarrayLen) { @@ -1782,7 +1782,7 @@ private LocalMerge combineBlocks(T[] array, int start, int length, int bufferLen else { int keyBuffer = keyLen / 2; shellSort(array, start, keyBuffer, this.cmp); - + if(extBuffer == null) { while(keyBuffer >= ((2 * subarrayLen) / keyBuffer)) { if(direction == LocalMerge.FORWARDS) { @@ -1821,17 +1821,17 @@ private LocalMerge combineBlocks(T[] array, int start, int length, int bufferLen } shellSort(array, start, keyLen, this.cmp); - + while((length - keyLen) > subarrayLen) { this.lazyCombine(array, start, start + keyLen, length - keyLen, subarrayLen, (2 * subarrayLen) / keyLen); subarrayLen *= 2; } } - + return direction; } - + // "Classic" in-place merge sort using binary searches and rotations // Forwards rotates the leftLen into the rightLen // cost: leftLen^2 + rightLen @@ -1861,14 +1861,14 @@ private static void lazyMergeForwards(T[] array, int start, int leftLen, int } } } - + // "Classic" in-place merge sort using binary searches and rotations // Backwards rotates the rigthLen into the leftLen // cost: rightLen^2 + leftLen private static void lazyMergeBackwards(T[] array, int start, int leftLen, int rightLen, Comparator cmp) { int end = start + leftLen + rightLen - 1; - while(rightLen != 0) { + while(rightLen != 0) { int mergeLen = binarySearchRight(array, start, leftLen, array[end], cmp); if(mergeLen != leftLen) { @@ -1892,11 +1892,11 @@ private static void lazyMergeBackwards(T[] array, int start, int leftLen, in } } } - + private static void lazyMergeBufferBackwards(T[] array, int start, int leftLen, int rightLen, Comparator cmp) { int end = start + leftLen + rightLen - 1; - while(rightLen != 0) { + while(rightLen != 0) { int mergeLen = binarySearchLeft(array, start, leftLen, array[end], cmp); if(mergeLen != leftLen) { @@ -1920,7 +1920,7 @@ private static void lazyMergeBufferBackwards(T[] array, int start, int leftL } } } - + private static void lazyStableSort(T[] array, int start, int length, Comparator cmp) { int i; for(i = 0; i <= length - 16; i += 16) { @@ -1944,48 +1944,48 @@ private static void lazyStableSort(T[] array, int start, int length, Compara } } } - + void commonSort(T[] array, int start, int length, T[] extBuffer, int extBufferLen) { if(length < 16) { insertSort(array, start, length, this.cmp); return; } - + // smallest possible O(sqrt n) block length that // doesn't include arrays sorted by Insertion Sort int blockLen = 4; - + // find the smallest power of two greater than or // equal to the square root of the input's length while((blockLen * blockLen) < length) { blockLen *= 2; } - + // '((a - 1) / b) + 1' is actually a clever and very efficient // formula for the ceiling of (a / b) // // credit to Anonymous0726 for figuring this out! - + // TODO: We don't need this ceiling??? int keyLen = ((length - 1) / blockLen) + 1; - + // Holy Grail is hoping to find '~2 sqrt n' unique items // throughout the array int idealKeys = keyLen + blockLen; - + int keysFound = collectKeys(array, start, length, idealKeys, this.cmp); - + boolean idealBuffer; if(keysFound < idealKeys) { - + // HOLY GRAIL STRATEGY 3 // No block swaps or scrolling buffer; resort to Lazy Stable Sort if(keysFound < 4) { - + // if all items in the array equal each other, // then they're already sorted. done! if(keysFound == 1) return; - + lazyStableSort(array, start, length, this.cmp); return; } @@ -2006,7 +2006,7 @@ void commonSort(T[] array, int start, int length, T[] extBuffer, int extBufferLe // Block swaps with scrolling buffer idealBuffer = true; } - + int bufferLen = blockLen + keyLen; int subarrayLen; if(idealBuffer) { @@ -2015,22 +2015,22 @@ void commonSort(T[] array, int start, int length, T[] extBuffer, int extBufferLe else { subarrayLen = keyLen; } - + if(extBuffer != null) { // GRAILSORT + EXTRA SPACE this.extBuffer = extBuffer; this.extBufferLen = extBufferLen; } - + this.buildBlocks(array, start + bufferLen, length - bufferLen, subarrayLen, this.cmp); - + // TODO: Handle case where external buffer is not large enough for combine blocks - + LocalMerge direction = this.combineBlocks(array, start, length, bufferLen, subarrayLen, blockLen, keyLen, idealBuffer); - + // TODO: Paste external buffer back into array - + // This 'if' case will always run during Strategy 2 if(direction == LocalMerge.FORWARDS) { shellSort(array, start + keyLen, blockLen, this.cmp); diff --git a/Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft/src/holygrail/Tester.java b/Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft/src/holygrail/Tester.java index 26cfb39..cbb45ce 100644 --- a/Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft/src/holygrail/Tester.java +++ b/Holy Grail Sort/Java/Summer Dragonfly et al.'s Rough Draft/src/holygrail/Tester.java @@ -1,46 +1,263 @@ package holygrail; +import java.lang.reflect.Array; +import java.util.Arrays; import java.util.Comparator; -interface IntegerPair { - public Integer getKey(); - public Integer getValue(); -} +public class Tester { + static class SortFailedException extends Exception { + } -class GrailPair implements IntegerPair { - private Integer key; - private Integer value; - - public GrailPair(Integer key, Integer value) { - this.key = key; - this.value = value; + static interface IntegerPair { + public Integer getKey(); + public Integer getValue(); } - @Override - public Integer getKey() { - return this.key; + + static class GrailPair implements IntegerPair { + private Integer key; + private Integer value; + + public GrailPair(Integer key, Integer value) { + this.key = key; + this.value = value; + } + @Override + public Integer getKey() { + return this.key; + } + @Override + public Integer getValue() { + return this.value; + } } - @Override - public Integer getValue() { - return this.value; + + static class GrailComparator implements Comparator { + @Override + public int compare(GrailPair o1, GrailPair o2) { + if (o1.getKey() < o2.getKey()) return -1; + else if(o1.getKey() > o2.getKey()) return 1; + else return 0; + } } -} -class GrailComparator implements Comparator { - @Override - public int compare(GrailPair o1, GrailPair o2) { - if (o1.getKey() < o2.getKey()) return -1; - else if(o1.getKey() > o2.getKey()) return 1; - else return 0; + private int seed; + + private GrailPair[] keyArray; + private GrailPair[] referenceArray; + private Integer[] valueArray; + + private String failReason; + + public Tester(int maxLength, int maxKeyCount) { + this.seed = 100000001; + this.keyArray = new GrailPair[maxLength]; + this.valueArray = new Integer[maxKeyCount]; } -} -public class Tester { + private int getRandomNumber(int key) { + this.seed = (this.seed * 1234565) + 1; + return (int) (((long) (this.seed & 0x7fffffff) * key) >> 31); + } + + private void generateTestArray(int start, int length, int keyCount) { + for(int i = 0; i < keyCount; i++) { + this.valueArray[i] = 0; + } + + for(int i = start; i < start + length; i++) { + if(keyCount != 0) { + int key = this.getRandomNumber(keyCount); + this.keyArray[i] = new GrailPair(key, this.valueArray[key]); + this.valueArray[key]++; + } + else { + this.keyArray[i] = new GrailPair(this.getRandomNumber(1000000000), 0); + } + } + } - public Tester() { - new HolyGrailSort(new GrailComparator()); + private boolean testArray(int start, int length, GrailComparator test) { + for(int i = start + 1; i < start + length; i++) { + int compare = test.compare(this.keyArray[i - 1], + this.keyArray[i ]); + if(compare > 0) { + this.failReason = "testArray[" + (i - 1) + "] and testArray[" + i + "] are out-of-order\n"; + return false; + } + else if(compare == 0 && this.keyArray[i - 1].getValue() > this.keyArray[i].getValue()) { + this.failReason = "testArray[" + (i - 1) + "] and testArray[" + i + "] are unstable\n"; + return false; + } + else if(!this.keyArray[i - 1].equals(this.referenceArray[i - 1])) { + this.failReason = "testArray[" + (i - 1) + "] does not match the reference array\n"; + return false; + } + } + return true; + } + + private void checkAlgorithm(int start, int length, int keyCount, boolean grailSort, int grailBufferType, String grailStrategy, GrailComparator test) throws SortFailedException { + this.generateTestArray(start, length, keyCount); + this.referenceArray = Arrays.copyOf(this.keyArray, start + length); + + String grailType = "w/o External Buffer"; + if(grailBufferType == 1) { + grailType = "w/ O(1) Buffer "; + } + else if(grailBufferType == 2) { + grailType = "w/ O(sqrt n) Buffer"; + } + + if(grailSort) { + System.out.println("\n* Grailsort " + grailType + ", " + grailStrategy + " \n* start = " + start + ", length = " + length + ", unique items = " + keyCount); + } + else { + System.out.println("\n* Arrays.sort (Timsort) \n* start = " + start + ", length = " + length + ", unique items = " + keyCount); + } + + long begin; + long time; + + if(grailSort) { + HolyGrailSort grail = new HolyGrailSort<>(test); + + GrailPair[] buffer = null; + int bufferLen = 0; + + // Grailsort with static buffer + if(grailBufferType == 1) { + buffer = (GrailPair[]) Array.newInstance(this.keyArray.getClass().getComponentType(), HolyGrailSort.STATIC_EXT_BUFFER_LEN); + bufferLen = HolyGrailSort.STATIC_EXT_BUFFER_LEN; + } + // Grailsort with dynamic buffer + else if(grailBufferType == 2) { + bufferLen = 1; + while((bufferLen * bufferLen) < length) { + bufferLen *= 2; + } + buffer = (GrailPair[]) Array.newInstance(this.keyArray.getClass().getComponentType(), bufferLen); + } + + begin = System.nanoTime(); + grail.commonSort(this.keyArray, start, length, buffer, bufferLen); + time = System.nanoTime() - begin; + } + else { + begin = System.nanoTime(); + Arrays.sort(this.keyArray, start, start + length, test); + time = System.nanoTime() - begin; + } + + System.out.print("- Sorted in " + time * 1e-6d + "ms..."); + Arrays.sort(this.referenceArray, start, start + length, test); + + boolean success = this.testArray(start, length, test); + if(success) { + System.out.print(" and the sort was successful!\n"); + } + else { + System.out.print(" but the sort was NOT successful!!\nReason: " + this.failReason); + throw new SortFailedException(); + } + + // Sometimes the garbage collector wasn't cooperating. + Arrays.fill(this.keyArray, null); + Arrays.fill(this.valueArray, null); + Arrays.fill(this.referenceArray, null); + System.gc(); + } + + private void checkBoth(int start, int length, int keyCount, String grailStrategy, GrailComparator test) throws SortFailedException { + int tempSeed = this.seed; + if(!grailStrategy.equals("Opti.Gnome")) { + for(int i = 0; i < 3; i++) { + this.checkAlgorithm(start, length, keyCount, true, i, grailStrategy, test); + this.seed = tempSeed; + } + } + else { + this.checkAlgorithm(start, length, keyCount, true, 0, grailStrategy, test); + this.seed = tempSeed; + } + + this.checkAlgorithm(start, length, keyCount, false, 0, null, test); } public static void main(String[] args) { - new Tester(); + int maxLength = 50000000; + int maxKeyCount = 25000000; + + Tester testClass = new Tester(maxLength, maxKeyCount); + GrailComparator testCompare = new GrailComparator(); + + System.out.println("Warming-up the JVM..."); + + try { + for(int u = 5; u <= (maxLength / 100); u *= 10) { + for(int v = 2; v <= u && v <= (maxKeyCount / 100); v *= 2) { + for(int i = 0; i < 3; i++) { + testClass.checkAlgorithm(0, u, v - 1, true, i, "All Strategies", testCompare); + } + } + } + + System.out.println("\n*** Testing Grailsort against Timsort ***"); + + testClass.checkBoth( 0, 15, 4, "Opti.Gnome", testCompare); + testClass.checkBoth( 0, 15, 8, "Opti.Gnome", testCompare); + testClass.checkBoth( 7, 8, 4, "Opti.Gnome", testCompare); + + testClass.checkBoth( 0, 1000000, 3, "Strategy 3", testCompare); + testClass.checkBoth( 0, 1000000, 1023, "Strategy 2", testCompare); + testClass.checkBoth( 0, 1000000, 500000, "Strategy 1", testCompare); + testClass.checkBoth( 500000, 500000, 3, "Strategy 3", testCompare); + testClass.checkBoth( 500000, 500000, 511, "Strategy 2", testCompare); + testClass.checkBoth( 500000, 500000, 250000, "Strategy 1", testCompare); + + testClass.checkBoth( 0, 10000000, 3, "Strategy 3", testCompare); + testClass.checkBoth( 0, 10000000, 4095, "Strategy 2", testCompare); + testClass.checkBoth( 0, 10000000, 5000000, "Strategy 1", testCompare); + testClass.checkBoth( 5000000, 5000000, 3, "Strategy 3", testCompare); + testClass.checkBoth( 5000000, 5000000, 2047, "Strategy 2", testCompare); + testClass.checkBoth( 5000000, 5000000, 2500000, "Strategy 1", testCompare); + + testClass.checkBoth( 0, 50000000, 3, "Strategy 3", testCompare); + testClass.checkBoth( 0, 50000000, 16383, "Strategy 2", testCompare); + testClass.checkBoth( 0, 50000000, 25000000, "Strategy 1", testCompare); + testClass.checkBoth(25000000, 25000000, 3, "Strategy 3", testCompare); + testClass.checkBoth(25000000, 25000000, 8191, "Strategy 2", testCompare); + testClass.checkBoth(25000000, 25000000, 12500000, "Strategy 1", testCompare); + + + testClass.checkBoth(25000000, 25000000, 12500000, "Strategy 1", testCompare); + testClass.checkBoth(25000000, 25000000, 8191, "Strategy 2", testCompare); + testClass.checkBoth(25000000, 25000000, 3, "Strategy 3", testCompare); + testClass.checkBoth( 0, 50000000, 25000000, "Strategy 1", testCompare); + testClass.checkBoth( 0, 50000000, 16383, "Strategy 2", testCompare); + testClass.checkBoth( 0, 50000000, 3, "Strategy 3", testCompare); + + testClass.checkBoth( 5000000, 5000000, 2500000, "Strategy 1", testCompare); + testClass.checkBoth( 5000000, 5000000, 2047, "Strategy 2", testCompare); + testClass.checkBoth( 5000000, 5000000, 3, "Strategy 3", testCompare); + testClass.checkBoth( 0, 10000000, 5000000, "Strategy 1", testCompare); + testClass.checkBoth( 0, 10000000, 4095, "Strategy 2", testCompare); + testClass.checkBoth( 0, 10000000, 3, "Strategy 3", testCompare); + + testClass.checkBoth( 500000, 500000, 250000, "Strategy 1", testCompare); + testClass.checkBoth( 500000, 500000, 511, "Strategy 2", testCompare); + testClass.checkBoth( 500000, 500000, 3, "Strategy 3", testCompare); + testClass.checkBoth( 0, 1000000, 500000, "Strategy 1", testCompare); + testClass.checkBoth( 0, 1000000, 1023, "Strategy 2", testCompare); + testClass.checkBoth( 0, 1000000, 3, "Strategy 3", testCompare); + + testClass.checkBoth( 7, 8, 4, "Opti.Gnome", testCompare); + testClass.checkBoth( 0, 15, 8, "Opti.Gnome", testCompare); + testClass.checkBoth( 0, 15, 4, "Opti.Gnome", testCompare); + + System.out.println("\nAll tests passed successfully!!"); + } catch (SortFailedException e) { + System.out.println("\nTesting failed!!\n"); + System.exit(1); + } } }