diff --git a/app/src/main/java/de/uni_marburg/powersort/FinnSort/FasterFinnSort.java b/app/src/main/java/de/uni_marburg/powersort/FinnSort/FasterFinnSort.java index 5e92f96..b1622ce 100644 --- a/app/src/main/java/de/uni_marburg/powersort/FinnSort/FasterFinnSort.java +++ b/app/src/main/java/de/uni_marburg/powersort/FinnSort/FasterFinnSort.java @@ -26,6 +26,7 @@ package de.uni_marburg.powersort.FinnSort; */ +import java.util.Arrays; import java.util.Comparator; import static java.lang.Math.pow; @@ -68,13 +69,13 @@ public class FasterFinnSort { * This is the minimum sized sequence that will be merged. Shorter * sequences will be lengthened by calling binarySort. If the entire * array is less than this length, no merges will be performed. - * + *

* This constant should be a power of two. It was 64 in Tim Peter's C * implementation, but 32 was empirically determined to work better in * this implementation. In the unlikely event that you set this constant * to be a number that's not a power of two, you'll need to change the * {@link #minRunLength} computation. - * + *

* If you decrease this constant, you must change the stackLen * computation in the TimSort constructor, or you risk an * ArrayOutOfBounds exception. See listsort.txt for a discussion @@ -87,6 +88,7 @@ public class FasterFinnSort { * The array being sorted. */ private final T[] a; + private final int rangeSize; /** * The comparator for this sort. @@ -97,7 +99,7 @@ public class FasterFinnSort { * When we get into galloping mode, we stay there until both runs win less * often than MIN_GALLOP consecutive times. */ - private static final int MIN_GALLOP = 7; + private static final int MIN_GALLOP = 7; /** * This controls when we get *into* galloping mode. It is initialized @@ -128,9 +130,9 @@ public class FasterFinnSort { * A stack of pending runs yet to be merged. Run i starts at * address base[i] and extends for len[i] elements. It's always * true (so long as the indices are in bounds) that: - * - * runBase[i] + runLen[i] == runBase[i + 1] - * + *

+ * runBase[i] + runLen[i] == runBase[i + 1] + *

* so we could cut the storage for this, but it's a minor amount, * and keeping all the info explicit simplifies the code. */ @@ -142,29 +144,28 @@ public class FasterFinnSort { /** * Creates a TimSort instance to maintain the state of an ongoing sort. * - * @param a the array to be sorted - * @param c the comparator to determine the order of the sort - * @param work a workspace array (slice) + * @param a the array to be sorted + * @param c the comparator to determine the order of the sort + * @param work a workspace array (slice) * @param workBase origin of usable space in work array - * @param workLen usable size of work array + * @param workLen usable size of work array */ - FasterFinnSort(T[] a, Comparator c, T[] work, int workBase, int workLen) { + FasterFinnSort(T[] a, Comparator c, T[] work, int workBase, int workLen, int rangeSize) { this.a = a; this.c = c; - + this.rangeSize = rangeSize; // Allocate temp storage (which may be increased later if necessary) int len = a.length; int tlen = (len < 2 * INITIAL_TMP_STORAGE_LENGTH) ? len >>> 1 : INITIAL_TMP_STORAGE_LENGTH; if (work == null || workLen < tlen || workBase + tlen > work.length) { @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"}) - T[] newArray = (T[])java.lang.reflect.Array.newInstance + T[] newArray = (T[]) java.lang.reflect.Array.newInstance (a.getClass().getComponentType(), tlen); tmp = newArray; tmpBase = 0; tmpLen = tlen; - } - else { + } else { tmp = work; tmpBase = workBase; tmpLen = workLen; @@ -204,24 +205,24 @@ public class FasterFinnSort { * any necessary array bounds checks and expanding parameters into * the required forms. * - * @param a the array to be sorted - * @param lo the index of the first element, inclusive, to be sorted - * @param hi the index of the last element, exclusive, to be sorted - * @param c the comparator to use - * @param work a workspace array (slice) + * @param a the array to be sorted + * @param lo the index of the first element, inclusive, to be sorted + * @param hi the index of the last element, exclusive, to be sorted + * @param c the comparator to use + * @param work a workspace array (slice) * @param workBase origin of usable space in work array - * @param workLen usable size of work array + * @param workLen usable size of work array * @since 1.8 */ public static void sort(T[] a, int lo, int hi, Comparator c, - T[] work, int workBase, int workLen) { + T[] work, int workBase, int workLen) { assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length; - - int nRemaining = hi - lo; + int nRemaining = hi - lo; if (nRemaining < 2) return; // Arrays of size 0 and 1 are always sorted // If array is small, do a "mini-TimSort" with no merges + if (nRemaining < MIN_MERGE) { int initRunLen = countRunAndMakeAscending(a, lo, hi, c); binarySort(a, lo, hi, lo + initRunLen, c); @@ -233,8 +234,8 @@ public class FasterFinnSort { * extending short natural runs to minRun elements, and merging runs * to maintain stack invariant. */ - FasterFinnSort ts = new FasterFinnSort<>(a, c, work, workBase, workLen); - int minRun = ts.minRunLength(nRemaining); + FasterFinnSort fs = new FasterFinnSort<>(a, c, work, workBase, workLen, hi - lo); + int minRun = fs.minRunLength(nRemaining); do { // Identify next run int runLen = countRunAndMakeAscending(a, lo, hi, c); @@ -247,8 +248,8 @@ public class FasterFinnSort { } // Push run onto pending-run stack, and maybe merge - ts.pushRun(lo, runLen, hi - lo); - ts.mergeCollapse(); + fs.pushRun(lo, runLen); + fs.mergeCollapse(); // Advance to find next run lo += runLen; @@ -257,8 +258,8 @@ public class FasterFinnSort { // Merge all remaining runs to complete sort assert lo == hi; - ts.mergeForceCollapse(); - assert ts.stackSize == 1; + fs.mergeForceCollapse(); + assert fs.stackSize == 1; } /** @@ -266,18 +267,18 @@ public class FasterFinnSort { * insertion sort. This is the best method for sorting small numbers * of elements. It requires O(n log n) compares, but O(n^2) data * movement (worst case). - * + *

* If the initial part of the specified range is already sorted, * this method can take advantage of it: the method assumes that the * elements from index {@code lo}, inclusive, to {@code start}, * exclusive are already sorted. * - * @param a the array in which a range is to be sorted - * @param lo the index of the first element in the range to be sorted - * @param hi the index after the last element in the range to be sorted + * @param a the array in which a range is to be sorted + * @param lo the index of the first element in the range to be sorted + * @param hi the index after the last element in the range to be sorted * @param start the index of the first element in the range that is - * not already known to be sorted ({@code lo <= start <= hi}) - * @param c comparator to used for the sort + * not already known to be sorted ({@code lo <= start <= hi}) + * @param c comparator to used for the sort */ @SuppressWarnings("fallthrough") static void binarySort(T[] a, int lo, int hi, int start, @@ -285,7 +286,7 @@ public class FasterFinnSort { assert lo <= start && start <= hi; if (start == lo) start++; - for ( ; start < hi; start++) { + for (; start < hi; start++) { T pivot = a[start]; // Set left (and right) to the index where a[start] (pivot) belongs @@ -329,26 +330,26 @@ public class FasterFinnSort { * Returns the length of the run beginning at the specified position in * the specified array and reverses the run if it is descending (ensuring * that the run will always be ascending when the method returns). - * + *

* A run is the longest ascending sequence with: - * - * a[lo] <= a[lo + 1] <= a[lo + 2] <= ... - * + *

+ * a[lo] <= a[lo + 1] <= a[lo + 2] <= ... + *

* or the longest descending sequence with: - * - * a[lo] > a[lo + 1] > a[lo + 2] > ... - * + *

+ * a[lo] > a[lo + 1] > a[lo + 2] > ... + *

* For its intended use in a stable mergesort, the strictness of the * definition of "descending" is needed so that the call can safely * reverse a descending sequence without violating stability. * - * @param a the array in which a run is to be counted and possibly reversed + * @param a the array in which a run is to be counted and possibly reversed * @param lo index of the first element in the run * @param hi index after the last element that may be contained in the run. - * It is required that {@code lo < hi}. - * @param c the comparator to used for the sort - * @return the length of the run beginning at the specified position in - * the specified array + * It is required that {@code lo < hi}. + * @param c the comparator to used for the sort + * @return the length of the run beginning at the specified position in + * the specified array */ static int countRunAndMakeAscending(T[] a, int lo, int hi, Comparator c) { @@ -373,7 +374,7 @@ public class FasterFinnSort { /** * Reverse the specified range of the specified array. * - * @param a the array in which a range is to be reversed + * @param a the array in which a range is to be reversed * @param lo the index of the first element in the range to be reversed * @param hi the index after the last element in the range to be reversed */ @@ -390,14 +391,14 @@ public class FasterFinnSort { * Returns the minimum acceptable run length for an array of the specified * length. Natural runs shorter than this will be extended with * {@link #binarySort}. - * + *

* Roughly speaking, the computation is: - * - * If n < MIN_MERGE, return n (it's too small to bother with fancy stuff). - * Else if n is an exact power of 2, return MIN_MERGE/2. - * Else return an int k, MIN_MERGE/2 <= k <= MIN_MERGE, such that n/k - * is close to, but strictly less than, an exact power of 2. - * + *

+ * If n < MIN_MERGE, return n (it's too small to bother with fancy stuff). + * Else if n is an exact power of 2, return MIN_MERGE/2. + * Else return an int k, MIN_MERGE/2 <= k <= MIN_MERGE, such that n/k + * is close to, but strictly less than, an exact power of 2. + *

* For the rationale, see listsort.txt. * * @param n the length of the array to be sorted @@ -419,24 +420,24 @@ public class FasterFinnSort { * @param runBase index of the first element in the run * @param runLen the number of elements in the run */ - void pushRun(int runBase, int runLen, int rangeSize) { + void pushRun(int runBase, int runLen) { this.runBase[stackSize] = runBase; this.runLen[stackSize] = runLen; - this.runPower[stackSize] = power(stackSize, rangeSize); + this.runPower[stackSize] = power(stackSize); stackSize++; } /** * Examines the stack of runs waiting to be merged and merges adjacent runs * until the stack invariants are reestablished: - * - * 1. runLen[i - 3] > runLen[i - 2] + runLen[i - 1] - * 2. runLen[i - 2] > runLen[i - 1] - * + *

+ * 1. runLen[i - 3] > runLen[i - 2] + runLen[i - 1] + * 2. runLen[i - 2] > runLen[i - 1] + *

* This method is called each time a new run is pushed onto the stack, * so the invariants are guaranteed to hold for i < stackSize upon * entry to the method. - * + *

* Thanks to Stijn de Gouw, Jurriaan Rot, Frank S. de Boer, * Richard Bubel and Reiner Hahnle, this is fixed with respect to * the analysis in "On the Worst-Case Complexity of TimSort" by @@ -444,16 +445,35 @@ public class FasterFinnSort { */ void mergeCollapse() { while (stackSize > 1) { - int n = stackSize - 2; - if (n > 0 && runPower[n + 1] < runPower[n]) { - mergeAt(n); + if (runPower[stackSize - 1] < runPower[stackSize - 2]) { + mergeAt(stackSize - 3); } else { break; // Invariant is established } } } - - int power(int stackSize, int rangeSize) { +/* + private int power(int stackSize) { + if (stackSize == 0) { + return 0; + } + // int = (right - left + 1); = RangeSize + long l = runLen[stackSize - 1]; // + (long) runBase[stackSize]; // - ((long) left << 1); // 2*middleA + long r = runLen[stackSize]; // - ((long) left << 1); // 2*middleB + int a = (int) ((l << 30) / rangeSize); // middleA / 2n + int b = (int) ((r << 30) / rangeSize); // middleB / 2n + return Integer.numberOfLeadingZeros(a ^ b); + } +*/ + int power(int stackSize) { + /* + System.out.println(Arrays.toString(runBase)); + System.out.println(Arrays.toString(runLen)); + System.out.println(Arrays.toString(runPower)); + System.out.println(stackSize); + System.out.println(rangeSize); + System.out.println(); + */ if (stackSize == 0) return 0; @@ -465,18 +485,50 @@ public class FasterFinnSort { int result = 0; - while (b < rangeSize) { + while (true) { ++result; if (a >= rangeSize) { a -= rangeSize; b -= rangeSize; } + if (b >= rangeSize) { + break; + } a <<= 1; b <<= 1; } return result; } +/* + public int power(int stackSize) { + + System.out.println(Arrays.toString(runBase)); + System.out.println(Arrays.toString(runLen)); + System.out.println(Arrays.toString(runPower)); + System.out.println(stackSize); + System.out.println(rangeSize); + System.out.println(); + + + if (stackSize == 0) + return 0; + + int n_1 = this.runLen[stackSize - 1]; + int n_2 = this.runLen[stackSize]; + + double a = ((double) this.runBase[stackSize - 1] + 0.5d * n_1 - 1d) / this.rangeSize; + double b = ((double) this.runBase[stackSize] + 0.5d * n_2 - 1d) / this.rangeSize; + int l = 0; + while ((int) (a * pow(2, l)) == (int) (b * pow(2 ,l))) { + + l++; + } + return l; + } + */ + + /* Backup mergeCollapse() von TimSort: @@ -519,7 +571,7 @@ public class FasterFinnSort { private void mergeAt(int i) { assert stackSize >= 2; assert i >= 0; - assert i == stackSize - 2 || i == stackSize - 3; + //assert i == stackSize - 3; int base1 = runBase[i]; int len1 = runLen[i]; @@ -533,12 +585,14 @@ public class FasterFinnSort { * run now, also slide over the last run (which isn't involved * in this merge). The current run (i+1) goes away in any case. */ - runLen[i] = len1 + len2; - if (i == stackSize - 3) { - runBase[i + 1] = runBase[i + 2]; - runLen[i + 1] = runLen[i + 2]; - } stackSize--; + runLen[i] = len1 + len2; + + // @TODO: Check power before pushing the run + runLen[i + 1] = runLen[i + 2]; + runBase[i + 1] = runBase[i + 2]; + runPower[i + 1] = runPower[i + 2]; + //runPower[i] = power(i); /* * Find where the first element of run2 goes in run1. Prior elements diff --git a/app/src/main/java/de/uni_marburg/powersort/FinnSort/Run.java b/app/src/main/java/de/uni_marburg/powersort/FinnSort/Run.java index eba6fc6..2a23c52 100644 --- a/app/src/main/java/de/uni_marburg/powersort/FinnSort/Run.java +++ b/app/src/main/java/de/uni_marburg/powersort/FinnSort/Run.java @@ -1,14 +1,16 @@ package de.uni_marburg.powersort.FinnSort; -class Run { - int start; - int end; +public class Run { + public int start; + public int end; int power; + public int len; public Run(int i, int j, int p) { start = i; end = j; power = p; + len = end - start; } } diff --git a/app/src/main/java/de/uni_marburg/powersort/MSort/IMPL_M_1.java b/app/src/main/java/de/uni_marburg/powersort/MSort/IMPL_M_1.java index 54b8ea4..4dc8dcd 100644 --- a/app/src/main/java/de/uni_marburg/powersort/MSort/IMPL_M_1.java +++ b/app/src/main/java/de/uni_marburg/powersort/MSort/IMPL_M_1.java @@ -1,6 +1,7 @@ package de.uni_marburg.powersort.MSort; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -29,9 +30,9 @@ public class IMPL_M_1 { */ protected static int MERGE_COST = 0; - public static void fillWithAscRunsHighToLow(List A, int[] runLengths, int runLenFactor) { + public static void fillWithAscRunsHighToLow(Integer[] A, int[] runLengths, int runLenFactor) { //A has a fixed size, but it doesn't have any meaningful values - int n = A.size(); + int n = A.length; //This ensures that the sum of runLengths multiplied by runLenFactor equals the list size n. If not, an AssertionError is thrown. assert IntStream.of(runLengths).sum() * runLenFactor == n; @@ -39,34 +40,59 @@ public class IMPL_M_1 { //IntStream.of(runLengths).forEach(System.out::println); for (int i = 0; i < n; i++) { //putting i in set a, while a is always the last index of n - A.set(i, n - i); + A[i] = n - i; } - int i = 0; + //For each value l in the array runLengths, do the following // runLengths = {2, 3, 5}, the loop will run three times, with l taking values 2, 3, and 5 respectively. + int startIndex = 0; for (int l : runLengths) { int L = l * runLenFactor; - List sublist = A.subList(i, i + L); - Collections.sort(sublist); - i += L; + // Sort the subarray from startIndex to startIndex+L manually + for (int i = startIndex; i < startIndex + L - 1; i++) { + for (int j = startIndex; j < startIndex + L - 1 - (i - startIndex); j++) { + if (A[j] > A[j + 1]) { + // Swap elements + int temp = A[j]; + A[j] = A[j + 1]; + A[j + 1] = temp; + } + } + } + startIndex += L; } } - static List merge(List run1, List run2, Comparator c) { - List result = new ArrayList<>(); - while (!run1.isEmpty() && !run2.isEmpty()) { + static T[] merge(T[] run1, T[] run2, Comparator c) { + /** + * We need this because: + * In Java, you cannot create generic arrays directly (can't write new T[size]) + * The workaround is to create an Object array and cast it to T[] + * This casting generates a warning because the compiler can't verify the type safety at runtime due to Java's type erasure + * **/ + @SuppressWarnings("unchecked") + T[] result = (T[]) new Object[run1.length + run2.length]; + int i = 0, j = 0, k = 0; + + while (i < run1.length && j < run2.length) { //This comparison only works if the lists are sorted - if (c.compare(run1.getFirst(),run2.getFirst()) < 0) { - result.add(run1.removeFirst()); + if (c.compare(run1[i], run2[j]) <= 0) { + result[k++] = run1[i++]; } else { - result.add(run2.removeFirst()); + result[k++] = run2[j++]; } } // can be improved by finding out which one is empty and only add the other one - result.addAll(run1); - result.addAll(run2); + // Copy remaining elements + while (i < run1.length) { + result[k++] = run1[i++]; + } + while (j < run2.length) { + result[k++] = run2[j++]; + } + return result; } @@ -85,9 +111,9 @@ public class IMPL_M_1 { } static void mergeInplace(T[] a, int i, int m, int j, Comparator c) { - // System.out.printf("Merge(%d, %d, %d)%n", i, m, j); + System.out.printf("Merge(%d, %d, %d)%n", i, m, j); MERGE_COST += j - i; -// Create temporary arrays for merging + // Create temporary arrays for merging @SuppressWarnings("unchecked") T[] left = (T[]) new Object[m - i]; @SuppressWarnings("unchecked") @@ -98,22 +124,11 @@ public class IMPL_M_1 { System.arraycopy(a, m, right, 0, j - m); // Merge back to original array - int k = i, l = 0, r = 0; - while (l < left.length && r < right.length) { - if (c.compare(left[l], right[r]) <= 0) { - a[k++] = left[l++]; - } else { - a[k++] = right[r++]; - } - } + // Merge the runs + T[] merged = merge(left, right, c); - // Copy remaining elements - while (l < left.length) { - a[k++] = left[l++]; - } - while (r < right.length) { - a[k++] = right[r++]; - } + //copy back to original array + System.arraycopy(merged, 0, a, i,merged.length); } diff --git a/app/src/main/java/de/uni_marburg/powersort/MSort/IMPL_M_2.java b/app/src/main/java/de/uni_marburg/powersort/MSort/IMPL_M_2.java index b892e84..a552fca 100644 --- a/app/src/main/java/de/uni_marburg/powersort/MSort/IMPL_M_2.java +++ b/app/src/main/java/de/uni_marburg/powersort/MSort/IMPL_M_2.java @@ -79,7 +79,7 @@ public class IMPL_M_2{ * of the minimum stack length required as a function of the length * of the array being sorted and the minimum merge sequence length. */ - private static final int MIN_MERGE = 24; + private static final int MIN_MERGE = 32; /** * The array being sorted. diff --git a/app/src/test/java/de/uni_marburg/powersort/MSort/PowerSortT.java b/app/src/test/java/de/uni_marburg/powersort/MSort/PowerSortT.java index feb81dc..0664717 100644 --- a/app/src/test/java/de/uni_marburg/powersort/MSort/PowerSortT.java +++ b/app/src/test/java/de/uni_marburg/powersort/MSort/PowerSortT.java @@ -7,6 +7,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import de.uni_marburg.powersort.benchmark.NaturalOrder; + public class PowerSortT { public static void main(String[] args) { @@ -22,7 +24,7 @@ public class PowerSortT { // Test for fillWithAscRunsHighToLow public static void testFillWithAscRunsHighToLow() { - List A = new ArrayList<>(Collections.nCopies(10, 0)); + Integer[] A = new Integer[10]; int[] runLengths = {2, 3, 5}; int runLenFactor = 1; fillWithAscRunsHighToLow(A, runLengths, runLenFactor); @@ -31,24 +33,24 @@ public class PowerSortT { // Test for merge public static void testMerge() { - List run1 = new ArrayList<>(Arrays.asList(1, 4, 6)); - List run2 = new ArrayList<>(Arrays.asList(2, 3, 5)); - // List result = merge(run1, run2); - // System.out.println("Test merge: " + result); + Integer[] run1 ={1,4,6}; + Integer []run2 = {2, 3, 5}; + Integer[] result = merge(run1, run2, NaturalOrder.INSTANCE); + System.out.println("Test merge: " + result); } // Test for mergeInplace public static void testMergeInplace() { - List A = new ArrayList<>(Arrays.asList(1, 4, 6, 2, 3, 5)); - //mergeInplace(A, 0, 3, 6); + Integer[] A = {1,4,6,2,3,5}; + mergeInplace(A, 0, 3, 6,NaturalOrder.INSTANCE); System.out.println("Test mergeInplace: " + A); } // Test for extendRun public static void testExtendRun() { - List A = new ArrayList<>(Arrays.asList(1, 2, 3, 6, 5, 4)); - // int endIndex = extendRun(A, 0); - // System.out.println("Test extendRun (from 0): " + endIndex); + Integer [] A = {1, 2, 3, 6, 5, 4}; + int endIndex = extendRun(A, 0,NaturalOrder.INSTANCE); + System.out.println("Test extendRun (from 0): " + endIndex); System.out.println("Modified List: " + A); } @@ -72,18 +74,18 @@ public class PowerSortT { // Test for mergeTopmost2 public static void testMergeTopmost2() { - List A = new ArrayList<>(Arrays.asList(1, 3, 5, 2, 4, 6)); + Integer[] A = {1, 3, 5, 2, 4, 6}; List runs = new ArrayList<>(); runs.add(new int[]{0, 3, 1}); runs.add(new int[]{3, 3, 1}); - // mergeTopmost2(A, runs); + mergeTopmost2(A, runs,NaturalOrder.INSTANCE); System.out.println("Test mergeTopmost2: " + A); } // Test for powerSort public static void testPowerSort() { - List A = new ArrayList<>(Arrays.asList(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)); - // powerSort(A); + Integer [] A = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; + powerSort(A, NaturalOrder.INSTANCE); System.out.println("Test powerSort: " + A); } } diff --git a/app/src/test/java/de/uni_marburg/powersort/MSort/PowerSortTest.java b/app/src/test/java/de/uni_marburg/powersort/MSort/PowerSortTest.java index 07d5ab6..134834e 100644 --- a/app/src/test/java/de/uni_marburg/powersort/MSort/PowerSortTest.java +++ b/app/src/test/java/de/uni_marburg/powersort/MSort/PowerSortTest.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; +import de.uni_marburg.powersort.benchmark.NaturalOrder; import org.junit.jupiter.api.Test; import static de.uni_marburg.powersort.MSort.IMPL_M_1.MERGE_COST; @@ -17,28 +18,30 @@ class PowerSortTest { public void testWithOneInputList() { // List list = new ArrayList<>(List.of(5, 2, 8, 12, 1, 6)); // extendRun(list, 0); -//System.out.println(list); + //System.out.println(list); // example from slides he wrote this - int[] runs = {5, 3, 3, 14, 1, 2}; - runs = new int[]{9, 16, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}; + // int[] runs = {5, 3, 3, 14, 1, 2}; + int [] runs = new int[]{9, 16, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}; + int totalSize = Arrays.stream(runs).sum(); - List a = new ArrayList<>(IntStream.range(0, Arrays.stream(runs).sum()).boxed().collect(Collectors.toList())); + Integer[] a = new Integer[totalSize]; - System.out.println(); - fillWithAscRunsHighToLow(a, runs, 1); - MERGE_COST = 0; - System.out.println("Sorting with Powersort:"); - //powerSort(a); - System.out.println("Merge cost: " + MERGE_COST); + System.out.println(); + fillWithAscRunsHighToLow(a, runs, 1); + MERGE_COST = 0; + System.out.println("Sorting with Powersort:"); + powerSort(a,NaturalOrder.INSTANCE); + System.out.println("Sorted Array"+Arrays.toString(a)); + System.out.println("Merge cost: " + MERGE_COST); } @Test - public void testWithFinnInputList() { - List numbers = List.of(new Integer[] {24, 25, 26, 27, 28, 21, 22, 23, 18, 19, 20, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 3, 1, 2}); - - // powerSort(numbers); - System.out.println("Result: "); - System.out.println(new ArrayList<>(List.of(numbers))); + public void testWithFinnInputList() { + Integer [] numbers = new Integer[] {24, 25, 26, 27, 28, 21, 22, 23, 18, 19, 20, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 3, 1, 2}; + System.out.println("Original array"+Arrays.toString(numbers)); + powerSort(numbers, NaturalOrder.INSTANCE); + System.out.println("Result: "+Arrays.toString(numbers)); + // System.out.println(new ArrayList<>(List.of(numbers))); } } diff --git a/app/src/test/java/de/uni_marburg/powersort/sort/FasterFinnSortTest.java b/app/src/test/java/de/uni_marburg/powersort/sort/FasterFinnSortTest.java index d050e33..ec99a0f 100644 --- a/app/src/test/java/de/uni_marburg/powersort/sort/FasterFinnSortTest.java +++ b/app/src/test/java/de/uni_marburg/powersort/sort/FasterFinnSortTest.java @@ -1,8 +1,77 @@ package de.uni_marburg.powersort.sort; +import de.uni_marburg.powersort.FinnSort.FasterFinnSort; +import de.uni_marburg.powersort.FinnSort.Run; +import de.uni_marburg.powersort.benchmark.NaturalOrder; +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Method; + +import static java.lang.Math.pow; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class FasterFinnSortTest extends AbstractSortTest { FasterFinnSortTest() { sortAlg = SortEnum.FASTER_FINN_SORT; } -} \ No newline at end of file + @Test + public void testMergeOrder() { + Integer[] input = {24,25,26,27,28,21,22,23,18,19,20,4,5,6,7,8,9,10,11,12,13,14,15,16,17,3,1,2}; + FasterFinnSort.sort(input, 0, input.length, NaturalOrder.INSTANCE,null, 0, 0); + } + @Test + public void powerTest() { + Run run1 = new Run(0, 10, 0); + Run run2 = new Run(10, 20, 0); + + for (int i = 20; i < 10100; i++) { + System.out.println(i); + //assertEquals(integerPower(run1, run2, i), power(run1, run2, i)); + assertEquals(power(run1, run2, i), + power2(run1, run2, i)); + } + + } + private static int integerPower(Run run1, Run run2, int n) { + + int n_1 = run1.len; + int n_2 = run2.len; + + int a = 2 * run1.start + n_1 - 1; + int b = a + n_1 + n_2; + + int result = 0; + + while (a * pow(2, result) == b * pow(2, result)) { + result++; + } + + return result; + } + private static int power(Run run1, Run run2, int n) { + /* + if (run1.start == 0) { + return 0; + } + + */ + int n_1 = run1.end - run1.start; + int n_2 = run2.end - run2.start; + double a = ((double) run1.start + 0.5d * n_1) / n; + double b = ((double) run2.start + 0.5d * n_2) / n; + int l = 1; + while ((int) (a * pow(2, l)) == (int) (b * pow(2 ,l))) { + l++; + } + return l; + } + + private int power2(Run run1, Run run2, int n) { + long l = (long) run1.start + (long) run2.start; // 2*middleA + long r = (long) run2.start + (long) run2.end + 1; // 2*middleB + int a = (int) ((l << 30) / n); // middleA / 2n + int b = (int) ((r << 30) / n); // middleB / 2n + return Integer.numberOfLeadingZeros(a ^ b); + } +}