From b0250b83faae21f6a9419f8bfff916cc854aed30 Mon Sep 17 00:00:00 2001 From: M-H9 Date: Tue, 10 Dec 2024 10:54:18 +0100 Subject: [PATCH 01/35] switched to my branch --- .vscode/settings.json | 3 +++ app/bin/main/de/uni_marburg/powersort/App.class | Bin 0 -> 700 bytes .../powersort/ComparableTimSort.class | Bin 0 -> 9818 bytes .../de/uni_marburg/powersort/PowerSort.class | Bin 0 -> 1652 bytes .../main/de/uni_marburg/powersort/TimSort.class | Bin 0 -> 10968 bytes .../test/de/uni_marburg/powersort/AppTest.class | Bin 0 -> 751 bytes 6 files changed, 3 insertions(+) create mode 100644 .vscode/settings.json create mode 100644 app/bin/main/de/uni_marburg/powersort/App.class create mode 100644 app/bin/main/de/uni_marburg/powersort/ComparableTimSort.class create mode 100644 app/bin/main/de/uni_marburg/powersort/PowerSort.class create mode 100644 app/bin/main/de/uni_marburg/powersort/TimSort.class create mode 100644 app/bin/test/de/uni_marburg/powersort/AppTest.class diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7b016a8 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.compile.nullAnalysis.mode": "automatic" +} \ No newline at end of file diff --git a/app/bin/main/de/uni_marburg/powersort/App.class b/app/bin/main/de/uni_marburg/powersort/App.class new file mode 100644 index 0000000000000000000000000000000000000000..2c43fac1548bca0ebe71dd1f7f98c27aee63f344 GIT binary patch literal 700 zcmaKp?MfR_5Qg6|(M{G>^I@#E)~;1+QqaACl$Ih`D4`Wn0@5GlY&@(-vb*8rY{k2( z{!mcx0=y`3PE3iS_~)IS+4*?p%+2lPHGmy#I+!3VAIKm})Sp=BFw;@cPmiS@q}l{u z`+Wy_Lg`5S6+urVQSdW7l3hcX`lJ$NJ`-~FMu(8!Ne`rp9Eu($F-4ebsYL$B;!x^e zBJ4>*rImI?uOqaw{wSC?hiX7rX}!eIBuq!reA7}Il|+R3dZRT)Y8%bbW&vf}NSe)o zAKHk&_kR)Jr2cnaVU9q|)Yp8+Pg z?KIO}xvT687x-S=b`-Z}Qa&+Q$sUB&VJ~1yY$rcnpm53`6L4AWZ>!U+-hBew8TQC7 z!fK1R*xI~YrSy-@!_vZo(%h)DhzhEs(l0{}pnQh;E71N0UZ3O5Io^<yAKmmw4`& Pql`7IbDXd-9Qol6`md0` literal 0 HcmV?d00001 diff --git a/app/bin/main/de/uni_marburg/powersort/ComparableTimSort.class b/app/bin/main/de/uni_marburg/powersort/ComparableTimSort.class new file mode 100644 index 0000000000000000000000000000000000000000..9f7d58fb15f9a65057ccc57b54766ea52cf8f15c GIT binary patch literal 9818 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 z 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 literal 0 HcmV?d00001 From e40a430a11e37dc1a95c4ed15c24942962f857be Mon Sep 17 00:00:00 2001 From: M-H9 Date: Tue, 10 Dec 2024 10:46:40 +0100 Subject: [PATCH 02/35] first Powersort successful implementation, Translation of the notebook. --- .idea/misc.xml | 4 +- .../java/de/uni_marburg/powersort/App.java | 8 + .../de/uni_marburg/powersort/PowerSort.java | 229 +++++++++++++++++- 3 files changed, 236 insertions(+), 5 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index a29a496..baddb10 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,5 +3,5 @@ - - + + \ No newline at end of file diff --git a/app/src/main/java/de/uni_marburg/powersort/App.java b/app/src/main/java/de/uni_marburg/powersort/App.java index 23e9332..fc8aa9e 100644 --- a/app/src/main/java/de/uni_marburg/powersort/App.java +++ b/app/src/main/java/de/uni_marburg/powersort/App.java @@ -3,6 +3,11 @@ */ package de.uni_marburg.powersort; +import java.util.ArrayList; +import java.util.List; + +import static de.uni_marburg.powersort.PowerSort.extendRun; + public class App { public String getGreeting() { return "Let's bring Powersort to Java!"; @@ -10,5 +15,8 @@ public class App { public static void main(String[] args) { System.out.println(new App().getGreeting()); + List list = new ArrayList<>(List.of(5, 2, 8, 12, 1, 6)); + extendRun(list, 0); + System.out.println(list); } } diff --git a/app/src/main/java/de/uni_marburg/powersort/PowerSort.java b/app/src/main/java/de/uni_marburg/powersort/PowerSort.java index 7c7f5fc..2152d71 100644 --- a/app/src/main/java/de/uni_marburg/powersort/PowerSort.java +++ b/app/src/main/java/de/uni_marburg/powersort/PowerSort.java @@ -1,6 +1,8 @@ package de.uni_marburg.powersort; -import java.util.Comparator; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; class PowerSort { /** @@ -19,8 +21,229 @@ class PowerSort { * @param workLen usable size of work array * @since 1.8 */ - static void sort(T[] a, int lo, int hi, Comparator c, + private static int MERGE_COST = 0; + + private static List merge(List run1, List run2) { + List result = new ArrayList<>(); + while (!run1.isEmpty() && !run2.isEmpty()) { + if (run1.get(0) < run2.get(0)) { + result.add(run1.remove(0)); + } else { + result.add(run2.remove(0)); + } + } + result.addAll(run1); + result.addAll(run2); + return result; + } + + private static void mergeInplace(List a, int i, int m, int j) { + System.out.printf("Merge(%d, %d, %d)%n", i, m, j); + MERGE_COST += j - i; + List sublist = merge( + new ArrayList<>(a.subList(i, m)), + new ArrayList<>(a.subList(m, j)) + ); + for (int k = 0; k < sublist.size(); k++) { + a.set(i + k, sublist.get(k)); + } + } + + static int extendRun(List a, int i) { + if (i == a.size() - 1) { + return i + 1; + } + int j = i + 1; + if (a.get(i) <= a.get(j)) { + while (j < a.size() && a.get(j - 1) <= a.get(j)) { + j++; + } + } else { + while (j < a.size() && a.get(j - 1) > a.get(j)) { + j++; + } + List sublist = a.subList(i, j); + Collections.reverse(sublist); + } + return j; + } + + private static int extendRunIncreasingOnly(List a, int i) { + if (i == a.size() - 1) { + return i + 1; + } + int j = i + 1; + while (j < a.size() && a.get(j - 1) <= a.get(j)) { + j++; + } + return j; + } + + public static int power(int[] run1, int[] run2, int n) { + int i1 = run1[0], n1 = run1[1]; + int i2 = run2[0], n2 = run2[1]; + + assert i1 >= 0; + assert i2 == i1 + n1; + assert n1 >= 1 && n2 >= 1; + assert i2 + n2 <= n; +// ask question about this whether it should be double or int + int a = (int) ((i1 + n1 / 2.0) / n); + int b = (int) ((i2 + n2 / 2.0) / n); + + int l = 0; + while (Math.floor(a * Math.pow(2, l)) == Math.floor(b * Math.pow(2, l))) { + l++; + } + return l; + } + + public static int powerFast(int[] run1, int[] run2, int n) { + int i1 = run1[0], n1 = run1[1]; + int i2 = run2[0], n2 = run2[1]; + + int a = 2 * i1 + n1; + int b = a + n1 + n2; + + int l = 0; + while (true) { + l++; + if (a >= n) { + assert b >= a; + a -= n; + b -= n; + } else if (b >= n) { + break; + } + assert a < b && b < n; + a <<= 1; + b <<= 1; + } + return l; + } + + public static void mergeTopmost2(List a, List runs) { + assert runs.size() >= 2; +// is this right? + int[] Y = runs.get(runs.size() - 2); + int[] Z = runs.get(runs.size() - 1); + + assert Z[0] == Y[0] + Y[1]; + + mergeInplace(a, Y[0], Z[0], Z[0] + Z[1]); + + runs.set(runs.size() - 2, new int[]{Y[0], Y[1] + Z[1], Y[2]}); + runs.remove(runs.size() - 1); + } + + public static void powerSort(List a) { + int n = a.size(); + int i = 0; + List runs = new ArrayList<>(); + + int j = extendRun(a, i); + runs.add(new int[]{i, j - i, 0}); + i = j; + + while (i < n) { + j = extendRun(a, i); + int p = power(runs.get(runs.size() - 1), new int[]{i, j - i}, n); + + while (p <= runs.get(runs.size() - 1)[2]) { + mergeTopmost2(a, runs); + } + + runs.add(new int[]{i, j - i, p}); + i = j; + } + + while (runs.size() >= 2) { + mergeTopmost2(a, runs); + } + } + } + +// // Example usage +// public static void main(String[] args) { +// List list = new ArrayList<>(List.of(5, 2, 8, 12, 1, 6)); +// extendRun(list, 0); +// System.out.println(list); +// } + + + + /* static void sort(T[] a, int lo, int hi, Comparator c, T[] work, int workBase, int workLen) { assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length; + }*/ +/* + public static final int MIN_MERGE=24; + public int mergeCost=0; + private final T []sortedArray; + + public PowerSort(T[] sortedArray) { + super(); + this.sortedArray = sortedArray; } -} \ No newline at end of file + + ArrayList run1 = new ArrayList<>(); + ArrayList run2 = new ArrayList<>(); + + private AbstractList merge(ArrayList run1, ArrayList run2) { + ArrayList result = new ArrayList<>(); + + while(run1.size() > 0 && run2.size() >0) { + if (run1.getFirst() Date: Tue, 10 Dec 2024 18:10:32 +0100 Subject: [PATCH 03/35] refactor --- .../main/java/de/uni_marburg/powersort/{ => sort}/ASort.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename app/src/main/java/de/uni_marburg/powersort/{ => sort}/ASort.java (99%) diff --git a/app/src/main/java/de/uni_marburg/powersort/ASort.java b/app/src/main/java/de/uni_marburg/powersort/sort/ASort.java similarity index 99% rename from app/src/main/java/de/uni_marburg/powersort/ASort.java rename to app/src/main/java/de/uni_marburg/powersort/sort/ASort.java index 20c1207..dbd4abe 100644 --- a/app/src/main/java/de/uni_marburg/powersort/ASort.java +++ b/app/src/main/java/de/uni_marburg/powersort/sort/ASort.java @@ -1,4 +1,4 @@ -package de.uni_marburg.powersort; +package de.uni_marburg.powersort.sort; import java.util.Comparator; import java.util.Stack; From 3f35d9bbfe543dd053377c8db35bb74519763a0c Mon Sep 17 00:00:00 2001 From: M-H9 Date: Tue, 10 Dec 2024 18:12:08 +0100 Subject: [PATCH 04/35] Created my branch folder for the merge --- .../Mohammed_Implementations/IMPL_M_1.java | 302 ++++++++++++++++++ .../java/de/uni_marburg/powersort/App.java | 22 -- .../de/uni_marburg/powersort/PowerSort.java | 229 +------------ .../de/uni_marburg/powersort/AppTest.java | 14 - .../uni_marburg/powersort/PowerSortTest.java | 37 +++ 5 files changed, 342 insertions(+), 262 deletions(-) create mode 100644 app/src/main/java/Mohammed_Implementations/IMPL_M_1.java delete mode 100644 app/src/main/java/de/uni_marburg/powersort/App.java delete mode 100644 app/src/test/java/de/uni_marburg/powersort/AppTest.java create mode 100644 app/src/test/java/de/uni_marburg/powersort/PowerSortTest.java diff --git a/app/src/main/java/Mohammed_Implementations/IMPL_M_1.java b/app/src/main/java/Mohammed_Implementations/IMPL_M_1.java new file mode 100644 index 0000000..03c69d6 --- /dev/null +++ b/app/src/main/java/Mohammed_Implementations/IMPL_M_1.java @@ -0,0 +1,302 @@ +package Mohammed_Implementations; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.IntStream; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.IntStream; +public class IMPL_M_1 { + + + + private IMPL_M_1() {} + + /** + * Sorts the given range, using the given workspace array slice + * for temp storage when possible. This method is designed to be + * invoked from public methods (in class Arrays) after performing + * 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 workBase origin of usable space in work array + * @param workLen usable size of work array + * @since 1.8 + */ + private static int MERGE_COST = 0; + + // Example usage +// int[] runs = new int[] {5, 3, 3, 14, 1, 2}; // example from slides +// //runs = new int[]{9, 16, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}; +// +// ArrayList a = new ArrayList<>(IntStream.range(0, Arrays.stream(runs).sum()).boxed().collect(Collectors.toList())); +// +// System.out.println(); +// fillWithAscRunsHighToLow(a, runs); +// MERGE_COST = 0; +// System.out.println("Sorting with Powersort:"); +// powersort(a, this::extendRunIncreasingOnly); +// System.out.println("Merge cost: " + MERGE_COST); + +// runs = [5,3,3,14,1,2]; +// runs = [9,16,7,7,7,7,7,7,7,7,7,7]; +// +// a = list(range(sum(runs))); +// fill_with_asc_runs_high_to_low(a, runs); +// MERGE_COST = 0; +// System.out.println("Sorting with Powersort:"); +// powersort(a, extendRunIncreasingOnly); +// System.out.println("Merge cost: " + MERGE_COST); + + + public static void fillWithAscRunsHighToLow(List A, int[] runLengths, int runLenFactor) { + int n = A.size(); + assert IntStream.of(runLengths).sum() * runLenFactor == n; + + for (int i = 0; i < n; i++) { + A.set(i, n - i); + } + + int i = 0; + for (int l : runLengths) { + int L = l * runLenFactor; + List sublist = A.subList(i, i + L); + Collections.sort(sublist); + i += L; + } + } + + private static List merge(List run1, List run2) { + List result = new ArrayList<>(); + while (!run1.isEmpty() && !run2.isEmpty()) { + if (run1.get(0) < run2.get(0)) { + result.add(run1.remove(0)); + } else { + result.add(run2.remove(0)); + } + } + result.addAll(run1); + result.addAll(run2); + return result; + } + + private static void mergeInplace(List a, int i, int m, int j) { + System.out.printf("Merge(%d, %d, %d)%n", i, m, j); + MERGE_COST += j - i; + List sublist = merge( + new ArrayList<>(a.subList(i, m)), + new ArrayList<>(a.subList(m, j)) + ); + for (int k = 0; k < sublist.size(); k++) { + a.set(i + k, sublist.get(k)); + } + } + + static int extendRun(List a, int i) { + if (i == a.size() - 1) { + return i + 1; + } + int j = i + 1; + if (a.get(i) <= a.get(j)) { + while (j < a.size() && a.get(j - 1) <= a.get(j)) { + j++; + } + } else { + while (j < a.size() && a.get(j - 1) > a.get(j)) { + j++; + } + List sublist = a.subList(i, j); + Collections.reverse(sublist); + } + return j; + } + + private static int extendRunIncreasingOnly(List a, int i) { + if (i == a.size() - 1) { + return i + 1; + } + int j = i + 1; + while (j < a.size() && a.get(j - 1) <= a.get(j)) { + j++; + } + return j; + } + + public static int power(int[] run1, int[] run2, int n) { + int i1 = run1[0], n1 = run1[1]; + int i2 = run2[0], n2 = run2[1]; + + assert i1 >= 0; + assert i2 == i1 + n1; + assert n1 >= 1 && n2 >= 1; + assert i2 + n2 <= n; + + double a = ((i1 + n1 / 2.0d) / n); + double b = ((i2 + n2 / 2.0d) / n); + + int l = 0; + while (Math.floor(a * Math.pow(2, l)) == Math.floor(b * Math.pow(2, l))) { + l++; + } + return l; + } + + public static int powerFast(int[] run1, int[] run2, int n) { + int i1 = run1[0], n1 = run1[1]; + int i2 = run2[0], n2 = run2[1]; + + int a = 2 * i1 + n1; + int b = a + n1 + n2; + + int l = 0; + while (true) { + l++; + if (a >= n) { + assert b >= a; + a -= n; + b -= n; + } else if (b >= n) { + break; + } + assert a < b && b < n; + a <<= 1; + b <<= 1; + } + return l; + } + + public static void mergeTopmost2(List a, List runs) { + assert runs.size() >= 2; + + int[] Y = runs.get(runs.size() - 2); + int[] Z = runs.get(runs.size() - 1); + + assert Z[0] == Y[0] + Y[1]; + + mergeInplace(a, Y[0], Z[0], Z[0] + Z[1]); + + runs.set(runs.size() - 2, new int[] {Y[0], Y[1] + Z[1], Y[2]}); + runs.remove(runs.size() - 1); + } + + public static void powerSort(List a) { + int n = a.size(); + int i = 0; + List runs = new ArrayList<>(); + + int j = extendRun(a, i); + runs.add(new int[] {i, j - i, 0}); + i = j; + + while (i < n) { + j = extendRun(a, i); + int p = power(runs.get(runs.size() - 1), new int[] {i, j - i}, n); + + while (p <= runs.get(runs.size() - 1)[2]) { + mergeTopmost2(a, runs); + } + + runs.add(new int[] {i, j - i, p}); + i = j; + } + + while (runs.size() >= 2) { + mergeTopmost2(a, runs); + } + } + + /* """Fills the given array A with ascending runs of the given list of run + lengths. + More precisely, the array is first filled n, n-1, ..., 1 + and then for i=0..l-1 segments of runLengths.get(i) * runLenFactor + are sorted ascending. + The sum of all lengths in runLengths times runLenFactor should be equal to the + length of A. + """*/ + + + /* static void sort(T[] a, int lo, int hi, Comparator c, + T[] work, int workBase, int workLen) { + assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length; + }*/ +/* + public static final int MIN_MERGE=24; + public int mergeCost=0; + private final T []sortedArray; + + public PowerSort(T[] sortedArray) { + super(); + this.sortedArray = sortedArray; + } + + ArrayList run1 = new ArrayList<>(); + ArrayList run2 = new ArrayList<>(); + + private AbstractList merge(ArrayList run1, ArrayList run2) { + ArrayList result = new ArrayList<>(); + + while(run1.size() > 0 && run2.size() >0) { + if (run1.getFirst() list = new ArrayList<>(List.of(5, 2, 8, 12, 1, 6)); - extendRun(list, 0); - System.out.println(list); - } -} diff --git a/app/src/main/java/de/uni_marburg/powersort/PowerSort.java b/app/src/main/java/de/uni_marburg/powersort/PowerSort.java index 2152d71..39916ad 100644 --- a/app/src/main/java/de/uni_marburg/powersort/PowerSort.java +++ b/app/src/main/java/de/uni_marburg/powersort/PowerSort.java @@ -1,8 +1,6 @@ package de.uni_marburg.powersort; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.Comparator; class PowerSort { /** @@ -21,229 +19,8 @@ class PowerSort { * @param workLen usable size of work array * @since 1.8 */ - private static int MERGE_COST = 0; - - private static List merge(List run1, List run2) { - List result = new ArrayList<>(); - while (!run1.isEmpty() && !run2.isEmpty()) { - if (run1.get(0) < run2.get(0)) { - result.add(run1.remove(0)); - } else { - result.add(run2.remove(0)); - } - } - result.addAll(run1); - result.addAll(run2); - return result; - } - - private static void mergeInplace(List a, int i, int m, int j) { - System.out.printf("Merge(%d, %d, %d)%n", i, m, j); - MERGE_COST += j - i; - List sublist = merge( - new ArrayList<>(a.subList(i, m)), - new ArrayList<>(a.subList(m, j)) - ); - for (int k = 0; k < sublist.size(); k++) { - a.set(i + k, sublist.get(k)); - } - } - - static int extendRun(List a, int i) { - if (i == a.size() - 1) { - return i + 1; - } - int j = i + 1; - if (a.get(i) <= a.get(j)) { - while (j < a.size() && a.get(j - 1) <= a.get(j)) { - j++; - } - } else { - while (j < a.size() && a.get(j - 1) > a.get(j)) { - j++; - } - List sublist = a.subList(i, j); - Collections.reverse(sublist); - } - return j; - } - - private static int extendRunIncreasingOnly(List a, int i) { - if (i == a.size() - 1) { - return i + 1; - } - int j = i + 1; - while (j < a.size() && a.get(j - 1) <= a.get(j)) { - j++; - } - return j; - } - - public static int power(int[] run1, int[] run2, int n) { - int i1 = run1[0], n1 = run1[1]; - int i2 = run2[0], n2 = run2[1]; - - assert i1 >= 0; - assert i2 == i1 + n1; - assert n1 >= 1 && n2 >= 1; - assert i2 + n2 <= n; -// ask question about this whether it should be double or int - int a = (int) ((i1 + n1 / 2.0) / n); - int b = (int) ((i2 + n2 / 2.0) / n); - - int l = 0; - while (Math.floor(a * Math.pow(2, l)) == Math.floor(b * Math.pow(2, l))) { - l++; - } - return l; - } - - public static int powerFast(int[] run1, int[] run2, int n) { - int i1 = run1[0], n1 = run1[1]; - int i2 = run2[0], n2 = run2[1]; - - int a = 2 * i1 + n1; - int b = a + n1 + n2; - - int l = 0; - while (true) { - l++; - if (a >= n) { - assert b >= a; - a -= n; - b -= n; - } else if (b >= n) { - break; - } - assert a < b && b < n; - a <<= 1; - b <<= 1; - } - return l; - } - - public static void mergeTopmost2(List a, List runs) { - assert runs.size() >= 2; -// is this right? - int[] Y = runs.get(runs.size() - 2); - int[] Z = runs.get(runs.size() - 1); - - assert Z[0] == Y[0] + Y[1]; - - mergeInplace(a, Y[0], Z[0], Z[0] + Z[1]); - - runs.set(runs.size() - 2, new int[]{Y[0], Y[1] + Z[1], Y[2]}); - runs.remove(runs.size() - 1); - } - - public static void powerSort(List a) { - int n = a.size(); - int i = 0; - List runs = new ArrayList<>(); - - int j = extendRun(a, i); - runs.add(new int[]{i, j - i, 0}); - i = j; - - while (i < n) { - j = extendRun(a, i); - int p = power(runs.get(runs.size() - 1), new int[]{i, j - i}, n); - - while (p <= runs.get(runs.size() - 1)[2]) { - mergeTopmost2(a, runs); - } - - runs.add(new int[]{i, j - i, p}); - i = j; - } - - while (runs.size() >= 2) { - mergeTopmost2(a, runs); - } - } - } - -// // Example usage -// public static void main(String[] args) { -// List list = new ArrayList<>(List.of(5, 2, 8, 12, 1, 6)); -// extendRun(list, 0); -// System.out.println(list); -// } - - - - /* static void sort(T[] a, int lo, int hi, Comparator c, + static void sort(T[] a, int lo, int hi, Comparator c, T[] work, int workBase, int workLen) { assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length; - }*/ -/* - public static final int MIN_MERGE=24; - public int mergeCost=0; - private final T []sortedArray; - - public PowerSort(T[] sortedArray) { - super(); - this.sortedArray = sortedArray; } - - ArrayList run1 = new ArrayList<>(); - ArrayList run2 = new ArrayList<>(); - - private AbstractList merge(ArrayList run1, ArrayList run2) { - ArrayList result = new ArrayList<>(); - - while(run1.size() > 0 && run2.size() >0) { - if (run1.getFirst() list = new ArrayList<>(List.of(5, 2, 8, 12, 1, 6)); + extendRun(list, 0); + 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}; + + List a = new ArrayList<>(IntStream.range(0, Arrays.stream(runs).sum()).boxed().collect(Collectors.toList())); + + 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); + } + + } \ No newline at end of file From b16ef90b8c1fd47696fb4def9ac51f031d62c5b7 Mon Sep 17 00:00:00 2001 From: Daniel Langbein Date: Tue, 10 Dec 2024 21:38:56 +0000 Subject: [PATCH 05/35] FinnSort: public access --- .../main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java b/app/src/main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java index ac9a591..ad7e189 100644 --- a/app/src/main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java +++ b/app/src/main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java @@ -7,7 +7,7 @@ public class FinnSort { private static final ArrayList runs = new ArrayList<>(); - static void sort(Integer[] a) { + public static void sort(Integer[] a) { int n = a.length; int i = 0; From d4fd68fa70fa0be78c4b6153ec327eda0cab113f Mon Sep 17 00:00:00 2001 From: M-H9 Date: Wed, 11 Dec 2024 11:55:31 +0100 Subject: [PATCH 06/35] Refactor package structure and update visibility modifier. Renamed packages to follow a consistent naming convention (`de.uni_marburg.powersort.msort`). Adjusted imports and references accordingly. Changed `MERGE_COST` visibility from private to protected for broader accessibility. --- .idea/misc.xml | 2 +- .../uni_marburg/powersort/msort}/IMPL_M_1.java | 8 ++------ .../powersort/{ => msort}/PowerSortTest.java | 10 +++++----- 3 files changed, 8 insertions(+), 12 deletions(-) rename app/src/main/java/{Mohammed_Implementations => de/uni_marburg/powersort/msort}/IMPL_M_1.java (97%) rename app/src/test/java/de/uni_marburg/powersort/{ => msort}/PowerSortTest.java (74%) diff --git a/.idea/misc.xml b/.idea/misc.xml index baddb10..122ba17 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/app/src/main/java/Mohammed_Implementations/IMPL_M_1.java b/app/src/main/java/de/uni_marburg/powersort/msort/IMPL_M_1.java similarity index 97% rename from app/src/main/java/Mohammed_Implementations/IMPL_M_1.java rename to app/src/main/java/de/uni_marburg/powersort/msort/IMPL_M_1.java index 03c69d6..0d0f25d 100644 --- a/app/src/main/java/Mohammed_Implementations/IMPL_M_1.java +++ b/app/src/main/java/de/uni_marburg/powersort/msort/IMPL_M_1.java @@ -1,14 +1,10 @@ -package Mohammed_Implementations; +package de.uni_marburg.powersort.msort; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.IntStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.stream.IntStream; public class IMPL_M_1 { @@ -31,7 +27,7 @@ public class IMPL_M_1 { * @param workLen usable size of work array * @since 1.8 */ - private static int MERGE_COST = 0; + protected static int MERGE_COST = 0; // Example usage // int[] runs = new int[] {5, 3, 3, 14, 1, 2}; // example from slides diff --git a/app/src/test/java/de/uni_marburg/powersort/PowerSortTest.java b/app/src/test/java/de/uni_marburg/powersort/msort/PowerSortTest.java similarity index 74% rename from app/src/test/java/de/uni_marburg/powersort/PowerSortTest.java rename to app/src/test/java/de/uni_marburg/powersort/msort/PowerSortTest.java index 7c466ef..dc2bfa5 100644 --- a/app/src/test/java/de/uni_marburg/powersort/PowerSortTest.java +++ b/app/src/test/java/de/uni_marburg/powersort/msort/PowerSortTest.java @@ -1,4 +1,4 @@ -package de.uni_marburg.powersort; +package de.uni_marburg.powersort.msort; import java.util.ArrayList; import java.util.Arrays; @@ -8,10 +8,10 @@ import java.util.stream.IntStream; import org.junit.jupiter.api.Test; -import static Mohammed_Implementations.PowerSort.MERGE_COST; -import static Mohammed_Implementations.PowerSort.extendRun; -import static Mohammed_Implementations.PowerSort.fillWithAscRunsHighToLow; -import static Mohammed_Implementations.PowerSort.powerSort; +import static de.uni_marburg.powersort.msort.IMPL_M_1.MERGE_COST; +import static de.uni_marburg.powersort.msort.IMPL_M_1.extendRun; +import static de.uni_marburg.powersort.msort.IMPL_M_1.fillWithAscRunsHighToLow; +import static de.uni_marburg.powersort.msort.IMPL_M_1.powerSort; class PowerSortTest { @Test From 18c27e2ea05c07f519939411f6819664716b9d9a Mon Sep 17 00:00:00 2001 From: M-H9 Date: Wed, 11 Dec 2024 12:00:37 +0100 Subject: [PATCH 07/35] Remove .vscode/settings.json from the repository The file likely contained editor-specific configurations that are unrelated to the source code. Removing it helps prevent unintentional overrides of personal developer settings and keeps the repository cleaner. --- .vscode/settings.json | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 7b016a8..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "java.compile.nullAnalysis.mode": "automatic" -} \ No newline at end of file From ebff5b6dc513f967e722ada4816aa47671409386 Mon Sep 17 00:00:00 2001 From: M-H9 Date: Wed, 11 Dec 2024 14:04:46 +0100 Subject: [PATCH 08/35] add app/bin to .gitignore --- .gitignore | 1 + app/bin/main/de/uni_marburg/powersort/App.class | Bin 700 -> 0 bytes .../powersort/ComparableTimSort.class | Bin 9818 -> 0 bytes .../de/uni_marburg/powersort/PowerSort.class | Bin 1652 -> 0 bytes .../main/de/uni_marburg/powersort/TimSort.class | Bin 10968 -> 0 bytes .../test/de/uni_marburg/powersort/AppTest.class | Bin 751 -> 0 bytes 6 files changed, 1 insertion(+) delete mode 100644 app/bin/main/de/uni_marburg/powersort/App.class delete mode 100644 app/bin/main/de/uni_marburg/powersort/ComparableTimSort.class delete mode 100644 app/bin/main/de/uni_marburg/powersort/PowerSort.class delete mode 100644 app/bin/main/de/uni_marburg/powersort/TimSort.class delete mode 100644 app/bin/test/de/uni_marburg/powersort/AppTest.class diff --git a/.gitignore b/.gitignore index f72df32..7f936b2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /.idea +/app/bin/ # Ignore Gradle project-specific cache directory /.gradle diff --git a/app/bin/main/de/uni_marburg/powersort/App.class b/app/bin/main/de/uni_marburg/powersort/App.class deleted file mode 100644 index 2c43fac1548bca0ebe71dd1f7f98c27aee63f344..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 700 zcmaKp?MfR_5Qg6|(M{G>^I@#E)~;1+QqaACl$Ih`D4`Wn0@5GlY&@(-vb*8rY{k2( z{!mcx0=y`3PE3iS_~)IS+4*?p%+2lPHGmy#I+!3VAIKm})Sp=BFw;@cPmiS@q}l{u z`+Wy_Lg`5S6+urVQSdW7l3hcX`lJ$NJ`-~FMu(8!Ne`rp9Eu($F-4ebsYL$B;!x^e zBJ4>*rImI?uOqaw{wSC?hiX7rX}!eIBuq!reA7}Il|+R3dZRT)Y8%bbW&vf}NSe)o zAKHk&_kR)Jr2cnaVU9q|)Yp8+Pg z?KIO}xvT687x-S=b`-Z}Qa&+Q$sUB&VJ~1yY$rcnpm53`6L4AWZ>!U+-hBew8TQC7 z!fK1R*xI~YrSy-@!_vZo(%h)DhzhEs(l0{}pnQh;E71N0UZ3O5Io^<yAKmmw4`& Pql`7IbDXd-9Qol6`md0` diff --git a/app/bin/main/de/uni_marburg/powersort/ComparableTimSort.class b/app/bin/main/de/uni_marburg/powersort/ComparableTimSort.class deleted file mode 100644 index 9f7d58fb15f9a65057ccc57b54766ea52cf8f15c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9818 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 z 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 From e627c99b55b7c0eec332bf828e96ea3770d29082 Mon Sep 17 00:00:00 2001 From: Daniel Langbein Date: Wed, 11 Dec 2024 15:40:50 +0000 Subject: [PATCH 09/35] benchmark: doc --- .../java/de/uni_marburg/powersort/benchmark/BenchmarkJmh.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/BenchmarkJmh.java b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/BenchmarkJmh.java index 77ea4d6..d4ebd95 100644 --- a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/BenchmarkJmh.java +++ b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/BenchmarkJmh.java @@ -13,6 +13,10 @@ import java.util.concurrent.TimeUnit; @Warmup(iterations = 3) @Measurement(iterations = 6) public class BenchmarkJmh { + /** + * Quote from JMH: + * State objects naturally encapsulate the state on which benchmark is working on. + */ @State(Scope.Benchmark) public static class State1 { RandomIntegers d = new RandomIntegers(); From 684f28bb2b01340884cc3ddbc6ad0f70d7604f0c Mon Sep 17 00:00:00 2001 From: Daniel Langbein Date: Wed, 11 Dec 2024 16:08:49 +0000 Subject: [PATCH 10/35] benchmark: refactor --- .../powersort/benchmark/BenchmarkJmh.java | 56 +++++++++---------- .../uni_marburg/powersort/benchmark/Main.java | 2 +- .../powersort/data/IntegerSupplier.java | 4 +- .../powersort/data/ObjectSupplier.java | 2 +- 4 files changed, 31 insertions(+), 33 deletions(-) diff --git a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/BenchmarkJmh.java b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/BenchmarkJmh.java index d4ebd95..09b1685 100644 --- a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/BenchmarkJmh.java +++ b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/BenchmarkJmh.java @@ -9,45 +9,43 @@ import org.openjdk.jmh.annotations.*; import java.util.concurrent.TimeUnit; // TODO: The parameters are way too low. Use for debugging only! -@Fork(1) -@Warmup(iterations = 3) -@Measurement(iterations = 6) +/* + * Benchmark parameters + */ +@Fork(0) +@Warmup(iterations = 0) +@Measurement(iterations = 1) +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +/* + * Benchmark state parameters + * + * Quote from JMH: + * State objects naturally encapsulate the state on which benchmark is working on. + */ +@State(Scope.Benchmark) public class BenchmarkJmh { - /** - * Quote from JMH: - * State objects naturally encapsulate the state on which benchmark is working on. - */ - @State(Scope.Benchmark) - public static class State1 { - RandomIntegers d = new RandomIntegers(); - Integer[] a; + private final RandomIntegers readonly = new RandomIntegers(); + /* package-protected */ Integer[] array; - // TODO: This is inaccurate. - // How to create and use separate arrays for each warmup x iteration x sortAlgorithm ? - @Setup(Level.Invocation) - public void setup() { - a = d.get(); - } + // TODO: This is inaccurate. How to create and use separate arrays for each warmup x iteration x sortAlgorithm ? + @Setup(Level.Invocation) + public void setup() { + array = readonly.getCopy(); } - @BenchmarkMode(Mode.AverageTime) - @OutputTimeUnit(TimeUnit.MILLISECONDS) @Benchmark - public void rand1DummySort(State1 s) { - DummySort.sort(s.a, 0, s.a.length, NaturalOrder.INSTANCE, null, 0, 0); + public void rand1DummySort() { + DummySort.sort(array, 0, array.length, NaturalOrder.INSTANCE, null, 0, 0); } - @BenchmarkMode(Mode.AverageTime) - @OutputTimeUnit(TimeUnit.MILLISECONDS) @Benchmark - public void rand1TimSort(State1 s) { - TimSort.sort(s.a, 0, s.a.length, NaturalOrder.INSTANCE, null, 0, 0); + public void rand1TimSort() { + TimSort.sort(array, 0, array.length, NaturalOrder.INSTANCE, null, 0, 0); } - @BenchmarkMode(Mode.AverageTime) - @OutputTimeUnit(TimeUnit.MILLISECONDS) @Benchmark - public void rand1MergeSort(State1 s) { - MergeSort.legacyMergeSort(s.a, NaturalOrder.INSTANCE); + public void rand1MergeSort() { + MergeSort.legacyMergeSort(array, NaturalOrder.INSTANCE); } } diff --git a/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java b/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java index b4a5c48..59d8848 100644 --- a/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java +++ b/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java @@ -25,7 +25,7 @@ public class Main { System.out.println("\n" + objectSupplier.title()); for (SortImpl sortImplementation : sortImplementations) { - Object[] sortInput = objectSupplier.get(); + Object[] sortInput = objectSupplier.getCopy(); final long startNanos = System.nanoTime(); sortImplementation.sort(sortInput); diff --git a/app/src/main/java/de/uni_marburg/powersort/data/IntegerSupplier.java b/app/src/main/java/de/uni_marburg/powersort/data/IntegerSupplier.java index 3e0f392..f1727d7 100644 --- a/app/src/main/java/de/uni_marburg/powersort/data/IntegerSupplier.java +++ b/app/src/main/java/de/uni_marburg/powersort/data/IntegerSupplier.java @@ -6,7 +6,7 @@ public abstract class IntegerSupplier extends ObjectSupplier { } @Override - public Integer[] get() { - return (Integer[]) super.get(); + public Integer[] getCopy() { + return (Integer[]) super.getCopy(); } } diff --git a/app/src/main/java/de/uni_marburg/powersort/data/ObjectSupplier.java b/app/src/main/java/de/uni_marburg/powersort/data/ObjectSupplier.java index 6ddd7b7..f191abc 100644 --- a/app/src/main/java/de/uni_marburg/powersort/data/ObjectSupplier.java +++ b/app/src/main/java/de/uni_marburg/powersort/data/ObjectSupplier.java @@ -17,7 +17,7 @@ public abstract class ObjectSupplier { /** * @return A fresh copy of the array of objects represented by this object. */ - public Object[] get(){ + public Object[] getCopy(){ return Arrays.copyOf(readOnly, readOnly.length); } } From 605d0c278161e1704a9e1ad7c4adca72379968a4 Mon Sep 17 00:00:00 2001 From: Daniel Langbein Date: Wed, 11 Dec 2024 16:25:47 +0000 Subject: [PATCH 11/35] benchmark: refactor --- ...nchmarkJmh.java => AbstractBenchmark.java} | 22 ++++++------------- .../benchmark/DummySortBenchmark.java | 10 +++++++++ .../benchmark/MergeSortBenchmark.java | 10 +++++++++ 3 files changed, 27 insertions(+), 15 deletions(-) rename app/src/jmh/java/de/uni_marburg/powersort/benchmark/{BenchmarkJmh.java => AbstractBenchmark.java} (62%) create mode 100644 app/src/jmh/java/de/uni_marburg/powersort/benchmark/DummySortBenchmark.java create mode 100644 app/src/jmh/java/de/uni_marburg/powersort/benchmark/MergeSortBenchmark.java diff --git a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/BenchmarkJmh.java b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/AbstractBenchmark.java similarity index 62% rename from app/src/jmh/java/de/uni_marburg/powersort/benchmark/BenchmarkJmh.java rename to app/src/jmh/java/de/uni_marburg/powersort/benchmark/AbstractBenchmark.java index 09b1685..8603207 100644 --- a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/BenchmarkJmh.java +++ b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/AbstractBenchmark.java @@ -1,8 +1,5 @@ package de.uni_marburg.powersort.benchmark; -import de.uni_marburg.powersort.sort.DummySort; -import de.uni_marburg.powersort.sort.MergeSort; -import de.uni_marburg.powersort.sort.TimSort; import de.uni_marburg.powersort.data.RandomIntegers; import org.openjdk.jmh.annotations.*; @@ -24,7 +21,7 @@ import java.util.concurrent.TimeUnit; * State objects naturally encapsulate the state on which benchmark is working on. */ @State(Scope.Benchmark) -public class BenchmarkJmh { +public abstract class AbstractBenchmark { private final RandomIntegers readonly = new RandomIntegers(); /* package-protected */ Integer[] array; @@ -35,17 +32,12 @@ public class BenchmarkJmh { } @Benchmark - public void rand1DummySort() { - DummySort.sort(array, 0, array.length, NaturalOrder.INSTANCE, null, 0, 0); + public void benchmark() { + sort(); } - @Benchmark - public void rand1TimSort() { - TimSort.sort(array, 0, array.length, NaturalOrder.INSTANCE, null, 0, 0); - } - - @Benchmark - public void rand1MergeSort() { - MergeSort.legacyMergeSort(array, NaturalOrder.INSTANCE); - } + /** + * Sorts this.array with some sorting algorithm. + */ + /* package-protected */ abstract void sort(); } diff --git a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/DummySortBenchmark.java b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/DummySortBenchmark.java new file mode 100644 index 0000000..3bb2bf9 --- /dev/null +++ b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/DummySortBenchmark.java @@ -0,0 +1,10 @@ +package de.uni_marburg.powersort.benchmark; + +import de.uni_marburg.powersort.sort.DummySort; + +public class DummySortBenchmark extends AbstractBenchmark { + @Override + public void sort() { + DummySort.sort(array, 0, array.length, NaturalOrder.INSTANCE, null, 0, 0); + } +} diff --git a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/MergeSortBenchmark.java b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/MergeSortBenchmark.java new file mode 100644 index 0000000..75e4eb6 --- /dev/null +++ b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/MergeSortBenchmark.java @@ -0,0 +1,10 @@ +package de.uni_marburg.powersort.benchmark; + +import de.uni_marburg.powersort.sort.MergeSort; + +public class MergeSortBenchmark extends AbstractBenchmark { + @Override + public void sort() { + MergeSort.legacyMergeSort(array, NaturalOrder.INSTANCE); + } +} From 904d462fc681b09098e99aeee46a94f9e2f176e7 Mon Sep 17 00:00:00 2001 From: Daniel Langbein Date: Wed, 11 Dec 2024 17:08:01 +0000 Subject: [PATCH 12/35] benchmark: @Param & DataEnum --- .../benchmark/AbstractBenchmark.java | 32 ++++++++++++++--- .../benchmark/DummySortBenchmark.java | 2 +- .../benchmark/MergeSortBenchmark.java | 2 +- .../powersort/benchmark/IntegerArray.java | 30 ++++++++++++---- .../uni_marburg/powersort/benchmark/Main.java | 34 ++++++++----------- .../powersort/data/AscendingIntegers.java | 17 ++++++++++ .../uni_marburg/powersort/data/DataEnum.java | 15 ++++++++ .../powersort/data/ObjectSupplier.java | 2 +- 8 files changed, 100 insertions(+), 34 deletions(-) create mode 100644 app/src/main/java/de/uni_marburg/powersort/data/AscendingIntegers.java create mode 100644 app/src/main/java/de/uni_marburg/powersort/data/DataEnum.java diff --git a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/AbstractBenchmark.java b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/AbstractBenchmark.java index 8603207..2be81c0 100644 --- a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/AbstractBenchmark.java +++ b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/AbstractBenchmark.java @@ -1,7 +1,19 @@ package de.uni_marburg.powersort.benchmark; -import de.uni_marburg.powersort.data.RandomIntegers; -import org.openjdk.jmh.annotations.*; +import de.uni_marburg.powersort.data.DataEnum; +import de.uni_marburg.powersort.data.ObjectSupplier; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; import java.util.concurrent.TimeUnit; @@ -22,13 +34,23 @@ import java.util.concurrent.TimeUnit; */ @State(Scope.Benchmark) public abstract class AbstractBenchmark { - private final RandomIntegers readonly = new RandomIntegers(); - /* package-protected */ Integer[] array; + @Param() + private DataEnum dataEnum; + + private DataEnum prevDataEnum = null; + private ObjectSupplier data; + + /* package-protected */ Object[] workingCopy; // TODO: This is inaccurate. How to create and use separate arrays for each warmup x iteration x sortAlgorithm ? @Setup(Level.Invocation) public void setup() { - array = readonly.getCopy(); + if (dataEnum != prevDataEnum){ + System.out.println(prevDataEnum + " => " + dataEnum); + prevDataEnum = dataEnum; + data = dataEnum.get(); + } + workingCopy = data.getCopy(); } @Benchmark diff --git a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/DummySortBenchmark.java b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/DummySortBenchmark.java index 3bb2bf9..2091b60 100644 --- a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/DummySortBenchmark.java +++ b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/DummySortBenchmark.java @@ -5,6 +5,6 @@ import de.uni_marburg.powersort.sort.DummySort; public class DummySortBenchmark extends AbstractBenchmark { @Override public void sort() { - DummySort.sort(array, 0, array.length, NaturalOrder.INSTANCE, null, 0, 0); + DummySort.sort(workingCopy, 0, workingCopy.length, NaturalOrder.INSTANCE, null, 0, 0); } } diff --git a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/MergeSortBenchmark.java b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/MergeSortBenchmark.java index 75e4eb6..f125585 100644 --- a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/MergeSortBenchmark.java +++ b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/MergeSortBenchmark.java @@ -5,6 +5,6 @@ import de.uni_marburg.powersort.sort.MergeSort; public class MergeSortBenchmark extends AbstractBenchmark { @Override public void sort() { - MergeSort.legacyMergeSort(array, NaturalOrder.INSTANCE); + MergeSort.legacyMergeSort(workingCopy, NaturalOrder.INSTANCE); } } diff --git a/app/src/main/java/de/uni_marburg/powersort/benchmark/IntegerArray.java b/app/src/main/java/de/uni_marburg/powersort/benchmark/IntegerArray.java index 911edc1..13a449d 100644 --- a/app/src/main/java/de/uni_marburg/powersort/benchmark/IntegerArray.java +++ b/app/src/main/java/de/uni_marburg/powersort/benchmark/IntegerArray.java @@ -17,19 +17,35 @@ public class IntegerArray { } /** - * @return [start, start-1, ..., end+1, end] + * @return [high, high-1, ..., low+1, low] */ - public static Integer[] descending(final int start, final int end) { - assert start > end; + public static Integer[] descending(final int high, final int low) { + assert high > low; - Integer[] list = new Integer[start - end + 1]; + Integer[] list = new Integer[high - low + 1]; for (int i = 0; i < list.length; i++) { - int value = start - i; + int value = high - i; list[i] = value; } - assert list[0] == start; - assert list[list.length - 1] == end; + assert list[0] == high; + assert list[list.length - 1] == low; + return list; + } + /** + * @return [low, low-1, ..., high+1, high] + */ + public static Integer[] ascending(final int low, final int high) { + assert low < high; + + Integer[] list = new Integer[low - high + 1]; + for (int i = 0; i < list.length; i++) { + int value = low + i; + list[i] = value; + } + + assert list[0] == low; + assert list[list.length - 1] == high; return list; } } diff --git a/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java b/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java index 59d8848..4c8a996 100644 --- a/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java +++ b/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java @@ -1,16 +1,13 @@ package de.uni_marburg.powersort.benchmark; +import de.uni_marburg.powersort.data.DataEnum; import de.uni_marburg.powersort.sort.DummySort; import de.uni_marburg.powersort.sort.MergeSort; import de.uni_marburg.powersort.sort.TimSort; -import de.uni_marburg.powersort.data.DescendingIntegers; -import de.uni_marburg.powersort.data.RandomIntegers; import de.uni_marburg.powersort.data.ObjectSupplier; -import java.util.Arrays; -import java.util.List; +import java.util.EnumSet; import java.util.concurrent.TimeUnit; -import java.util.function.Supplier; /** * Custom benchmark. @@ -18,10 +15,10 @@ import java.util.function.Supplier; public class Main { public static void main(final String[] args) { final SortImpl[] sortImplementations = getSortImplementations(); - final List> sortInputSuppliers = getSortInputSuppliers(); + final EnumSet dataEnums = getSortInputSuppliers(); - for (Supplier sortInputSupplier : sortInputSuppliers) { - ObjectSupplier objectSupplier = sortInputSupplier.get(); + for (DataEnum dataEnum : dataEnums) { + ObjectSupplier objectSupplier = dataEnum.get(); System.out.println("\n" + objectSupplier.title()); for (SortImpl sortImplementation : sortImplementations) { @@ -53,6 +50,12 @@ public class Main { TimSort.sort(a, 0, a.length, NaturalOrder.INSTANCE, null, 0, 0); } }, +// new SortImpl("FinnSort") { +// @Override +// public void sort(Object[] a) { +// FinnSort.sort(a); +// } +// }, new SortImpl("MergeSort") { @Override public void sort(Object[] a) { @@ -63,18 +66,11 @@ public class Main { } /** - * The returned ObjectSupplier objects are wrapped by Supplier objects. - * This way they are lazily created on their first access. + * The returned ObjectSupplier objects are wrapped by DataEnum objects. + * This way they are lazily created on their first access with DataEnum.get(). * This saves memory if we work with large lists. */ - static List> getSortInputSuppliers() { - return Arrays.asList( - // Three different random lists. - RandomIntegers::new, - RandomIntegers::new, - RandomIntegers::new, - // One descending list. - DescendingIntegers::new - ); + static EnumSet getSortInputSuppliers() { + return EnumSet.allOf(DataEnum.class); } } diff --git a/app/src/main/java/de/uni_marburg/powersort/data/AscendingIntegers.java b/app/src/main/java/de/uni_marburg/powersort/data/AscendingIntegers.java new file mode 100644 index 0000000..11e44b3 --- /dev/null +++ b/app/src/main/java/de/uni_marburg/powersort/data/AscendingIntegers.java @@ -0,0 +1,17 @@ +package de.uni_marburg.powersort.data; + +import de.uni_marburg.powersort.benchmark.IntegerArray; +import de.uni_marburg.powersort.benchmark.LongFormatter; + +public class AscendingIntegers extends IntegerSupplier { + private static final int SIZE = 50_000_000; + + public AscendingIntegers() { + super(IntegerArray.ascending(SIZE, 0)); + } + + @Override + public String title() { + return "Array of " + LongFormatter.formatUnderscore(SIZE) + " ascending Integer objects."; + } +} diff --git a/app/src/main/java/de/uni_marburg/powersort/data/DataEnum.java b/app/src/main/java/de/uni_marburg/powersort/data/DataEnum.java new file mode 100644 index 0000000..6b8bd30 --- /dev/null +++ b/app/src/main/java/de/uni_marburg/powersort/data/DataEnum.java @@ -0,0 +1,15 @@ +package de.uni_marburg.powersort.data; + +public enum DataEnum { + RANDOM_INTEGERS, + ASCENDING_INTEGERS, + DESCENDING_INTEGERS; + + public ObjectSupplier get() { + return switch (this) { + case RANDOM_INTEGERS -> new RandomIntegers(); + case ASCENDING_INTEGERS -> new AscendingIntegers(); + case DESCENDING_INTEGERS -> new DescendingIntegers(); + }; + } +} diff --git a/app/src/main/java/de/uni_marburg/powersort/data/ObjectSupplier.java b/app/src/main/java/de/uni_marburg/powersort/data/ObjectSupplier.java index f191abc..c1decbc 100644 --- a/app/src/main/java/de/uni_marburg/powersort/data/ObjectSupplier.java +++ b/app/src/main/java/de/uni_marburg/powersort/data/ObjectSupplier.java @@ -3,7 +3,7 @@ package de.uni_marburg.powersort.data; import java.util.Arrays; public abstract class ObjectSupplier { - final Object[] readOnly; + private final Object[] readOnly; ObjectSupplier(Object[] readOnly) { this.readOnly = readOnly; From 060ff596b80f45c3b19c7ee3b223f65729176744 Mon Sep 17 00:00:00 2001 From: Daniel Langbein Date: Wed, 11 Dec 2024 17:38:55 +0000 Subject: [PATCH 13/35] benchmark: SortEnum --- .../uni_marburg/powersort/benchmark/Main.java | 41 ++++--------------- .../powersort/benchmark/NaturalOrder.java | 4 +- .../powersort/data/AscendingIntegers.java | 8 ++-- .../powersort/data/DataArraySizes.java | 7 ++++ .../powersort/data/DescendingIntegers.java | 8 ++-- .../powersort/data/ObjectSupplier.java | 2 +- .../powersort/data/RandomIntegers.java | 8 ++-- .../powersort/sort/SimpleSort.java | 5 +++ .../uni_marburg/powersort/sort/SortEnum.java | 17 ++++++++ 9 files changed, 51 insertions(+), 49 deletions(-) create mode 100644 app/src/main/java/de/uni_marburg/powersort/data/DataArraySizes.java create mode 100644 app/src/main/java/de/uni_marburg/powersort/sort/SimpleSort.java create mode 100644 app/src/main/java/de/uni_marburg/powersort/sort/SortEnum.java diff --git a/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java b/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java index 4c8a996..517e6f6 100644 --- a/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java +++ b/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java @@ -1,9 +1,7 @@ package de.uni_marburg.powersort.benchmark; import de.uni_marburg.powersort.data.DataEnum; -import de.uni_marburg.powersort.sort.DummySort; -import de.uni_marburg.powersort.sort.MergeSort; -import de.uni_marburg.powersort.sort.TimSort; +import de.uni_marburg.powersort.sort.SortEnum; import de.uni_marburg.powersort.data.ObjectSupplier; import java.util.EnumSet; @@ -14,55 +12,30 @@ import java.util.concurrent.TimeUnit; */ public class Main { public static void main(final String[] args) { - final SortImpl[] sortImplementations = getSortImplementations(); + final EnumSet sortImplementations = getSortImplementations(); final EnumSet dataEnums = getSortInputSuppliers(); for (DataEnum dataEnum : dataEnums) { ObjectSupplier objectSupplier = dataEnum.get(); System.out.println("\n" + objectSupplier.title()); - for (SortImpl sortImplementation : sortImplementations) { + for (SortEnum sortImplementation : sortImplementations) { Object[] sortInput = objectSupplier.getCopy(); final long startNanos = System.nanoTime(); - sortImplementation.sort(sortInput); + sortImplementation.get().sort(sortInput); final long stopNanos = System.nanoTime(); final long durNanos = stopNanos - startNanos; final long durMillis = TimeUnit.NANOSECONDS.toMillis(durNanos); final String durFormatted = LongFormatter.formatUnderscore(durMillis); - System.out.println(durFormatted + "," + sortImplementation.title); + System.out.println(durFormatted + "," + sortImplementation); } } } - static SortImpl[] getSortImplementations() { - return new SortImpl[]{ - new SortImpl("DummySort") { - @Override - public void sort(Object[] a) { - DummySort.sort(a, 0, a.length, NaturalOrder.INSTANCE, null, 0, 0); - } - }, - new SortImpl("TimSort") { - @Override - public void sort(Object[] a) { - TimSort.sort(a, 0, a.length, NaturalOrder.INSTANCE, null, 0, 0); - } - }, -// new SortImpl("FinnSort") { -// @Override -// public void sort(Object[] a) { -// FinnSort.sort(a); -// } -// }, - new SortImpl("MergeSort") { - @Override - public void sort(Object[] a) { - MergeSort.legacyMergeSort(a, NaturalOrder.INSTANCE); - } - } - }; + static EnumSet getSortImplementations() { + return EnumSet.allOf(SortEnum.class); } /** diff --git a/app/src/main/java/de/uni_marburg/powersort/benchmark/NaturalOrder.java b/app/src/main/java/de/uni_marburg/powersort/benchmark/NaturalOrder.java index e60074c..9fc8da8 100644 --- a/app/src/main/java/de/uni_marburg/powersort/benchmark/NaturalOrder.java +++ b/app/src/main/java/de/uni_marburg/powersort/benchmark/NaturalOrder.java @@ -5,11 +5,11 @@ import java.util.Comparator; /** * Copied from JDK23 Arrays.java */ -final class NaturalOrder implements Comparator { +public final class NaturalOrder implements Comparator { @SuppressWarnings("unchecked") public int compare(Object first, Object second) { return ((Comparable) first).compareTo(second); } - static final NaturalOrder INSTANCE = new NaturalOrder(); + public static final NaturalOrder INSTANCE = new NaturalOrder(); } diff --git a/app/src/main/java/de/uni_marburg/powersort/data/AscendingIntegers.java b/app/src/main/java/de/uni_marburg/powersort/data/AscendingIntegers.java index 11e44b3..9a830c9 100644 --- a/app/src/main/java/de/uni_marburg/powersort/data/AscendingIntegers.java +++ b/app/src/main/java/de/uni_marburg/powersort/data/AscendingIntegers.java @@ -3,15 +3,15 @@ package de.uni_marburg.powersort.data; import de.uni_marburg.powersort.benchmark.IntegerArray; import de.uni_marburg.powersort.benchmark.LongFormatter; -public class AscendingIntegers extends IntegerSupplier { - private static final int SIZE = 50_000_000; +import static de.uni_marburg.powersort.data.DataArraySizes.SIZE_ASC; +public class AscendingIntegers extends IntegerSupplier { public AscendingIntegers() { - super(IntegerArray.ascending(SIZE, 0)); + super(IntegerArray.ascending(SIZE_ASC, 1)); } @Override public String title() { - return "Array of " + LongFormatter.formatUnderscore(SIZE) + " ascending Integer objects."; + return "Array of " + LongFormatter.formatUnderscore(readOnly.length) + " ascending Integer objects."; } } diff --git a/app/src/main/java/de/uni_marburg/powersort/data/DataArraySizes.java b/app/src/main/java/de/uni_marburg/powersort/data/DataArraySizes.java new file mode 100644 index 0000000..627a63e --- /dev/null +++ b/app/src/main/java/de/uni_marburg/powersort/data/DataArraySizes.java @@ -0,0 +1,7 @@ +package de.uni_marburg.powersort.data; + +public interface DataArraySizes { + int SIZE_RAND = 50_000_000; + int SIZE_ASC = 50_000_000; + int SIZE_DESC = 50_000_000; +} diff --git a/app/src/main/java/de/uni_marburg/powersort/data/DescendingIntegers.java b/app/src/main/java/de/uni_marburg/powersort/data/DescendingIntegers.java index 4f3bea6..901b08b 100644 --- a/app/src/main/java/de/uni_marburg/powersort/data/DescendingIntegers.java +++ b/app/src/main/java/de/uni_marburg/powersort/data/DescendingIntegers.java @@ -3,15 +3,15 @@ package de.uni_marburg.powersort.data; import de.uni_marburg.powersort.benchmark.IntegerArray; import de.uni_marburg.powersort.benchmark.LongFormatter; -public class DescendingIntegers extends IntegerSupplier { - private static final int SIZE = 50_000_000; +import static de.uni_marburg.powersort.data.DataArraySizes.SIZE_DESC; +public class DescendingIntegers extends IntegerSupplier { public DescendingIntegers() { - super(IntegerArray.descending(SIZE, 0)); + super(IntegerArray.descending(SIZE_DESC, 1)); } @Override public String title() { - return "Array of " + LongFormatter.formatUnderscore(SIZE) + " descending Integer objects."; + return "Array of " + LongFormatter.formatUnderscore(readOnly.length) + " descending Integer objects."; } } diff --git a/app/src/main/java/de/uni_marburg/powersort/data/ObjectSupplier.java b/app/src/main/java/de/uni_marburg/powersort/data/ObjectSupplier.java index c1decbc..e1bd1c8 100644 --- a/app/src/main/java/de/uni_marburg/powersort/data/ObjectSupplier.java +++ b/app/src/main/java/de/uni_marburg/powersort/data/ObjectSupplier.java @@ -3,7 +3,7 @@ package de.uni_marburg.powersort.data; import java.util.Arrays; public abstract class ObjectSupplier { - private final Object[] readOnly; + /* package-protected */ final Object[] readOnly; ObjectSupplier(Object[] readOnly) { this.readOnly = readOnly; diff --git a/app/src/main/java/de/uni_marburg/powersort/data/RandomIntegers.java b/app/src/main/java/de/uni_marburg/powersort/data/RandomIntegers.java index db29bf9..8cb36a9 100644 --- a/app/src/main/java/de/uni_marburg/powersort/data/RandomIntegers.java +++ b/app/src/main/java/de/uni_marburg/powersort/data/RandomIntegers.java @@ -3,15 +3,15 @@ package de.uni_marburg.powersort.data; import de.uni_marburg.powersort.benchmark.IntegerArray; import de.uni_marburg.powersort.benchmark.LongFormatter; -public class RandomIntegers extends IntegerSupplier { - private static final int SIZE = 50_000_000; +import static de.uni_marburg.powersort.data.DataArraySizes.SIZE_RAND; +public class RandomIntegers extends IntegerSupplier { public RandomIntegers() { - super(IntegerArray.random(SIZE)); + super(IntegerArray.random(SIZE_RAND)); } @Override public String title() { - return "Array of " + LongFormatter.formatUnderscore(SIZE) + " random Integer objects."; + return "Array of " + LongFormatter.formatUnderscore(readOnly.length) + " random Integer objects."; } } diff --git a/app/src/main/java/de/uni_marburg/powersort/sort/SimpleSort.java b/app/src/main/java/de/uni_marburg/powersort/sort/SimpleSort.java new file mode 100644 index 0000000..79e993e --- /dev/null +++ b/app/src/main/java/de/uni_marburg/powersort/sort/SimpleSort.java @@ -0,0 +1,5 @@ +package de.uni_marburg.powersort.sort; + +public interface SimpleSort { + void sort(Object[] list); +} diff --git a/app/src/main/java/de/uni_marburg/powersort/sort/SortEnum.java b/app/src/main/java/de/uni_marburg/powersort/sort/SortEnum.java new file mode 100644 index 0000000..151fb55 --- /dev/null +++ b/app/src/main/java/de/uni_marburg/powersort/sort/SortEnum.java @@ -0,0 +1,17 @@ +package de.uni_marburg.powersort.sort; + +import de.uni_marburg.powersort.benchmark.NaturalOrder; + +public enum SortEnum { +// BUBBLE_SORT, + MERGE_SORT, + TIM_SORT; + + public SimpleSort get() { + return switch (this) { +// case BUBBLE_SORT -> array -> BubbleSort.sort(array, NaturalOrder.INSTANCE); + case MERGE_SORT -> array -> MergeSort.legacyMergeSort(array, NaturalOrder.INSTANCE); + case TIM_SORT -> array -> TimSort.sort(array, 0, array.length, NaturalOrder.INSTANCE, null, 0, 0); + }; + } +} From e3b90c83cc73b7dbdf9c5b72732a8b7866129893 Mon Sep 17 00:00:00 2001 From: Daniel Langbein Date: Wed, 11 Dec 2024 18:05:12 +0000 Subject: [PATCH 14/35] benchmark: JMH SortEnum --- .../benchmark/DummySortBenchmark.java | 10 -------- .../{AbstractBenchmark.java => MainJmh.java} | 24 ++++++++----------- .../benchmark/MergeSortBenchmark.java | 10 -------- 3 files changed, 10 insertions(+), 34 deletions(-) delete mode 100644 app/src/jmh/java/de/uni_marburg/powersort/benchmark/DummySortBenchmark.java rename app/src/jmh/java/de/uni_marburg/powersort/benchmark/{AbstractBenchmark.java => MainJmh.java} (70%) delete mode 100644 app/src/jmh/java/de/uni_marburg/powersort/benchmark/MergeSortBenchmark.java diff --git a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/DummySortBenchmark.java b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/DummySortBenchmark.java deleted file mode 100644 index 2091b60..0000000 --- a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/DummySortBenchmark.java +++ /dev/null @@ -1,10 +0,0 @@ -package de.uni_marburg.powersort.benchmark; - -import de.uni_marburg.powersort.sort.DummySort; - -public class DummySortBenchmark extends AbstractBenchmark { - @Override - public void sort() { - DummySort.sort(workingCopy, 0, workingCopy.length, NaturalOrder.INSTANCE, null, 0, 0); - } -} diff --git a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/AbstractBenchmark.java b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/MainJmh.java similarity index 70% rename from app/src/jmh/java/de/uni_marburg/powersort/benchmark/AbstractBenchmark.java rename to app/src/jmh/java/de/uni_marburg/powersort/benchmark/MainJmh.java index 2be81c0..1b55391 100644 --- a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/AbstractBenchmark.java +++ b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/MainJmh.java @@ -2,6 +2,7 @@ package de.uni_marburg.powersort.benchmark; import de.uni_marburg.powersort.data.DataEnum; import de.uni_marburg.powersort.data.ObjectSupplier; +import de.uni_marburg.powersort.sort.SortEnum; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; @@ -33,33 +34,28 @@ import java.util.concurrent.TimeUnit; * State objects naturally encapsulate the state on which benchmark is working on. */ @State(Scope.Benchmark) -public abstract class AbstractBenchmark { +public class MainJmh { @Param() private DataEnum dataEnum; + @Param() + private SortEnum sortEnum; - private DataEnum prevDataEnum = null; private ObjectSupplier data; - /* package-protected */ Object[] workingCopy; // TODO: This is inaccurate. How to create and use separate arrays for each warmup x iteration x sortAlgorithm ? @Setup(Level.Invocation) public void setup() { - if (dataEnum != prevDataEnum){ - System.out.println(prevDataEnum + " => " + dataEnum); - prevDataEnum = dataEnum; - data = dataEnum.get(); - } + // TODO: We tried to store the old `dataEnum` in a separate variable and only call `dataEnum.get()` if `dataEnum` changed. But the separate variable was always reverted to `null`. Why? Maybe as the benchmark method does not use it? + // TODO: This leads to different random lists used for each sort impl. + // + // TODO: This is better anyways: Store random list on disk and reuse it for reproducibility + data = dataEnum.get(); workingCopy = data.getCopy(); } @Benchmark public void benchmark() { - sort(); + sortEnum.get().sort(workingCopy); } - - /** - * Sorts this.array with some sorting algorithm. - */ - /* package-protected */ abstract void sort(); } diff --git a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/MergeSortBenchmark.java b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/MergeSortBenchmark.java deleted file mode 100644 index f125585..0000000 --- a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/MergeSortBenchmark.java +++ /dev/null @@ -1,10 +0,0 @@ -package de.uni_marburg.powersort.benchmark; - -import de.uni_marburg.powersort.sort.MergeSort; - -public class MergeSortBenchmark extends AbstractBenchmark { - @Override - public void sort() { - MergeSort.legacyMergeSort(workingCopy, NaturalOrder.INSTANCE); - } -} From 025193595c2b85a5e6dac69b256c56a81c4bb6fe Mon Sep 17 00:00:00 2001 From: Daniel Langbein Date: Thu, 12 Dec 2024 15:31:00 +0000 Subject: [PATCH 15/35] benchmark: reproducible random lists --- .../powersort/benchmark/MainJmh.java | 14 ++-- .../powersort/benchmark/IntegerArray.java | 8 +-- .../powersort/benchmark/RandomInt.java | 28 ++++++-- .../uni_marburg/powersort/data/DataEnum.java | 6 +- .../powersort/data/RandomIntegers.java | 4 +- .../powersort/benchmark/RandomIntTest.java | 66 +++++++++++-------- 6 files changed, 81 insertions(+), 45 deletions(-) diff --git a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/MainJmh.java b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/MainJmh.java index 1b55391..d0151f6 100644 --- a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/MainJmh.java +++ b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/MainJmh.java @@ -46,11 +46,15 @@ public class MainJmh { // TODO: This is inaccurate. How to create and use separate arrays for each warmup x iteration x sortAlgorithm ? @Setup(Level.Invocation) public void setup() { - // TODO: We tried to store the old `dataEnum` in a separate variable and only call `dataEnum.get()` if `dataEnum` changed. But the separate variable was always reverted to `null`. Why? Maybe as the benchmark method does not use it? - // TODO: This leads to different random lists used for each sort impl. - // - // TODO: This is better anyways: Store random list on disk and reuse it for reproducibility - data = dataEnum.get(); + // A new MainJmh object is created for each @Param variation. + // Then, `data` is `null` again. + if (data == null) { + data = dataEnum.get(); + } + // For all warmup and measurement iterations of one @Param variation, the MainJmh object is reused. + // Thus, we can't just sort `data` directly. + // Instead, we have to create a copy of it on which the sort algorithm can work. + // This way, all iterations sort the same input. workingCopy = data.getCopy(); } diff --git a/app/src/main/java/de/uni_marburg/powersort/benchmark/IntegerArray.java b/app/src/main/java/de/uni_marburg/powersort/benchmark/IntegerArray.java index 13a449d..0e54ab0 100644 --- a/app/src/main/java/de/uni_marburg/powersort/benchmark/IntegerArray.java +++ b/app/src/main/java/de/uni_marburg/powersort/benchmark/IntegerArray.java @@ -4,14 +4,10 @@ public class IntegerArray { private IntegerArray() { } - public static Integer[] random(final int length) { - return random(length, Integer.MIN_VALUE, Integer.MAX_VALUE); - } - - public static Integer[] random(final int length, final int minInt, final int maxInt) { + public static Integer[] random(final int length, final long seed) { final Integer[] list = new Integer[length]; for (int i = 0; i < length; i++) { - list[i] = RandomInt.integer(minInt, maxInt); + list[i] = RandomInt.integer(seed); } return list; } diff --git a/app/src/main/java/de/uni_marburg/powersort/benchmark/RandomInt.java b/app/src/main/java/de/uni_marburg/powersort/benchmark/RandomInt.java index 3575cdc..d2330c0 100644 --- a/app/src/main/java/de/uni_marburg/powersort/benchmark/RandomInt.java +++ b/app/src/main/java/de/uni_marburg/powersort/benchmark/RandomInt.java @@ -1,5 +1,7 @@ package de.uni_marburg.powersort.benchmark; +import java.util.Random; + /** * Provides utility methods related to random integers. */ @@ -8,15 +10,33 @@ public final class RandomInt { } /** - * Returns a random integer. - * * @return A random integer. */ public static int integer() { return integer(Integer.MIN_VALUE, Integer.MAX_VALUE); } public static int integer(final int minInt, final int maxInt) { - final double random = Math.random() * (maxInt - minInt) - minInt; - return (int) Math.round(random); + final double rand01 = Math.random(); + return helper(minInt, maxInt, rand01); + } + + /** + * The returned random integer to return is determined by the given seed. + * + * @return A random integer. + */ + public static int integer(final long seed) { + Random random = new Random(seed); + final double rand01 = random.nextDouble(); + return helper(Integer.MIN_VALUE, Integer.MAX_VALUE, rand01); + + } + + /** + * @param rand01 Random value in range [0,1) + */ + private static int helper(final int minInt, final int maxInt, final double rand01) { + final double randMinMax = rand01 * (maxInt - minInt) - minInt; + return (int) Math.round(randMinMax); } } diff --git a/app/src/main/java/de/uni_marburg/powersort/data/DataEnum.java b/app/src/main/java/de/uni_marburg/powersort/data/DataEnum.java index 6b8bd30..6d2ee1e 100644 --- a/app/src/main/java/de/uni_marburg/powersort/data/DataEnum.java +++ b/app/src/main/java/de/uni_marburg/powersort/data/DataEnum.java @@ -6,8 +6,12 @@ public enum DataEnum { DESCENDING_INTEGERS; public ObjectSupplier get() { + // We use a seed to get the same random list every time -> Repeatable benchmarks on same input data! + // final long seed = 3651660232967549736L; // System.nanoTime() ++ Math.random() + final long seed = 140506881906827520L; // (long) 'P' * (long) 'O' *(long) 'W' * (long) 'E' * (long) 'R' * (long) 'S' * (long) 'O' * (long) 'R' * (long) 'T'; + return switch (this) { - case RANDOM_INTEGERS -> new RandomIntegers(); + case RANDOM_INTEGERS -> new RandomIntegers(seed); case ASCENDING_INTEGERS -> new AscendingIntegers(); case DESCENDING_INTEGERS -> new DescendingIntegers(); }; diff --git a/app/src/main/java/de/uni_marburg/powersort/data/RandomIntegers.java b/app/src/main/java/de/uni_marburg/powersort/data/RandomIntegers.java index 8cb36a9..40c46f6 100644 --- a/app/src/main/java/de/uni_marburg/powersort/data/RandomIntegers.java +++ b/app/src/main/java/de/uni_marburg/powersort/data/RandomIntegers.java @@ -6,8 +6,8 @@ import de.uni_marburg.powersort.benchmark.LongFormatter; import static de.uni_marburg.powersort.data.DataArraySizes.SIZE_RAND; public class RandomIntegers extends IntegerSupplier { - public RandomIntegers() { - super(IntegerArray.random(SIZE_RAND)); + public RandomIntegers(final long seed) { + super(IntegerArray.random(SIZE_RAND, seed)); } @Override diff --git a/app/src/test/java/de/uni_marburg/powersort/benchmark/RandomIntTest.java b/app/src/test/java/de/uni_marburg/powersort/benchmark/RandomIntTest.java index 733b44d..ab63a86 100644 --- a/app/src/test/java/de/uni_marburg/powersort/benchmark/RandomIntTest.java +++ b/app/src/test/java/de/uni_marburg/powersort/benchmark/RandomIntTest.java @@ -3,34 +3,46 @@ package de.uni_marburg.powersort.benchmark; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + class RandomIntTest { - protected RandomIntTest(){ - // This constructor is intentionally empty. Nothing special is needed here. - } - - @Test - void testRandomInt() { - final double accuracy = 0.99; - final int min = (int) Math.round(Integer.MIN_VALUE * accuracy); - final int max = (int) Math.round(Integer.MAX_VALUE * accuracy); - - boolean minPassed = false; - boolean maxPassed = false; - for (int i = 0; i < 1000; i++) { - final int random = RandomInt.integer(); - System.out.println(random); //NOPMD - suppressed SystemPrintln - Testing - - if (random <= min) { - minPassed = true; - } - if (random >= max) { - maxPassed = true; - } - if (minPassed && maxPassed) { - return; - } + protected RandomIntTest() { + // This constructor is intentionally empty. Nothing special is needed here. } - Assertions.fail("min or max not reached - not a random int generator"); - } + @Test + void testRandomInt() { + final double accuracy = 0.99; + final int min = (int) Math.round(Integer.MIN_VALUE * accuracy); + final int max = (int) Math.round(Integer.MAX_VALUE * accuracy); + + boolean minPassed = false; + boolean maxPassed = false; + for (int i = 0; i < 1000; i++) { + final int random = RandomInt.integer(); + System.out.println(random); //NOPMD - suppressed SystemPrintln - Testing + + if (random <= min) { + minPassed = true; + } + if (random >= max) { + maxPassed = true; + } + if (minPassed && maxPassed) { + return; + } + } + + Assertions.fail("min or max not reached - not a random int generator"); + } + + @Test + void testReproducibility() { + long seed = 1337; + + int expected = 2147483647; + long actual = RandomInt.integer(seed); + + assertEquals(expected, actual); + } } From a262272b19704a521606d88eba06a0b68cd532f0 Mon Sep 17 00:00:00 2001 From: Daniel Langbein Date: Sun, 15 Dec 2024 20:07:28 +0000 Subject: [PATCH 16/35] benchmark: ascending runs --- .../powersort/benchmark/IntegerArray.java | 6 +- .../powersort/data/AscendingIntegers.java | 2 +- .../powersort/data/AscendingRuns.java | 40 ++++++++++++++ .../uni_marburg/powersort/data/DataEnum.java | 4 +- .../powersort/data/AscendingRunsTest.java | 55 +++++++++++++++++++ 5 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/de/uni_marburg/powersort/data/AscendingRuns.java create mode 100644 app/src/test/java/de/uni_marburg/powersort/data/AscendingRunsTest.java diff --git a/app/src/main/java/de/uni_marburg/powersort/benchmark/IntegerArray.java b/app/src/main/java/de/uni_marburg/powersort/benchmark/IntegerArray.java index 0e54ab0..4f22483 100644 --- a/app/src/main/java/de/uni_marburg/powersort/benchmark/IntegerArray.java +++ b/app/src/main/java/de/uni_marburg/powersort/benchmark/IntegerArray.java @@ -16,7 +16,7 @@ public class IntegerArray { * @return [high, high-1, ..., low+1, low] */ public static Integer[] descending(final int high, final int low) { - assert high > low; + assert high >= low; Integer[] list = new Integer[high - low + 1]; for (int i = 0; i < list.length; i++) { @@ -32,9 +32,9 @@ public class IntegerArray { * @return [low, low-1, ..., high+1, high] */ public static Integer[] ascending(final int low, final int high) { - assert low < high; + assert low <= high; - Integer[] list = new Integer[low - high + 1]; + Integer[] list = new Integer[high - low + 1]; for (int i = 0; i < list.length; i++) { int value = low + i; list[i] = value; diff --git a/app/src/main/java/de/uni_marburg/powersort/data/AscendingIntegers.java b/app/src/main/java/de/uni_marburg/powersort/data/AscendingIntegers.java index 9a830c9..c660f84 100644 --- a/app/src/main/java/de/uni_marburg/powersort/data/AscendingIntegers.java +++ b/app/src/main/java/de/uni_marburg/powersort/data/AscendingIntegers.java @@ -7,7 +7,7 @@ import static de.uni_marburg.powersort.data.DataArraySizes.SIZE_ASC; public class AscendingIntegers extends IntegerSupplier { public AscendingIntegers() { - super(IntegerArray.ascending(SIZE_ASC, 1)); + super(IntegerArray.ascending( 1, SIZE_ASC)); } @Override diff --git a/app/src/main/java/de/uni_marburg/powersort/data/AscendingRuns.java b/app/src/main/java/de/uni_marburg/powersort/data/AscendingRuns.java new file mode 100644 index 0000000..be1a221 --- /dev/null +++ b/app/src/main/java/de/uni_marburg/powersort/data/AscendingRuns.java @@ -0,0 +1,40 @@ +package de.uni_marburg.powersort.data; + +import de.uni_marburg.powersort.benchmark.IntegerArray; + +public class AscendingRuns extends IntegerSupplier { + /** + * Can be used e.g. to construct this array: + * [0, 1, 2, 3, -2, -1, 0, 1, -4, -3, -2, -1] + * + * @param runLength >= 1 + */ + public static AscendingRuns newAscendingRuns( + int numOfRuns, + int runLength, + int decreaseBetweenRuns + ) { + if(numOfRuns < 0 || runLength <= 0){ + throw new IllegalArgumentException(); + } + + Integer[] data = new Integer[numOfRuns * runLength]; + for (int i = 0; i < numOfRuns; i++) { + int low = decreaseBetweenRuns * i; + int high = low + runLength - 1; + + Integer[] run = IntegerArray.ascending(low, high); + System.arraycopy(run, 0, data, i * runLength, run.length); + } + return new AscendingRuns(data); + } + + private AscendingRuns(Integer[] readonly) { + super(readonly); + } + + @Override + public String title() { + return "Array of Integer objects with ascending runs"; + } +} diff --git a/app/src/main/java/de/uni_marburg/powersort/data/DataEnum.java b/app/src/main/java/de/uni_marburg/powersort/data/DataEnum.java index 6d2ee1e..af0fa35 100644 --- a/app/src/main/java/de/uni_marburg/powersort/data/DataEnum.java +++ b/app/src/main/java/de/uni_marburg/powersort/data/DataEnum.java @@ -3,7 +3,8 @@ package de.uni_marburg.powersort.data; public enum DataEnum { RANDOM_INTEGERS, ASCENDING_INTEGERS, - DESCENDING_INTEGERS; + DESCENDING_INTEGERS, + ASCENDING_RUNS; public ObjectSupplier get() { // We use a seed to get the same random list every time -> Repeatable benchmarks on same input data! @@ -14,6 +15,7 @@ public enum DataEnum { case RANDOM_INTEGERS -> new RandomIntegers(seed); case ASCENDING_INTEGERS -> new AscendingIntegers(); case DESCENDING_INTEGERS -> new DescendingIntegers(); + case ASCENDING_RUNS -> AscendingRuns.newAscendingRuns(10000, 10000, -10000); }; } } diff --git a/app/src/test/java/de/uni_marburg/powersort/data/AscendingRunsTest.java b/app/src/test/java/de/uni_marburg/powersort/data/AscendingRunsTest.java new file mode 100644 index 0000000..69f9b15 --- /dev/null +++ b/app/src/test/java/de/uni_marburg/powersort/data/AscendingRunsTest.java @@ -0,0 +1,55 @@ +package de.uni_marburg.powersort.data; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.converter.ConvertWith; +import org.junit.jupiter.params.converter.SimpleArgumentConverter; +import org.junit.jupiter.params.provider.CsvSource; + +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.*; + +class AscendingRunsTest { + /** + * https://stackoverflow.com/a/46850299/6334421 + */ + private static class IntArrayConverter extends SimpleArgumentConverter { + @Override + protected Object convert(Object source, Class targetType) { + if (source instanceof String s && int[].class.isAssignableFrom(targetType)) { + if (s.isEmpty()) { + return new int[0]; + } + String[] strings = s.split("\\s*\\|\\s*"); + return Arrays.stream(strings).mapToInt(Integer::valueOf).toArray(); + } else { + throw new IllegalArgumentException("Conversion from " + source.getClass() + + " to " + targetType + " not supported."); + } + } + + } + + @ParameterizedTest + @CsvSource({ + "0,1,-1,''", + "1,1,-1,0", + "1,2,-2,0|1", + "2,2,-2,0|1|-2|-1", + "2,4,-2,0|1|2|3|-2|-1|0|1", + }) + void testAscendingRuns1(int numOfRuns, int runLength, int decreaseBetweenRuns, @ConvertWith(IntArrayConverter.class) int[] expected) { + Integer[] actualIntegers = AscendingRuns.newAscendingRuns(numOfRuns, runLength, decreaseBetweenRuns).getCopy(); + int[] actual = Arrays.stream(actualIntegers).mapToInt(Integer::valueOf).toArray(); + assertArrayEquals(expected, actual); + } + + @ParameterizedTest + @CsvSource({ + "1,0,-1", + "-1,1,-1", + }) + void testAscendingRuns2(int numOfRuns, int runLength, int decreaseBetweenRuns) { + assertThrows(IllegalArgumentException.class, () -> AscendingRuns.newAscendingRuns(numOfRuns, runLength, decreaseBetweenRuns)); + } +} From 72d668e0f9b4909140ee59ec9743673edad0fcab Mon Sep 17 00:00:00 2001 From: Daniel Langbein Date: Sun, 15 Dec 2024 20:08:50 +0000 Subject: [PATCH 17/35] benchmark: docs --- app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java b/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java index 517e6f6..c70bfcc 100644 --- a/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java +++ b/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java @@ -22,6 +22,7 @@ public class Main { for (SortEnum sortImplementation : sortImplementations) { Object[] sortInput = objectSupplier.getCopy(); + // TODO: JVM warmup! final long startNanos = System.nanoTime(); sortImplementation.get().sort(sortInput); final long stopNanos = System.nanoTime(); From f32088c2c9c3cfbed47c2f5b0537bb3f67556a63 Mon Sep 17 00:00:00 2001 From: finnm Date: Mon, 16 Dec 2024 16:11:13 +0100 Subject: [PATCH 18/35] Made FinnSort generic --- .../powersort/FinnSort/FinnSort.java | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java b/app/src/main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java index ac9a591..09f7d72 100644 --- a/app/src/main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java +++ b/app/src/main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java @@ -7,43 +7,43 @@ public class FinnSort { private static final ArrayList runs = new ArrayList<>(); - static void sort(Integer[] a) { + static void sort(T[] a, Comparator c) { int n = a.length; int i = 0; - int j = extendRunRight(a, i); + int j = extendRunRight(a, i, c); - printList(a); + printList(a, c); runs.add(new Run(i, j, 0)); i = j; while (i < n) { - j = extendRunRight(a, i); + j = extendRunRight(a, i, c); //printRuns(); int p = power(runs.getLast(), new Run(i, j, 0), n); while (runs.size() >= 2 && p < power(runs.getLast(), runs.get(runs.size() - 2), n)) { - basicMerge(a, runs.removeFirst(), runs.removeFirst()); + basicMerge(a, runs.removeFirst(), runs.removeFirst(), c); } runs.add(new Run(i, j, p)); i = j; } while (runs.size() >= 2) { - basicMerge(a, runs.removeLast(), runs.removeLast()); + basicMerge(a, runs.removeLast(), runs.removeLast(), c); } } - private static void basicMerge(Integer[] a, Run r1, Run r2) { - ArrayList run1 = new ArrayList<>(Arrays.asList(a).subList(r1.start, r1.end)); - ArrayList run2 = new ArrayList<>(Arrays.asList(a).subList(r2.start, r2.end)); - ArrayList merge = new ArrayList<>(); + private static void basicMerge(T[] a, Run r1, Run r2, Comparator c) { + ArrayList run1 = new ArrayList<>(Arrays.asList(a).subList(r1.start, r1.end)); + ArrayList run2 = new ArrayList<>(Arrays.asList(a).subList(r2.start, r2.end)); + ArrayList merge = new ArrayList<>(); while (!run1.isEmpty() || !run2.isEmpty()) { - if (run2.isEmpty() || !run1.isEmpty() && run1.getFirst() < run2.getFirst()) { + if (run2.isEmpty() || !run1.isEmpty() && c.compare(run1.getFirst(), run2.getFirst()) < 0) { merge.add(run1.removeFirst()); } else { merge.add(run2.removeFirst()); @@ -53,12 +53,12 @@ public class FinnSort { System.arraycopy(merge.toArray(), 0, a, min(r1.start, r2.start), merge.size()); Run r = new Run(min(r1.start, r2.start), max(r1.end, r2.end), min(r1.power, r2.power)); runs.add(r); - printList(a); + printList(a, c); } - private static int extendRunRight(Integer[] a, int i) { + private static int extendRunRight(T[] a, int i, Comparator c) { int j = i + 1; - while (j < a.length && a[j-1] <= a[j]) { + while (j < a.length && c.compare(a[j-1], a[j]) <= 0) { j++; } return j; @@ -87,12 +87,12 @@ public class FinnSort { } System.out.println(s); } - public static void printList(Integer[] arr) { + public static void printList(T[] arr, Comparator c) { String s = ""; int i = 0; while (i < arr.length) { String run = "["; - int j = extendRunRight(arr, i); + int j = extendRunRight(arr, i, c); for (int t = i; t < j; t++) { run += arr[t] + ", "; } @@ -106,7 +106,7 @@ public class FinnSort { 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}; - sort(numbers); + sort(numbers, Comparator.naturalOrder()); System.out.println("Result: "); System.out.println(new ArrayList<>(List.of(numbers))); } From 8e49fb76b9444499a1e6e9c94337dc3609df8124 Mon Sep 17 00:00:00 2001 From: finnm Date: Mon, 16 Dec 2024 18:59:15 +0100 Subject: [PATCH 19/35] Made FinnSort generic --- .idea/misc.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 122ba17..5a6579d 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,5 +3,5 @@ - + \ No newline at end of file From 3fbee13d0757325d8c2b8c23cb7a364e1f11fb99 Mon Sep 17 00:00:00 2001 From: finnm Date: Mon, 16 Dec 2024 19:04:30 +0100 Subject: [PATCH 20/35] Made FinnSort public --- .../main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java b/app/src/main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java index 09f7d72..cb236e8 100644 --- a/app/src/main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java +++ b/app/src/main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java @@ -7,7 +7,7 @@ public class FinnSort { private static final ArrayList runs = new ArrayList<>(); - static void sort(T[] a, Comparator c) { + public static void sort(T[] a, Comparator c) { int n = a.length; int i = 0; From 8379570f9aa5b86dd9815dcc83cceb16840df689 Mon Sep 17 00:00:00 2001 From: Daniel Langbein Date: Mon, 16 Dec 2024 21:06:11 +0000 Subject: [PATCH 21/35] benchmark: more input lists --- .../powersort/data/AscendingIntegers.java | 6 ++---- .../powersort/data/DataArraySizes.java | 7 ------- .../de/uni_marburg/powersort/data/DataEnum.java | 15 ++++++++++----- .../powersort/data/DescendingIntegers.java | 6 ++---- .../powersort/data/RandomIntegers.java | 6 ++---- .../de/uni_marburg/powersort/sort/SortEnum.java | 5 ++++- 6 files changed, 20 insertions(+), 25 deletions(-) delete mode 100644 app/src/main/java/de/uni_marburg/powersort/data/DataArraySizes.java diff --git a/app/src/main/java/de/uni_marburg/powersort/data/AscendingIntegers.java b/app/src/main/java/de/uni_marburg/powersort/data/AscendingIntegers.java index c660f84..8050a21 100644 --- a/app/src/main/java/de/uni_marburg/powersort/data/AscendingIntegers.java +++ b/app/src/main/java/de/uni_marburg/powersort/data/AscendingIntegers.java @@ -3,11 +3,9 @@ package de.uni_marburg.powersort.data; import de.uni_marburg.powersort.benchmark.IntegerArray; import de.uni_marburg.powersort.benchmark.LongFormatter; -import static de.uni_marburg.powersort.data.DataArraySizes.SIZE_ASC; - public class AscendingIntegers extends IntegerSupplier { - public AscendingIntegers() { - super(IntegerArray.ascending( 1, SIZE_ASC)); + public AscendingIntegers(int size) { + super(IntegerArray.ascending( 1, size)); } @Override diff --git a/app/src/main/java/de/uni_marburg/powersort/data/DataArraySizes.java b/app/src/main/java/de/uni_marburg/powersort/data/DataArraySizes.java deleted file mode 100644 index 627a63e..0000000 --- a/app/src/main/java/de/uni_marburg/powersort/data/DataArraySizes.java +++ /dev/null @@ -1,7 +0,0 @@ -package de.uni_marburg.powersort.data; - -public interface DataArraySizes { - int SIZE_RAND = 50_000_000; - int SIZE_ASC = 50_000_000; - int SIZE_DESC = 50_000_000; -} diff --git a/app/src/main/java/de/uni_marburg/powersort/data/DataEnum.java b/app/src/main/java/de/uni_marburg/powersort/data/DataEnum.java index af0fa35..ff9de0a 100644 --- a/app/src/main/java/de/uni_marburg/powersort/data/DataEnum.java +++ b/app/src/main/java/de/uni_marburg/powersort/data/DataEnum.java @@ -4,18 +4,23 @@ public enum DataEnum { RANDOM_INTEGERS, ASCENDING_INTEGERS, DESCENDING_INTEGERS, - ASCENDING_RUNS; + ASCENDING_RUNS, + ASCENDING_RUNS_WITH_OVERLAP; public ObjectSupplier get() { // We use a seed to get the same random list every time -> Repeatable benchmarks on same input data! // final long seed = 3651660232967549736L; // System.nanoTime() ++ Math.random() final long seed = 140506881906827520L; // (long) 'P' * (long) 'O' *(long) 'W' * (long) 'E' * (long) 'R' * (long) 'S' * (long) 'O' * (long) 'R' * (long) 'T'; + int longListSize = 50_000_000; + return switch (this) { - case RANDOM_INTEGERS -> new RandomIntegers(seed); - case ASCENDING_INTEGERS -> new AscendingIntegers(); - case DESCENDING_INTEGERS -> new DescendingIntegers(); - case ASCENDING_RUNS -> AscendingRuns.newAscendingRuns(10000, 10000, -10000); + case RANDOM_INTEGERS -> new RandomIntegers(longListSize, seed); + case ASCENDING_INTEGERS -> new AscendingIntegers(longListSize); + case DESCENDING_INTEGERS -> new DescendingIntegers(longListSize); + + case ASCENDING_RUNS -> AscendingRuns.newAscendingRuns(10_000, 10_000, -10_000); + case ASCENDING_RUNS_WITH_OVERLAP -> AscendingRuns.newAscendingRuns(10_000, 10_000, -5_000); }; } } diff --git a/app/src/main/java/de/uni_marburg/powersort/data/DescendingIntegers.java b/app/src/main/java/de/uni_marburg/powersort/data/DescendingIntegers.java index 901b08b..70a8f15 100644 --- a/app/src/main/java/de/uni_marburg/powersort/data/DescendingIntegers.java +++ b/app/src/main/java/de/uni_marburg/powersort/data/DescendingIntegers.java @@ -3,11 +3,9 @@ package de.uni_marburg.powersort.data; import de.uni_marburg.powersort.benchmark.IntegerArray; import de.uni_marburg.powersort.benchmark.LongFormatter; -import static de.uni_marburg.powersort.data.DataArraySizes.SIZE_DESC; - public class DescendingIntegers extends IntegerSupplier { - public DescendingIntegers() { - super(IntegerArray.descending(SIZE_DESC, 1)); + public DescendingIntegers(int size) { + super(IntegerArray.descending(size, 1)); } @Override diff --git a/app/src/main/java/de/uni_marburg/powersort/data/RandomIntegers.java b/app/src/main/java/de/uni_marburg/powersort/data/RandomIntegers.java index 40c46f6..f7b85ee 100644 --- a/app/src/main/java/de/uni_marburg/powersort/data/RandomIntegers.java +++ b/app/src/main/java/de/uni_marburg/powersort/data/RandomIntegers.java @@ -3,11 +3,9 @@ package de.uni_marburg.powersort.data; import de.uni_marburg.powersort.benchmark.IntegerArray; import de.uni_marburg.powersort.benchmark.LongFormatter; -import static de.uni_marburg.powersort.data.DataArraySizes.SIZE_RAND; - public class RandomIntegers extends IntegerSupplier { - public RandomIntegers(final long seed) { - super(IntegerArray.random(SIZE_RAND, seed)); + public RandomIntegers(final int size, final long seed) { + super(IntegerArray.random(size, seed)); } @Override diff --git a/app/src/main/java/de/uni_marburg/powersort/sort/SortEnum.java b/app/src/main/java/de/uni_marburg/powersort/sort/SortEnum.java index 151fb55..58b2397 100644 --- a/app/src/main/java/de/uni_marburg/powersort/sort/SortEnum.java +++ b/app/src/main/java/de/uni_marburg/powersort/sort/SortEnum.java @@ -1,17 +1,20 @@ package de.uni_marburg.powersort.sort; +import de.uni_marburg.powersort.FinnSort.FinnSort; import de.uni_marburg.powersort.benchmark.NaturalOrder; public enum SortEnum { // BUBBLE_SORT, MERGE_SORT, - TIM_SORT; + TIM_SORT, + FIN_SORT; public SimpleSort get() { return switch (this) { // case BUBBLE_SORT -> array -> BubbleSort.sort(array, NaturalOrder.INSTANCE); case MERGE_SORT -> array -> MergeSort.legacyMergeSort(array, NaturalOrder.INSTANCE); case TIM_SORT -> array -> TimSort.sort(array, 0, array.length, NaturalOrder.INSTANCE, null, 0, 0); + case FIN_SORT -> array -> FinnSort.sort(array, NaturalOrder.INSTANCE); }; } } From 43dfcd987eb46cb7a3ed6135d75edaad93a72068 Mon Sep 17 00:00:00 2001 From: Daniel Langbein Date: Mon, 16 Dec 2024 21:07:18 +0000 Subject: [PATCH 22/35] add sort test --- .../de/uni_marburg/powersort/JUnitUtil.java | 41 +++++++++++++++++++ .../powersort/data/AscendingRunsTest.java | 24 +---------- .../powersort/sort/AbstractSortTest.java | 26 ++++++++++++ .../powersort/sort/FinnSortTest.java | 7 ++++ 4 files changed, 76 insertions(+), 22 deletions(-) create mode 100644 app/src/test/java/de/uni_marburg/powersort/JUnitUtil.java create mode 100644 app/src/test/java/de/uni_marburg/powersort/sort/AbstractSortTest.java create mode 100644 app/src/test/java/de/uni_marburg/powersort/sort/FinnSortTest.java diff --git a/app/src/test/java/de/uni_marburg/powersort/JUnitUtil.java b/app/src/test/java/de/uni_marburg/powersort/JUnitUtil.java new file mode 100644 index 0000000..372b152 --- /dev/null +++ b/app/src/test/java/de/uni_marburg/powersort/JUnitUtil.java @@ -0,0 +1,41 @@ +package de.uni_marburg.powersort; + +import org.junit.jupiter.params.converter.SimpleArgumentConverter; + +import java.util.Arrays; + +public class JUnitUtil { + /** + * https://stackoverflow.com/a/46850299/6334421 + */ + public static class IntArrayConverter extends SimpleArgumentConverter { + @Override + protected int[] convert(Object source, Class targetType) { + if (source instanceof String s && int[].class.isAssignableFrom(targetType)) { + if (s.isEmpty()) { + return new int[0]; + } + String[] strings = s.split("\\s*\\|\\s*"); + return Arrays.stream(strings).mapToInt(Integer::valueOf).toArray(); + } else { + throw new IllegalArgumentException("Conversion from " + source.getClass() + + " to " + targetType + " not supported."); + } + } + } + public static class IntegerArrayConverter extends SimpleArgumentConverter { + @Override + protected Integer[] convert(Object source, Class targetType) { + if (source instanceof String s && Integer[].class.isAssignableFrom(targetType)) { + if (s.isEmpty()) { + return new Integer[0]; + } + String[] strings = s.split("\\s*\\|\\s*"); + return Arrays.stream(strings).map(Integer::valueOf).toArray(Integer[]::new); + } else { + throw new IllegalArgumentException("Conversion from " + source.getClass() + + " to " + targetType + " not supported."); + } + } + } +} diff --git a/app/src/test/java/de/uni_marburg/powersort/data/AscendingRunsTest.java b/app/src/test/java/de/uni_marburg/powersort/data/AscendingRunsTest.java index 69f9b15..36e78aa 100644 --- a/app/src/test/java/de/uni_marburg/powersort/data/AscendingRunsTest.java +++ b/app/src/test/java/de/uni_marburg/powersort/data/AscendingRunsTest.java @@ -1,8 +1,8 @@ package de.uni_marburg.powersort.data; +import de.uni_marburg.powersort.JUnitUtil; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.converter.ConvertWith; -import org.junit.jupiter.params.converter.SimpleArgumentConverter; import org.junit.jupiter.params.provider.CsvSource; import java.util.Arrays; @@ -10,26 +10,6 @@ import java.util.Arrays; import static org.junit.jupiter.api.Assertions.*; class AscendingRunsTest { - /** - * https://stackoverflow.com/a/46850299/6334421 - */ - private static class IntArrayConverter extends SimpleArgumentConverter { - @Override - protected Object convert(Object source, Class targetType) { - if (source instanceof String s && int[].class.isAssignableFrom(targetType)) { - if (s.isEmpty()) { - return new int[0]; - } - String[] strings = s.split("\\s*\\|\\s*"); - return Arrays.stream(strings).mapToInt(Integer::valueOf).toArray(); - } else { - throw new IllegalArgumentException("Conversion from " + source.getClass() - + " to " + targetType + " not supported."); - } - } - - } - @ParameterizedTest @CsvSource({ "0,1,-1,''", @@ -38,7 +18,7 @@ class AscendingRunsTest { "2,2,-2,0|1|-2|-1", "2,4,-2,0|1|2|3|-2|-1|0|1", }) - void testAscendingRuns1(int numOfRuns, int runLength, int decreaseBetweenRuns, @ConvertWith(IntArrayConverter.class) int[] expected) { + void testAscendingRuns1(int numOfRuns, int runLength, int decreaseBetweenRuns, @ConvertWith(JUnitUtil.IntArrayConverter.class) int[] expected) { Integer[] actualIntegers = AscendingRuns.newAscendingRuns(numOfRuns, runLength, decreaseBetweenRuns).getCopy(); int[] actual = Arrays.stream(actualIntegers).mapToInt(Integer::valueOf).toArray(); assertArrayEquals(expected, actual); diff --git a/app/src/test/java/de/uni_marburg/powersort/sort/AbstractSortTest.java b/app/src/test/java/de/uni_marburg/powersort/sort/AbstractSortTest.java new file mode 100644 index 0000000..7fde10e --- /dev/null +++ b/app/src/test/java/de/uni_marburg/powersort/sort/AbstractSortTest.java @@ -0,0 +1,26 @@ +package de.uni_marburg.powersort.sort; + +import de.uni_marburg.powersort.JUnitUtil; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.converter.ConvertWith; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +public abstract class AbstractSortTest { + SortEnum sortAlg; + + @ParameterizedTest + @CsvSource({ + "'',''", + "'1337','1337'", + "'3|2|1','1|2|3'", + "'1|1','1|1'", + "'2|1','1|2'", + "'2|1|2','1|2|2'", + }) + void test1(@ConvertWith(JUnitUtil.IntegerArrayConverter.class) Integer[] array, @ConvertWith(JUnitUtil.IntegerArrayConverter.class) Integer[] expected) { + sortAlg.get().sort(array); + assertArrayEquals(expected, array); + } +} diff --git a/app/src/test/java/de/uni_marburg/powersort/sort/FinnSortTest.java b/app/src/test/java/de/uni_marburg/powersort/sort/FinnSortTest.java new file mode 100644 index 0000000..17578ac --- /dev/null +++ b/app/src/test/java/de/uni_marburg/powersort/sort/FinnSortTest.java @@ -0,0 +1,7 @@ +package de.uni_marburg.powersort.sort; + +public class FinnSortTest extends AbstractSortTest { + FinnSortTest() { + sortAlg = SortEnum.FIN_SORT; + } +} From cb9ff240ea6e00c09d60480557fb4eb6c3b2280e Mon Sep 17 00:00:00 2001 From: Daniel Langbein Date: Mon, 16 Dec 2024 21:19:35 +0000 Subject: [PATCH 23/35] refactor --- .../uni_marburg/powersort/{benchmark => }/Educational.java | 5 ++++- .../de/uni_marburg/powersort/benchmark/DummyComparable1.java | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) rename app/src/main/java/de/uni_marburg/powersort/{benchmark => }/Educational.java (92%) diff --git a/app/src/main/java/de/uni_marburg/powersort/benchmark/Educational.java b/app/src/main/java/de/uni_marburg/powersort/Educational.java similarity index 92% rename from app/src/main/java/de/uni_marburg/powersort/benchmark/Educational.java rename to app/src/main/java/de/uni_marburg/powersort/Educational.java index 22c13b2..35bb456 100644 --- a/app/src/main/java/de/uni_marburg/powersort/benchmark/Educational.java +++ b/app/src/main/java/de/uni_marburg/powersort/Educational.java @@ -1,4 +1,7 @@ -package de.uni_marburg.powersort.benchmark; +package de.uni_marburg.powersort; + +import de.uni_marburg.powersort.benchmark.DummyComparable1; +import de.uni_marburg.powersort.benchmark.NaturalOrder; import java.util.Arrays; diff --git a/app/src/main/java/de/uni_marburg/powersort/benchmark/DummyComparable1.java b/app/src/main/java/de/uni_marburg/powersort/benchmark/DummyComparable1.java index 7cea94b..a404bbe 100644 --- a/app/src/main/java/de/uni_marburg/powersort/benchmark/DummyComparable1.java +++ b/app/src/main/java/de/uni_marburg/powersort/benchmark/DummyComparable1.java @@ -3,7 +3,7 @@ package de.uni_marburg.powersort.benchmark; /** * A class for tiny, comparable objects. */ -record DummyComparable1(int id) implements Comparable { +public record DummyComparable1(int id) implements Comparable { @Override public int compareTo(DummyComparable1 other) { return id - other.id; From e25a14f718631a60dacaeeaf80f311b8ac2bd09e Mon Sep 17 00:00:00 2001 From: Daniel Langbein Date: Mon, 16 Dec 2024 21:20:06 +0000 Subject: [PATCH 24/35] test and benchmark: add ASort --- .../main/java/de/uni_marburg/powersort/sort/SortEnum.java | 4 +++- .../test/java/de/uni_marburg/powersort/sort/ASortTest.java | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 app/src/test/java/de/uni_marburg/powersort/sort/ASortTest.java diff --git a/app/src/main/java/de/uni_marburg/powersort/sort/SortEnum.java b/app/src/main/java/de/uni_marburg/powersort/sort/SortEnum.java index 58b2397..f2c6bfe 100644 --- a/app/src/main/java/de/uni_marburg/powersort/sort/SortEnum.java +++ b/app/src/main/java/de/uni_marburg/powersort/sort/SortEnum.java @@ -7,7 +7,8 @@ public enum SortEnum { // BUBBLE_SORT, MERGE_SORT, TIM_SORT, - FIN_SORT; + FIN_SORT, + ASORT; public SimpleSort get() { return switch (this) { @@ -15,6 +16,7 @@ public enum SortEnum { case MERGE_SORT -> array -> MergeSort.legacyMergeSort(array, NaturalOrder.INSTANCE); case TIM_SORT -> array -> TimSort.sort(array, 0, array.length, NaturalOrder.INSTANCE, null, 0, 0); case FIN_SORT -> array -> FinnSort.sort(array, NaturalOrder.INSTANCE); + case ASORT -> array -> ASort.sort(array, NaturalOrder.INSTANCE); }; } } diff --git a/app/src/test/java/de/uni_marburg/powersort/sort/ASortTest.java b/app/src/test/java/de/uni_marburg/powersort/sort/ASortTest.java new file mode 100644 index 0000000..dc7acf5 --- /dev/null +++ b/app/src/test/java/de/uni_marburg/powersort/sort/ASortTest.java @@ -0,0 +1,7 @@ +package de.uni_marburg.powersort.sort; + +public class ASortTest extends AbstractSortTest { + ASortTest() { + sortAlg = SortEnum.ASORT; + } +} From ccd0fba7c2daac4b9391826efc8561d19651ded3 Mon Sep 17 00:00:00 2001 From: Daniel Langbein Date: Mon, 16 Dec 2024 21:28:43 +0000 Subject: [PATCH 25/35] docs --- README.md | 6 ------ .../de/uni_marburg/powersort/sort/ComparableTimSort.java | 4 ++++ .../main/java/de/uni_marburg/powersort/sort/TimSort.java | 4 ++++ 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 72131f6..7c50e36 100644 --- a/README.md +++ b/README.md @@ -56,9 +56,3 @@ Run the task "test": ```shell ./gradlew test ``` - -## TimSort - -Imported from -- src/java.base/share/classes/java/util/TimSort.java -- src/java.base/share/classes/java/util/ComparableTimSort.java diff --git a/app/src/main/java/de/uni_marburg/powersort/sort/ComparableTimSort.java b/app/src/main/java/de/uni_marburg/powersort/sort/ComparableTimSort.java index 8396420..1d0b78b 100644 --- a/app/src/main/java/de/uni_marburg/powersort/sort/ComparableTimSort.java +++ b/app/src/main/java/de/uni_marburg/powersort/sort/ComparableTimSort.java @@ -24,6 +24,10 @@ * questions. */ +/* + * Imported from OpenJDK git repo ComparableTimSort.java + */ + package de.uni_marburg.powersort.sort; /** diff --git a/app/src/main/java/de/uni_marburg/powersort/sort/TimSort.java b/app/src/main/java/de/uni_marburg/powersort/sort/TimSort.java index 3bab3b7..0a3958f 100644 --- a/app/src/main/java/de/uni_marburg/powersort/sort/TimSort.java +++ b/app/src/main/java/de/uni_marburg/powersort/sort/TimSort.java @@ -24,6 +24,10 @@ * questions. */ +/* + * Imported from OpenJDK git repo TimSort.java + */ + package de.uni_marburg.powersort.sort; import java.util.Comparator; From d19d89006c860db05ab2333f7897f71f24fdb60c Mon Sep 17 00:00:00 2001 From: Daniel Langbein Date: Mon, 16 Dec 2024 21:30:53 +0000 Subject: [PATCH 26/35] add sort test --- .../powersort/sort/AbstractSortTest.java | 34 +++++++++++++++---- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/app/src/test/java/de/uni_marburg/powersort/sort/AbstractSortTest.java b/app/src/test/java/de/uni_marburg/powersort/sort/AbstractSortTest.java index 7fde10e..b058a10 100644 --- a/app/src/test/java/de/uni_marburg/powersort/sort/AbstractSortTest.java +++ b/app/src/test/java/de/uni_marburg/powersort/sort/AbstractSortTest.java @@ -1,10 +1,13 @@ package de.uni_marburg.powersort.sort; import de.uni_marburg.powersort.JUnitUtil; +import de.uni_marburg.powersort.data.AscendingRuns; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.converter.ConvertWith; import org.junit.jupiter.params.provider.CsvSource; +import java.util.Arrays; + import static org.junit.jupiter.api.Assertions.assertArrayEquals; public abstract class AbstractSortTest { @@ -12,14 +15,31 @@ public abstract class AbstractSortTest { @ParameterizedTest @CsvSource({ - "'',''", - "'1337','1337'", - "'3|2|1','1|2|3'", - "'1|1','1|1'", - "'2|1','1|2'", - "'2|1|2','1|2|2'", + "''", + "1337", + "3|2|1", + "1|1", + "2|1", + "2|1|2", }) - void test1(@ConvertWith(JUnitUtil.IntegerArrayConverter.class) Integer[] array, @ConvertWith(JUnitUtil.IntegerArrayConverter.class) Integer[] expected) { + void test1(@ConvertWith(JUnitUtil.IntegerArrayConverter.class) Integer[] array) { + sortAndCheckResult(array); + } + + @ParameterizedTest + @CsvSource({ + "3,7,-13", + "3,7,-3", + }) + void test2(int numOfRuns, int runLength, int decreaseBetweenRuns) { + Integer[] array = AscendingRuns.newAscendingRuns(numOfRuns, runLength, decreaseBetweenRuns).getCopy(); + sortAndCheckResult(array); + } + + void sortAndCheckResult(Integer[] array){ + Integer[] expected = Arrays.copyOf(array, array.length); + Arrays.sort(expected); + sortAlg.get().sort(array); assertArrayEquals(expected, array); } From afe766992a174ec303b743452f4025d2501a4696 Mon Sep 17 00:00:00 2001 From: finnm Date: Mon, 16 Dec 2024 22:31:37 +0100 Subject: [PATCH 27/35] Initialized a second FinnSort --- .../powersort/FinnSort/FasterFinnSort.java | 960 ++++++++++++++++++ 1 file changed, 960 insertions(+) create mode 100644 app/src/main/java/de/uni_marburg/powersort/FinnSort/FasterFinnSort.java 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 new file mode 100644 index 0000000..37072ae --- /dev/null +++ b/app/src/main/java/de/uni_marburg/powersort/FinnSort/FasterFinnSort.java @@ -0,0 +1,960 @@ +package de.uni_marburg.powersort.FinnSort; +/* + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright 2009 Google Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +import java.util.Comparator; + +/** + * A stable, adaptive, iterative mergesort that requires far fewer than + * n lg(n) comparisons when running on partially sorted arrays, while + * offering performance comparable to a traditional mergesort when run + * on random arrays. Like all proper mergesorts, this sort is stable and + * runs O(n log n) time (worst case). In the worst case, this sort requires + * temporary storage space for n/2 object references; in the best case, + * it requires only a small constant amount of space. + * + * This implementation was adapted from Tim Peters's list sort for + * Python, which is described in detail here: + * + * http://svn.python.org/projects/python/trunk/Objects/listsort.txt + * + * Tim's C code may be found here: + * + * http://svn.python.org/projects/python/trunk/Objects/listobject.c + * + * The underlying techniques are described in this paper (and may have + * even earlier origins): + * + * "Optimistic Sorting and Information Theoretic Complexity" + * Peter McIlroy + * SODA (Fourth Annual ACM-SIAM Symposium on Discrete Algorithms), + * pp 467-474, Austin, Texas, 25-27 January 1993. + * + * While the API to this class consists solely of static methods, it is + * (privately) instantiable; a TimSort instance holds the state of an ongoing + * sort, assuming the input array is large enough to warrant the full-blown + * TimSort. Small arrays are sorted in place, using a binary insertion sort. + * + * @author Josh Bloch + */ +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 + * 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 = 32; + + /** + * The array being sorted. + */ + private final T[] a; + + /** + * The comparator for this sort. + */ + private final Comparator c; + + /** + * 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; + + /** + * This controls when we get *into* galloping mode. It is initialized + * to MIN_GALLOP. The mergeLo and mergeHi methods nudge it higher for + * random data, and lower for highly structured data. + */ + private int minGallop = MIN_GALLOP; + + /** + * Maximum initial size of tmp array, which is used for merging. The array + * can grow to accommodate demand. + * + * Unlike Tim's original C version, we do not allocate this much storage + * when sorting smaller arrays. This change was required for performance. + */ + private static final int INITIAL_TMP_STORAGE_LENGTH = 256; + + /** + * Temp storage for merges. A workspace array may optionally be + * provided in constructor, and if so will be used as long as it + * is big enough. + */ + private T[] tmp; + private int tmpBase; // base of tmp array slice + private int tmpLen; // length of tmp array slice + + /** + * 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] + * + * so we could cut the storage for this, but it's a minor amount, + * and keeping all the info explicit simplifies the code. + */ + private int stackSize = 0; // Number of pending runs on stack + private final int[] runBase; + private final int[] runLen; + + /** + * 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 workBase origin of usable space in work array + * @param workLen usable size of work array + */ + private FasterFinnSort(T[] a, Comparator c, T[] work, int workBase, int workLen) { + this.a = a; + this.c = c; + + // 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 + (a.getClass().getComponentType(), tlen); + tmp = newArray; + tmpBase = 0; + tmpLen = tlen; + } + else { + tmp = work; + tmpBase = workBase; + tmpLen = workLen; + } + + /* + * Allocate runs-to-be-merged stack (which cannot be expanded). The + * stack length requirements are described in listsort.txt. The C + * version always uses the same stack length (85), but this was + * measured to be too expensive when sorting "mid-sized" arrays (e.g., + * 100 elements) in Java. Therefore, we use smaller (but sufficiently + * large) stack lengths for smaller arrays. The "magic numbers" in the + * computation below must be changed if MIN_MERGE is decreased. See + * the MIN_MERGE declaration above for more information. + * The maximum value of 49 allows for an array up to length + * Integer.MAX_VALUE-4, if array is filled by the worst case stack size + * increasing scenario. More explanations are given in section 4 of: + * http://envisage-project.eu/wp-content/uploads/2015/02/sorting.pdf + */ + int stackLen = (len < 120 ? 5 : + len < 1542 ? 10 : + len < 119151 ? 24 : 49); + runBase = new int[stackLen]; + runLen = new int[stackLen]; + } + + /* + * The next method (package private and static) constitutes the + * entire API of this class. + */ + + /** + * Sorts the given range, using the given workspace array slice + * for temp storage when possible. This method is designed to be + * invoked from public methods (in class Arrays) after performing + * 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 workBase origin of usable space in work array + * @param workLen usable size of work array + * @since 1.8 + */ + static void sort(T[] a, int lo, int hi, Comparator c, + T[] work, int workBase, int workLen) { + assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length; + + 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); + return; + } + + /** + * March over the array once, left to right, finding natural runs, + * 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 = minRunLength(nRemaining); + do { + // Identify next run + int runLen = countRunAndMakeAscending(a, lo, hi, c); + + // If run is short, extend to min(minRun, nRemaining) + if (runLen < minRun) { + int force = nRemaining <= minRun ? nRemaining : minRun; + binarySort(a, lo, lo + force, lo + runLen, c); + runLen = force; + } + + // Push run onto pending-run stack, and maybe merge + ts.pushRun(lo, runLen); + ts.mergeCollapse(); + + // Advance to find next run + lo += runLen; + nRemaining -= runLen; + } while (nRemaining != 0); + + // Merge all remaining runs to complete sort + assert lo == hi; + ts.mergeForceCollapse(); + assert ts.stackSize == 1; + } + + /** + * Sorts the specified portion of the specified array using a binary + * 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 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 + */ + @SuppressWarnings("fallthrough") + private static void binarySort(T[] a, int lo, int hi, int start, + Comparator c) { + assert lo <= start && start <= hi; + if (start == lo) + start++; + for ( ; start < hi; start++) { + T pivot = a[start]; + + // Set left (and right) to the index where a[start] (pivot) belongs + int left = lo; + int right = start; + assert left <= right; + /* + * Invariants: + * pivot >= all in [lo, left). + * pivot < all in [right, start). + */ + while (left < right) { + int mid = (left + right) >>> 1; + if (c.compare(pivot, a[mid]) < 0) + right = mid; + else + left = mid + 1; + } + assert left == right; + + /* + * The invariants still hold: pivot >= all in [lo, left) and + * pivot < all in [left, start), so pivot belongs at left. Note + * that if there are elements equal to pivot, left points to the + * first slot after them -- that's why this sort is stable. + * Slide elements over to make room for pivot. + */ + int n = start - left; // The number of elements to move + // Switch is just an optimization for arraycopy in default case + switch (n) { + case 2: a[left + 2] = a[left + 1]; + case 1: a[left + 1] = a[left]; + break; + default: System.arraycopy(a, left, a, left + 1, n); + } + a[left] = pivot; + } + } + + /** + * 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] <= ... + * + * or the longest descending sequence with: + * + * 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 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 + */ + private static int countRunAndMakeAscending(T[] a, int lo, int hi, + Comparator c) { + assert lo < hi; + int runHi = lo + 1; + if (runHi == hi) + return 1; + + // Find end of run, and reverse range if descending + if (c.compare(a[runHi++], a[lo]) < 0) { // Descending + while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0) + runHi++; + reverseRange(a, lo, runHi); + } else { // Ascending + while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0) + runHi++; + } + + return runHi - lo; + } + + /** + * Reverse the specified range of the specified array. + * + * @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 + */ + private static void reverseRange(Object[] a, int lo, int hi) { + hi--; + while (lo < hi) { + Object t = a[lo]; + a[lo++] = a[hi]; + a[hi--] = t; + } + } + + /** + * 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. + * + * For the rationale, see listsort.txt. + * + * @param n the length of the array to be sorted + * @return the length of the minimum run to be merged + */ + private static int minRunLength(int n) { + assert n >= 0; + int r = 0; // Becomes 1 if any 1 bits are shifted off + while (n >= MIN_MERGE) { + r |= (n & 1); + n >>= 1; + } + return n + r; + } + + /** + * Pushes the specified run onto the pending-run stack. + * + * @param runBase index of the first element in the run + * @param runLen the number of elements in the run + */ + private void pushRun(int runBase, int runLen) { + this.runBase[stackSize] = runBase; + this.runLen[stackSize] = runLen; + 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] + * + * 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 + * Nicolas Auger, Vincent Jug, Cyril Nicaud, and Carine Pivoteau. + */ + private void mergeCollapse() { + while (stackSize > 1) { + int n = stackSize - 2; + if (n > 0 && runLen[n-1] <= runLen[n] + runLen[n+1] || + n > 1 && runLen[n-2] <= runLen[n] + runLen[n-1]) { + if (runLen[n - 1] < runLen[n + 1]) + n--; + } else if (n < 0 || runLen[n] > runLen[n + 1]) { + break; // Invariant is established + } + mergeAt(n); + } + } + /* + Backup mergeCollapse() von TimSort: + + private void mergeCollapse() { + while (stackSize > 1) { + int n = stackSize - 2; + if (n > 0 && runLen[n-1] <= runLen[n] + runLen[n+1] || + n > 1 && runLen[n-2] <= runLen[n] + runLen[n-1]) { + if (runLen[n - 1] < runLen[n + 1]) + n--; + } else if (n < 0 || runLen[n] > runLen[n + 1]) { + break; // Invariant is established + } + mergeAt(n); + } + } + + */ + + /** + * Merges all runs on the stack until only one remains. This method is + * called once, to complete the sort. + */ + private void mergeForceCollapse() { + while (stackSize > 1) { + int n = stackSize - 2; + if (n > 0 && runLen[n - 1] < runLen[n + 1]) + n--; + mergeAt(n); + } + } + + /** + * Merges the two runs at stack indices i and i+1. Run i must be + * the penultimate or antepenultimate run on the stack. In other words, + * i must be equal to stackSize-2 or stackSize-3. + * + * @param i stack index of the first of the two runs to merge + */ + private void mergeAt(int i) { + assert stackSize >= 2; + assert i >= 0; + assert i == stackSize - 2 || i == stackSize - 3; + + int base1 = runBase[i]; + int len1 = runLen[i]; + int base2 = runBase[i + 1]; + int len2 = runLen[i + 1]; + assert len1 > 0 && len2 > 0; + assert base1 + len1 == base2; + + /* + * Record the length of the combined runs; if i is the 3rd-last + * 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--; + + /* + * Find where the first element of run2 goes in run1. Prior elements + * in run1 can be ignored (because they're already in place). + */ + int k = gallopRight(a[base2], a, base1, len1, 0, c); + assert k >= 0; + base1 += k; + len1 -= k; + if (len1 == 0) + return; + + /* + * Find where the last element of run1 goes in run2. Subsequent elements + * in run2 can be ignored (because they're already in place). + */ + len2 = gallopLeft(a[base1 + len1 - 1], a, base2, len2, len2 - 1, c); + assert len2 >= 0; + if (len2 == 0) + return; + + // Merge remaining runs, using tmp array with min(len1, len2) elements + if (len1 <= len2) + mergeLo(base1, len1, base2, len2); + else + mergeHi(base1, len1, base2, len2); + } + + /** + * Locates the position at which to insert the specified key into the + * specified sorted range; if the range contains an element equal to key, + * returns the index of the leftmost equal element. + * + * @param key the key whose insertion point to search for + * @param a the array in which to search + * @param base the index of the first element in the range + * @param len the length of the range; must be > 0 + * @param hint the index at which to begin the search, 0 <= hint < n. + * The closer hint is to the result, the faster this method will run. + * @param c the comparator used to order the range, and to search + * @return the int k, 0 <= k <= n such that a[b + k - 1] < key <= a[b + k], + * pretending that a[b - 1] is minus infinity and a[b + n] is infinity. + * In other words, key belongs at index b + k; or in other words, + * the first k elements of a should precede key, and the last n - k + * should follow it. + */ + private static int gallopLeft(T key, T[] a, int base, int len, int hint, + Comparator c) { + assert len > 0 && hint >= 0 && hint < len; + int lastOfs = 0; + int ofs = 1; + if (c.compare(key, a[base + hint]) > 0) { + // Gallop right until a[base+hint+lastOfs] < key <= a[base+hint+ofs] + int maxOfs = len - hint; + while (ofs < maxOfs && c.compare(key, a[base + hint + ofs]) > 0) { + lastOfs = ofs; + ofs = (ofs << 1) + 1; + if (ofs <= 0) // int overflow + ofs = maxOfs; + } + if (ofs > maxOfs) + ofs = maxOfs; + + // Make offsets relative to base + lastOfs += hint; + ofs += hint; + } else { // key <= a[base + hint] + // Gallop left until a[base+hint-ofs] < key <= a[base+hint-lastOfs] + final int maxOfs = hint + 1; + while (ofs < maxOfs && c.compare(key, a[base + hint - ofs]) <= 0) { + lastOfs = ofs; + ofs = (ofs << 1) + 1; + if (ofs <= 0) // int overflow + ofs = maxOfs; + } + if (ofs > maxOfs) + ofs = maxOfs; + + // Make offsets relative to base + int tmp = lastOfs; + lastOfs = hint - ofs; + ofs = hint - tmp; + } + assert -1 <= lastOfs && lastOfs < ofs && ofs <= len; + + /* + * Now a[base+lastOfs] < key <= a[base+ofs], so key belongs somewhere + * to the right of lastOfs but no farther right than ofs. Do a binary + * search, with invariant a[base + lastOfs - 1] < key <= a[base + ofs]. + */ + lastOfs++; + while (lastOfs < ofs) { + int m = lastOfs + ((ofs - lastOfs) >>> 1); + + if (c.compare(key, a[base + m]) > 0) + lastOfs = m + 1; // a[base + m] < key + else + ofs = m; // key <= a[base + m] + } + assert lastOfs == ofs; // so a[base + ofs - 1] < key <= a[base + ofs] + return ofs; + } + + /** + * Like gallopLeft, except that if the range contains an element equal to + * key, gallopRight returns the index after the rightmost equal element. + * + * @param key the key whose insertion point to search for + * @param a the array in which to search + * @param base the index of the first element in the range + * @param len the length of the range; must be > 0 + * @param hint the index at which to begin the search, 0 <= hint < n. + * The closer hint is to the result, the faster this method will run. + * @param c the comparator used to order the range, and to search + * @return the int k, 0 <= k <= n such that a[b + k - 1] <= key < a[b + k] + */ + private static int gallopRight(T key, T[] a, int base, int len, + int hint, Comparator c) { + assert len > 0 && hint >= 0 && hint < len; + + int ofs = 1; + int lastOfs = 0; + if (c.compare(key, a[base + hint]) < 0) { + // Gallop left until a[b+hint - ofs] <= key < a[b+hint - lastOfs] + int maxOfs = hint + 1; + while (ofs < maxOfs && c.compare(key, a[base + hint - ofs]) < 0) { + lastOfs = ofs; + ofs = (ofs << 1) + 1; + if (ofs <= 0) // int overflow + ofs = maxOfs; + } + if (ofs > maxOfs) + ofs = maxOfs; + + // Make offsets relative to b + int tmp = lastOfs; + lastOfs = hint - ofs; + ofs = hint - tmp; + } else { // a[b + hint] <= key + // Gallop right until a[b+hint + lastOfs] <= key < a[b+hint + ofs] + int maxOfs = len - hint; + while (ofs < maxOfs && c.compare(key, a[base + hint + ofs]) >= 0) { + lastOfs = ofs; + ofs = (ofs << 1) + 1; + if (ofs <= 0) // int overflow + ofs = maxOfs; + } + if (ofs > maxOfs) + ofs = maxOfs; + + // Make offsets relative to b + lastOfs += hint; + ofs += hint; + } + assert -1 <= lastOfs && lastOfs < ofs && ofs <= len; + + /* + * Now a[b + lastOfs] <= key < a[b + ofs], so key belongs somewhere to + * the right of lastOfs but no farther right than ofs. Do a binary + * search, with invariant a[b + lastOfs - 1] <= key < a[b + ofs]. + */ + lastOfs++; + while (lastOfs < ofs) { + int m = lastOfs + ((ofs - lastOfs) >>> 1); + + if (c.compare(key, a[base + m]) < 0) + ofs = m; // key < a[b + m] + else + lastOfs = m + 1; // a[b + m] <= key + } + assert lastOfs == ofs; // so a[b + ofs - 1] <= key < a[b + ofs] + return ofs; + } + + /** + * Merges two adjacent runs in place, in a stable fashion. The first + * element of the first run must be greater than the first element of the + * second run (a[base1] > a[base2]), and the last element of the first run + * (a[base1 + len1-1]) must be greater than all elements of the second run. + * + * For performance, this method should be called only when len1 <= len2; + * its twin, mergeHi should be called if len1 >= len2. (Either method + * may be called if len1 == len2.) + * + * @param base1 index of first element in first run to be merged + * @param len1 length of first run to be merged (must be > 0) + * @param base2 index of first element in second run to be merged + * (must be aBase + aLen) + * @param len2 length of second run to be merged (must be > 0) + */ + private void mergeLo(int base1, int len1, int base2, int len2) { + assert len1 > 0 && len2 > 0 && base1 + len1 == base2; + + // Copy first run into temp array + T[] a = this.a; // For performance + T[] tmp = ensureCapacity(len1); + int cursor1 = tmpBase; // Indexes into tmp array + int cursor2 = base2; // Indexes int a + int dest = base1; // Indexes int a + System.arraycopy(a, base1, tmp, cursor1, len1); + + // Move first element of second run and deal with degenerate cases + a[dest++] = a[cursor2++]; + if (--len2 == 0) { + System.arraycopy(tmp, cursor1, a, dest, len1); + return; + } + if (len1 == 1) { + System.arraycopy(a, cursor2, a, dest, len2); + a[dest + len2] = tmp[cursor1]; // Last elt of run 1 to end of merge + return; + } + + Comparator c = this.c; // Use local variable for performance + int minGallop = this.minGallop; // " " " " " + outer: + while (true) { + int count1 = 0; // Number of times in a row that first run won + int count2 = 0; // Number of times in a row that second run won + + /* + * Do the straightforward thing until (if ever) one run starts + * winning consistently. + */ + do { + assert len1 > 1 && len2 > 0; + if (c.compare(a[cursor2], tmp[cursor1]) < 0) { + a[dest++] = a[cursor2++]; + count2++; + count1 = 0; + if (--len2 == 0) + break outer; + } else { + a[dest++] = tmp[cursor1++]; + count1++; + count2 = 0; + if (--len1 == 1) + break outer; + } + } while ((count1 | count2) < minGallop); + + /* + * One run is winning so consistently that galloping may be a + * huge win. So try that, and continue galloping until (if ever) + * neither run appears to be winning consistently anymore. + */ + do { + assert len1 > 1 && len2 > 0; + count1 = gallopRight(a[cursor2], tmp, cursor1, len1, 0, c); + if (count1 != 0) { + System.arraycopy(tmp, cursor1, a, dest, count1); + dest += count1; + cursor1 += count1; + len1 -= count1; + if (len1 <= 1) // len1 == 1 || len1 == 0 + break outer; + } + a[dest++] = a[cursor2++]; + if (--len2 == 0) + break outer; + + count2 = gallopLeft(tmp[cursor1], a, cursor2, len2, 0, c); + if (count2 != 0) { + System.arraycopy(a, cursor2, a, dest, count2); + dest += count2; + cursor2 += count2; + len2 -= count2; + if (len2 == 0) + break outer; + } + a[dest++] = tmp[cursor1++]; + if (--len1 == 1) + break outer; + minGallop--; + } while (count1 >= MIN_GALLOP | count2 >= MIN_GALLOP); + if (minGallop < 0) + minGallop = 0; + minGallop += 2; // Penalize for leaving gallop mode + } // End of "outer" loop + this.minGallop = minGallop < 1 ? 1 : minGallop; // Write back to field + + if (len1 == 1) { + assert len2 > 0; + System.arraycopy(a, cursor2, a, dest, len2); + a[dest + len2] = tmp[cursor1]; // Last elt of run 1 to end of merge + } else if (len1 == 0) { + throw new IllegalArgumentException( + "Comparison method violates its general contract!"); + } else { + assert len2 == 0; + assert len1 > 1; + System.arraycopy(tmp, cursor1, a, dest, len1); + } + } + + /** + * Like mergeLo, except that this method should be called only if + * len1 >= len2; mergeLo should be called if len1 <= len2. (Either method + * may be called if len1 == len2.) + * + * @param base1 index of first element in first run to be merged + * @param len1 length of first run to be merged (must be > 0) + * @param base2 index of first element in second run to be merged + * (must be aBase + aLen) + * @param len2 length of second run to be merged (must be > 0) + */ + private void mergeHi(int base1, int len1, int base2, int len2) { + assert len1 > 0 && len2 > 0 && base1 + len1 == base2; + + // Copy second run into temp array + T[] a = this.a; // For performance + T[] tmp = ensureCapacity(len2); + int tmpBase = this.tmpBase; + System.arraycopy(a, base2, tmp, tmpBase, len2); + + int cursor1 = base1 + len1 - 1; // Indexes into a + int cursor2 = tmpBase + len2 - 1; // Indexes into tmp array + int dest = base2 + len2 - 1; // Indexes into a + + // Move last element of first run and deal with degenerate cases + a[dest--] = a[cursor1--]; + if (--len1 == 0) { + System.arraycopy(tmp, tmpBase, a, dest - (len2 - 1), len2); + return; + } + if (len2 == 1) { + dest -= len1; + cursor1 -= len1; + System.arraycopy(a, cursor1 + 1, a, dest + 1, len1); + a[dest] = tmp[cursor2]; + return; + } + + Comparator c = this.c; // Use local variable for performance + int minGallop = this.minGallop; // " " " " " + outer: + while (true) { + int count1 = 0; // Number of times in a row that first run won + int count2 = 0; // Number of times in a row that second run won + + /* + * Do the straightforward thing until (if ever) one run + * appears to win consistently. + */ + do { + assert len1 > 0 && len2 > 1; + if (c.compare(tmp[cursor2], a[cursor1]) < 0) { + a[dest--] = a[cursor1--]; + count1++; + count2 = 0; + if (--len1 == 0) + break outer; + } else { + a[dest--] = tmp[cursor2--]; + count2++; + count1 = 0; + if (--len2 == 1) + break outer; + } + } while ((count1 | count2) < minGallop); + + /* + * One run is winning so consistently that galloping may be a + * huge win. So try that, and continue galloping until (if ever) + * neither run appears to be winning consistently anymore. + */ + do { + assert len1 > 0 && len2 > 1; + count1 = len1 - gallopRight(tmp[cursor2], a, base1, len1, len1 - 1, c); + if (count1 != 0) { + dest -= count1; + cursor1 -= count1; + len1 -= count1; + System.arraycopy(a, cursor1 + 1, a, dest + 1, count1); + if (len1 == 0) + break outer; + } + a[dest--] = tmp[cursor2--]; + if (--len2 == 1) + break outer; + + count2 = len2 - gallopLeft(a[cursor1], tmp, tmpBase, len2, len2 - 1, c); + if (count2 != 0) { + dest -= count2; + cursor2 -= count2; + len2 -= count2; + System.arraycopy(tmp, cursor2 + 1, a, dest + 1, count2); + if (len2 <= 1) // len2 == 1 || len2 == 0 + break outer; + } + a[dest--] = a[cursor1--]; + if (--len1 == 0) + break outer; + minGallop--; + } while (count1 >= MIN_GALLOP | count2 >= MIN_GALLOP); + if (minGallop < 0) + minGallop = 0; + minGallop += 2; // Penalize for leaving gallop mode + } // End of "outer" loop + this.minGallop = minGallop < 1 ? 1 : minGallop; // Write back to field + + if (len2 == 1) { + assert len1 > 0; + dest -= len1; + cursor1 -= len1; + System.arraycopy(a, cursor1 + 1, a, dest + 1, len1); + a[dest] = tmp[cursor2]; // Move first elt of run2 to front of merge + } else if (len2 == 0) { + throw new IllegalArgumentException( + "Comparison method violates its general contract!"); + } else { + assert len1 == 0; + assert len2 > 0; + System.arraycopy(tmp, tmpBase, a, dest - (len2 - 1), len2); + } + } + + /** + * Ensures that the external array tmp has at least the specified + * number of elements, increasing its size if necessary. The size + * increases exponentially to ensure amortized linear time complexity. + * + * @param minCapacity the minimum required capacity of the tmp array + * @return tmp, whether or not it grew + */ + private T[] ensureCapacity(int minCapacity) { + if (tmpLen < minCapacity) { + // Compute smallest power of 2 > minCapacity + int newSize = -1 >>> Integer.numberOfLeadingZeros(minCapacity); + newSize++; + + if (newSize < 0) // Not bloody likely! + newSize = minCapacity; + else + newSize = Math.min(newSize, a.length >>> 1); + + @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"}) + T[] newArray = (T[])java.lang.reflect.Array.newInstance + (a.getClass().getComponentType(), newSize); + tmp = newArray; + tmpLen = newSize; + tmpBase = 0; + } + return tmp; + } +} From e182ecc756994645f6ae789c8f16904e833d75d3 Mon Sep 17 00:00:00 2001 From: finnm Date: Mon, 16 Dec 2024 22:50:51 +0100 Subject: [PATCH 28/35] Fixed FinnSort: Cleared runs for every method call --- .../uni_marburg/powersort/FinnSort/FinnSort.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java b/app/src/main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java index cb236e8..1981b0b 100644 --- a/app/src/main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java +++ b/app/src/main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java @@ -5,10 +5,12 @@ import static java.lang.Math.*; public class FinnSort { - private static final ArrayList runs = new ArrayList<>(); + private static ArrayList runs; public static void sort(T[] a, Comparator c) { + runs = new ArrayList<>(); + int n = a.length; int i = 0; int j = extendRunRight(a, i, c); @@ -42,14 +44,22 @@ public class FinnSort { ArrayList run2 = new ArrayList<>(Arrays.asList(a).subList(r2.start, r2.end)); ArrayList merge = new ArrayList<>(); - while (!run1.isEmpty() || !run2.isEmpty()) { - if (run2.isEmpty() || !run1.isEmpty() && c.compare(run1.getFirst(), run2.getFirst()) < 0) { + while (!run1.isEmpty() && !run2.isEmpty()) { + if (c.compare(run1.getFirst(), run2.getFirst()) < 0) { merge.add(run1.removeFirst()); } else { merge.add(run2.removeFirst()); } } + while (!run1.isEmpty()) { + merge.add(run1.removeFirst()); + } + + while (!run2.isEmpty()) { + merge.add(run2.removeFirst()); + } + System.arraycopy(merge.toArray(), 0, a, min(r1.start, r2.start), merge.size()); Run r = new Run(min(r1.start, r2.start), max(r1.end, r2.end), min(r1.power, r2.power)); runs.add(r); From a782d8c1fa6f265644e6fb4c44250f43c0b36e19 Mon Sep 17 00:00:00 2001 From: Daniel Langbein Date: Tue, 17 Dec 2024 08:26:56 +0000 Subject: [PATCH 29/35] add sort test --- .../powersort/sort/AbstractSortTest.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/app/src/test/java/de/uni_marburg/powersort/sort/AbstractSortTest.java b/app/src/test/java/de/uni_marburg/powersort/sort/AbstractSortTest.java index b058a10..aba63c0 100644 --- a/app/src/test/java/de/uni_marburg/powersort/sort/AbstractSortTest.java +++ b/app/src/test/java/de/uni_marburg/powersort/sort/AbstractSortTest.java @@ -2,6 +2,7 @@ package de.uni_marburg.powersort.sort; import de.uni_marburg.powersort.JUnitUtil; import de.uni_marburg.powersort.data.AscendingRuns; +import de.uni_marburg.powersort.data.DescendingIntegers; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.converter.ConvertWith; import org.junit.jupiter.params.provider.CsvSource; @@ -17,9 +18,8 @@ public abstract class AbstractSortTest { @CsvSource({ "''", "1337", - "3|2|1", + "|2|3|1", "1|1", - "2|1", "2|1|2", }) void test1(@ConvertWith(JUnitUtil.IntegerArrayConverter.class) Integer[] array) { @@ -35,6 +35,17 @@ public abstract class AbstractSortTest { Integer[] array = AscendingRuns.newAscendingRuns(numOfRuns, runLength, decreaseBetweenRuns).getCopy(); sortAndCheckResult(array); } + @ParameterizedTest + @CsvSource({ + "2", + "3", + "13", + "1337", + }) + void test2(int size) { + Integer[] array = new DescendingIntegers(size).getCopy(); + sortAndCheckResult(array); + } void sortAndCheckResult(Integer[] array){ Integer[] expected = Arrays.copyOf(array, array.length); From c3ecfc5531508f30c541dc22c03ed01f9b571101 Mon Sep 17 00:00:00 2001 From: Daniel Langbein Date: Tue, 17 Dec 2024 08:28:09 +0000 Subject: [PATCH 30/35] benchmark: rm ObjectSupplier.title --- .../main/java/de/uni_marburg/powersort/benchmark/Main.java | 2 +- .../de/uni_marburg/powersort/data/AscendingIntegers.java | 6 ------ .../java/de/uni_marburg/powersort/data/AscendingRuns.java | 5 ----- .../de/uni_marburg/powersort/data/DescendingIntegers.java | 6 ------ .../java/de/uni_marburg/powersort/data/ObjectSupplier.java | 5 ----- .../java/de/uni_marburg/powersort/data/RandomIntegers.java | 6 ------ 6 files changed, 1 insertion(+), 29 deletions(-) diff --git a/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java b/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java index c70bfcc..5335757 100644 --- a/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java +++ b/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java @@ -17,7 +17,7 @@ public class Main { for (DataEnum dataEnum : dataEnums) { ObjectSupplier objectSupplier = dataEnum.get(); - System.out.println("\n" + objectSupplier.title()); + System.out.println(dataEnum); for (SortEnum sortImplementation : sortImplementations) { Object[] sortInput = objectSupplier.getCopy(); diff --git a/app/src/main/java/de/uni_marburg/powersort/data/AscendingIntegers.java b/app/src/main/java/de/uni_marburg/powersort/data/AscendingIntegers.java index 8050a21..c7d89f8 100644 --- a/app/src/main/java/de/uni_marburg/powersort/data/AscendingIntegers.java +++ b/app/src/main/java/de/uni_marburg/powersort/data/AscendingIntegers.java @@ -1,15 +1,9 @@ package de.uni_marburg.powersort.data; import de.uni_marburg.powersort.benchmark.IntegerArray; -import de.uni_marburg.powersort.benchmark.LongFormatter; public class AscendingIntegers extends IntegerSupplier { public AscendingIntegers(int size) { super(IntegerArray.ascending( 1, size)); } - - @Override - public String title() { - return "Array of " + LongFormatter.formatUnderscore(readOnly.length) + " ascending Integer objects."; - } } diff --git a/app/src/main/java/de/uni_marburg/powersort/data/AscendingRuns.java b/app/src/main/java/de/uni_marburg/powersort/data/AscendingRuns.java index be1a221..ed80f54 100644 --- a/app/src/main/java/de/uni_marburg/powersort/data/AscendingRuns.java +++ b/app/src/main/java/de/uni_marburg/powersort/data/AscendingRuns.java @@ -32,9 +32,4 @@ public class AscendingRuns extends IntegerSupplier { private AscendingRuns(Integer[] readonly) { super(readonly); } - - @Override - public String title() { - return "Array of Integer objects with ascending runs"; - } } diff --git a/app/src/main/java/de/uni_marburg/powersort/data/DescendingIntegers.java b/app/src/main/java/de/uni_marburg/powersort/data/DescendingIntegers.java index 70a8f15..d72745d 100644 --- a/app/src/main/java/de/uni_marburg/powersort/data/DescendingIntegers.java +++ b/app/src/main/java/de/uni_marburg/powersort/data/DescendingIntegers.java @@ -1,15 +1,9 @@ package de.uni_marburg.powersort.data; import de.uni_marburg.powersort.benchmark.IntegerArray; -import de.uni_marburg.powersort.benchmark.LongFormatter; public class DescendingIntegers extends IntegerSupplier { public DescendingIntegers(int size) { super(IntegerArray.descending(size, 1)); } - - @Override - public String title() { - return "Array of " + LongFormatter.formatUnderscore(readOnly.length) + " descending Integer objects."; - } } diff --git a/app/src/main/java/de/uni_marburg/powersort/data/ObjectSupplier.java b/app/src/main/java/de/uni_marburg/powersort/data/ObjectSupplier.java index e1bd1c8..f4c1fa8 100644 --- a/app/src/main/java/de/uni_marburg/powersort/data/ObjectSupplier.java +++ b/app/src/main/java/de/uni_marburg/powersort/data/ObjectSupplier.java @@ -9,11 +9,6 @@ public abstract class ObjectSupplier { this.readOnly = readOnly; } - /** - * Descriptive title for the array of objects represented by this object. - */ - public abstract String title(); - /** * @return A fresh copy of the array of objects represented by this object. */ diff --git a/app/src/main/java/de/uni_marburg/powersort/data/RandomIntegers.java b/app/src/main/java/de/uni_marburg/powersort/data/RandomIntegers.java index f7b85ee..6f0ff47 100644 --- a/app/src/main/java/de/uni_marburg/powersort/data/RandomIntegers.java +++ b/app/src/main/java/de/uni_marburg/powersort/data/RandomIntegers.java @@ -1,15 +1,9 @@ package de.uni_marburg.powersort.data; import de.uni_marburg.powersort.benchmark.IntegerArray; -import de.uni_marburg.powersort.benchmark.LongFormatter; public class RandomIntegers extends IntegerSupplier { public RandomIntegers(final int size, final long seed) { super(IntegerArray.random(size, seed)); } - - @Override - public String title() { - return "Array of " + LongFormatter.formatUnderscore(readOnly.length) + " random Integer objects."; - } } From 6b0a5394b19115584a362134c8fad3a37403c9b8 Mon Sep 17 00:00:00 2001 From: Daniel Langbein Date: Tue, 17 Dec 2024 08:34:57 +0000 Subject: [PATCH 31/35] benchmark: refactor --- .../jmh/java/de/uni_marburg/powersort/benchmark/MainJmh.java | 4 ++-- .../main/java/de/uni_marburg/powersort/benchmark/Main.java | 4 ++-- app/src/main/java/de/uni_marburg/powersort/data/DataEnum.java | 2 +- app/src/main/java/de/uni_marburg/powersort/sort/SortEnum.java | 2 +- .../powersort/sort/{SimpleSort.java => SortImpl.java} | 2 +- .../java/de/uni_marburg/powersort/sort/AbstractSortTest.java | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) rename app/src/main/java/de/uni_marburg/powersort/sort/{SimpleSort.java => SortImpl.java} (70%) diff --git a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/MainJmh.java b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/MainJmh.java index d0151f6..31cb83e 100644 --- a/app/src/jmh/java/de/uni_marburg/powersort/benchmark/MainJmh.java +++ b/app/src/jmh/java/de/uni_marburg/powersort/benchmark/MainJmh.java @@ -49,7 +49,7 @@ public class MainJmh { // A new MainJmh object is created for each @Param variation. // Then, `data` is `null` again. if (data == null) { - data = dataEnum.get(); + data = dataEnum.getObjectSupplier(); } // For all warmup and measurement iterations of one @Param variation, the MainJmh object is reused. // Thus, we can't just sort `data` directly. @@ -60,6 +60,6 @@ public class MainJmh { @Benchmark public void benchmark() { - sortEnum.get().sort(workingCopy); + sortEnum.getSortImpl().sort(workingCopy); } } diff --git a/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java b/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java index 5335757..917446f 100644 --- a/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java +++ b/app/src/main/java/de/uni_marburg/powersort/benchmark/Main.java @@ -16,7 +16,7 @@ public class Main { final EnumSet dataEnums = getSortInputSuppliers(); for (DataEnum dataEnum : dataEnums) { - ObjectSupplier objectSupplier = dataEnum.get(); + ObjectSupplier objectSupplier = dataEnum.getObjectSupplier(); System.out.println(dataEnum); for (SortEnum sortImplementation : sortImplementations) { @@ -24,7 +24,7 @@ public class Main { // TODO: JVM warmup! final long startNanos = System.nanoTime(); - sortImplementation.get().sort(sortInput); + sortImplementation.getSortImpl().sort(sortInput); final long stopNanos = System.nanoTime(); final long durNanos = stopNanos - startNanos; diff --git a/app/src/main/java/de/uni_marburg/powersort/data/DataEnum.java b/app/src/main/java/de/uni_marburg/powersort/data/DataEnum.java index ff9de0a..243f838 100644 --- a/app/src/main/java/de/uni_marburg/powersort/data/DataEnum.java +++ b/app/src/main/java/de/uni_marburg/powersort/data/DataEnum.java @@ -7,7 +7,7 @@ public enum DataEnum { ASCENDING_RUNS, ASCENDING_RUNS_WITH_OVERLAP; - public ObjectSupplier get() { + public ObjectSupplier getObjectSupplier() { // We use a seed to get the same random list every time -> Repeatable benchmarks on same input data! // final long seed = 3651660232967549736L; // System.nanoTime() ++ Math.random() final long seed = 140506881906827520L; // (long) 'P' * (long) 'O' *(long) 'W' * (long) 'E' * (long) 'R' * (long) 'S' * (long) 'O' * (long) 'R' * (long) 'T'; diff --git a/app/src/main/java/de/uni_marburg/powersort/sort/SortEnum.java b/app/src/main/java/de/uni_marburg/powersort/sort/SortEnum.java index f2c6bfe..1b636d9 100644 --- a/app/src/main/java/de/uni_marburg/powersort/sort/SortEnum.java +++ b/app/src/main/java/de/uni_marburg/powersort/sort/SortEnum.java @@ -10,7 +10,7 @@ public enum SortEnum { FIN_SORT, ASORT; - public SimpleSort get() { + public SortImpl getSortImpl() { return switch (this) { // case BUBBLE_SORT -> array -> BubbleSort.sort(array, NaturalOrder.INSTANCE); case MERGE_SORT -> array -> MergeSort.legacyMergeSort(array, NaturalOrder.INSTANCE); diff --git a/app/src/main/java/de/uni_marburg/powersort/sort/SimpleSort.java b/app/src/main/java/de/uni_marburg/powersort/sort/SortImpl.java similarity index 70% rename from app/src/main/java/de/uni_marburg/powersort/sort/SimpleSort.java rename to app/src/main/java/de/uni_marburg/powersort/sort/SortImpl.java index 79e993e..c47ec39 100644 --- a/app/src/main/java/de/uni_marburg/powersort/sort/SimpleSort.java +++ b/app/src/main/java/de/uni_marburg/powersort/sort/SortImpl.java @@ -1,5 +1,5 @@ package de.uni_marburg.powersort.sort; -public interface SimpleSort { +public interface SortImpl { void sort(Object[] list); } diff --git a/app/src/test/java/de/uni_marburg/powersort/sort/AbstractSortTest.java b/app/src/test/java/de/uni_marburg/powersort/sort/AbstractSortTest.java index aba63c0..09c771a 100644 --- a/app/src/test/java/de/uni_marburg/powersort/sort/AbstractSortTest.java +++ b/app/src/test/java/de/uni_marburg/powersort/sort/AbstractSortTest.java @@ -51,7 +51,7 @@ public abstract class AbstractSortTest { Integer[] expected = Arrays.copyOf(array, array.length); Arrays.sort(expected); - sortAlg.get().sort(array); + sortAlg.getSortImpl().sort(array); assertArrayEquals(expected, array); } } From 7a8f1c7f8db14256cfe8edb4d9f42b3418e0589e Mon Sep 17 00:00:00 2001 From: Daniel Langbein Date: Tue, 17 Dec 2024 08:40:04 +0000 Subject: [PATCH 32/35] fix: test data typo --- .../java/de/uni_marburg/powersort/sort/AbstractSortTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/test/java/de/uni_marburg/powersort/sort/AbstractSortTest.java b/app/src/test/java/de/uni_marburg/powersort/sort/AbstractSortTest.java index 09c771a..2c0e5a7 100644 --- a/app/src/test/java/de/uni_marburg/powersort/sort/AbstractSortTest.java +++ b/app/src/test/java/de/uni_marburg/powersort/sort/AbstractSortTest.java @@ -18,7 +18,7 @@ public abstract class AbstractSortTest { @CsvSource({ "''", "1337", - "|2|3|1", + "2|3|1", "1|1", "2|1|2", }) From b754184272198db6f53987d9a0438f3704c94985 Mon Sep 17 00:00:00 2001 From: Daniel Langbein Date: Tue, 17 Dec 2024 09:52:43 +0000 Subject: [PATCH 33/35] typo --- app/src/main/java/de/uni_marburg/powersort/sort/SortEnum.java | 4 ++-- .../test/java/de/uni_marburg/powersort/sort/FinnSortTest.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/de/uni_marburg/powersort/sort/SortEnum.java b/app/src/main/java/de/uni_marburg/powersort/sort/SortEnum.java index 1b636d9..976bfd8 100644 --- a/app/src/main/java/de/uni_marburg/powersort/sort/SortEnum.java +++ b/app/src/main/java/de/uni_marburg/powersort/sort/SortEnum.java @@ -7,7 +7,7 @@ public enum SortEnum { // BUBBLE_SORT, MERGE_SORT, TIM_SORT, - FIN_SORT, + FINN_SORT, ASORT; public SortImpl getSortImpl() { @@ -15,7 +15,7 @@ public enum SortEnum { // case BUBBLE_SORT -> array -> BubbleSort.sort(array, NaturalOrder.INSTANCE); case MERGE_SORT -> array -> MergeSort.legacyMergeSort(array, NaturalOrder.INSTANCE); case TIM_SORT -> array -> TimSort.sort(array, 0, array.length, NaturalOrder.INSTANCE, null, 0, 0); - case FIN_SORT -> array -> FinnSort.sort(array, NaturalOrder.INSTANCE); + case FINN_SORT -> array -> FinnSort.sort(array, NaturalOrder.INSTANCE); case ASORT -> array -> ASort.sort(array, NaturalOrder.INSTANCE); }; } diff --git a/app/src/test/java/de/uni_marburg/powersort/sort/FinnSortTest.java b/app/src/test/java/de/uni_marburg/powersort/sort/FinnSortTest.java index 17578ac..4ec57dd 100644 --- a/app/src/test/java/de/uni_marburg/powersort/sort/FinnSortTest.java +++ b/app/src/test/java/de/uni_marburg/powersort/sort/FinnSortTest.java @@ -2,6 +2,6 @@ package de.uni_marburg.powersort.sort; public class FinnSortTest extends AbstractSortTest { FinnSortTest() { - sortAlg = SortEnum.FIN_SORT; + sortAlg = SortEnum.FINN_SORT; } } From b1f94636c76b8d26151a4f6e8611978298a9f0af Mon Sep 17 00:00:00 2001 From: finnm Date: Tue, 17 Dec 2024 13:11:05 +0100 Subject: [PATCH 34/35] Removed Main Method from FinnSort --- .../java/de/uni_marburg/powersort/FinnSort/FinnSort.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/app/src/main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java b/app/src/main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java index 1981b0b..a0e4dbb 100644 --- a/app/src/main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java +++ b/app/src/main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java @@ -111,13 +111,4 @@ public class FinnSort { } System.out.println(s); } - - public static void main(String[] args) { - 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}; - - - sort(numbers, Comparator.naturalOrder()); - System.out.println("Result: "); - System.out.println(new ArrayList<>(List.of(numbers))); - } } \ No newline at end of file From 59bfd44f4595ef0e5a2d4c167abe975f4b398688 Mon Sep 17 00:00:00 2001 From: finnm Date: Tue, 17 Dec 2024 13:24:50 +0100 Subject: [PATCH 35/35] Fixed the merging order of FinnSort --- .../main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java b/app/src/main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java index a0e4dbb..341603f 100644 --- a/app/src/main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java +++ b/app/src/main/java/de/uni_marburg/powersort/FinnSort/FinnSort.java @@ -28,7 +28,7 @@ public class FinnSort { int p = power(runs.getLast(), new Run(i, j, 0), n); while (runs.size() >= 2 && p < power(runs.getLast(), runs.get(runs.size() - 2), n)) { - basicMerge(a, runs.removeFirst(), runs.removeFirst(), c); + basicMerge(a, runs.removeLast(), runs.removeLast(), c); } runs.add(new Run(i, j, p));