From 9ea1930da0ac0bea608c339c500f278a243b938e Mon Sep 17 00:00:00 2001 From: "Josiah (Gaming32) Glosson" Date: Wed, 24 Nov 2021 14:58:12 -0600 Subject: [PATCH 01/23] Remove Python dependency --- src/sorts/merge/OOPBufferedStoogeSort.java | 110 +++++ .../merge/OOPBufferedStoogeSort_backup.java | 115 +++++ src/sorts/merge/TimBufferedStoogeSort.java | 451 ++++++++++++++++++ src/utils/SortingNetworkGenerator.java | 184 +++---- src/utils/sorting_networks_min.py | 88 ++++ 5 files changed, 865 insertions(+), 83 deletions(-) create mode 100644 src/sorts/merge/OOPBufferedStoogeSort.java create mode 100644 src/sorts/merge/OOPBufferedStoogeSort_backup.java create mode 100644 src/sorts/merge/TimBufferedStoogeSort.java create mode 100644 src/utils/sorting_networks_min.py diff --git a/src/sorts/merge/OOPBufferedStoogeSort.java b/src/sorts/merge/OOPBufferedStoogeSort.java new file mode 100644 index 00000000..c42eb2a5 --- /dev/null +++ b/src/sorts/merge/OOPBufferedStoogeSort.java @@ -0,0 +1,110 @@ +package sorts.merge; + +import main.ArrayVisualizer; +import sorts.templates.Sort; + +/** + * @author _fluffyy + * @author thatsOven + * @author Gaming32 + */ +public class OOPBufferedStoogeSort extends Sort { + int[] aux; + + public OOPBufferedStoogeSort(ArrayVisualizer arrayVisualizer) { + super(arrayVisualizer); + this.setSortListName("OOP Buffered Stooge"); + this.setRunAllSortsName("OOP Buffered Stooge Sort"); + this.setRunSortName("OOP Buffered Stoogesort"); + this.setCategory("Merge Sorts"); + this.setComparisonBased(true); + this.setBucketSort(false); + this.setRadixSort(false); + this.setUnreasonablySlow(false); + this.setUnreasonableLimit(0); + this.setBogoSort(false); + } + + protected int compare(int[] arr, int x, int y) { + return Reads.compareIndices(arr, x, y, 0, true); + } + + protected void mergeOOP(int[] arr, int start, int mid, int end) { + Writes.arraycopy(arr, mid, aux, 0, end - mid, 1, true, true); + int auxPtr = end - mid - 1; + int left = mid - 1; + int right = end - 1; + Highlights.markArray(2, left); + while (right > left && left >= start) { + if (Reads.compareValues(aux[auxPtr], arr[left]) < 0) { + Writes.write(arr, right--, arr[left--], 1, true, false); + if (left >= 0) Highlights.markArray(2, left); + } else { + Writes.write(arr, right--, aux[auxPtr--], 1, true, false); + } + } + while (right > left) { + Writes.write(arr, right--, aux[auxPtr--], 1, true, false); + } + } + + public void wrapper(int[] arr, int start, int stop) { + if (stop - start > 1) { + if (stop - start == 2 && compare(arr, start, stop - 1) == 1) { + Writes.swap(arr, start, stop - 1, 1, true, false); + } + if (stop - start > 2) { + int third = (int) Math.ceil((stop - start) / 3.0) + start; + int twoThird = (int) Math.ceil((stop - start) / 3.0 * 2) + start; + if (twoThird - third < third) { + twoThird--; + } + if ((stop - start - 2) % 3 == 0) { + twoThird--; + } + wrapper(arr, third, twoThird); + wrapper(arr, twoThird, stop); + int left = third; + int right = twoThird; + int bufferStart = start; + while (left < twoThird && right < stop) { + if (compare(arr, left, right) < 0) { + Writes.swap(arr, bufferStart++, left++, 1, true, false); + } else { + Writes.swap(arr, bufferStart++, right++, 1, true, false); + } + } + while (right < stop) { + Writes.swap(arr, bufferStart++, right++, 1, true, false); + } + wrapper(arr, twoThird, stop); + if (stop - start > 8) { + if (stop > twoThird && twoThird > start) { + mergeOOP(arr, start, twoThird, stop); + } + } else { + int temp; + left = twoThird - 1; + right = stop - 1; + while (right > left && left >= start) { + if (compare(arr, left, right) > 0) { + temp = arr[left]; + Writes.arraycopy(arr, left + 1, arr, left, right - left, 0.5, true, false); + Writes.write(arr, right, temp, 0.5, true, false); + left--; + } + right--; + } + } + Highlights.clearMark(2); + } + } + } + + @Override + public void runSort(int[] array, int sortLength, int bucketCount) throws Exception { + aux = Writes.createExternalArray((sortLength + 2) / 3); + wrapper(array, 0, sortLength); + Writes.deleteExternalArray(aux); + } +} diff --git a/src/sorts/merge/OOPBufferedStoogeSort_backup.java b/src/sorts/merge/OOPBufferedStoogeSort_backup.java new file mode 100644 index 00000000..313311b1 --- /dev/null +++ b/src/sorts/merge/OOPBufferedStoogeSort_backup.java @@ -0,0 +1,115 @@ +package sorts.merge; + +import main.ArrayVisualizer; +import sorts.templates.Sort; + +/** + * @author _fluffyy + * @author thatsOven + * @author Gaming32 + */ +public class OOPBufferedStoogeSort_backup extends Sort { + int[] aux; + + public OOPBufferedStoogeSort_backup(ArrayVisualizer arrayVisualizer) { + super(arrayVisualizer); + this.setSortListName("OOP Buffered Stooge (old)"); + this.setRunAllSortsName("OOP Buffered Stooge Sort"); + this.setRunSortName("OOP Buffered Stoogesort"); + this.setCategory("Merge Sorts"); + this.setComparisonBased(true); + this.setBucketSort(false); + this.setRadixSort(false); + this.setUnreasonablySlow(false); + this.setUnreasonableLimit(0); + this.setBogoSort(false); + } + + protected int compare(int[] arr, int x, int y) { + return Reads.compareIndices(arr, x, y, 0, true); + } + + protected void mergeOOP(int[] arr, int start, int mid, int end) { + Writes.arraycopy(arr, mid, aux, 0, end - mid, 1, true, true); + int auxPtr = end - mid - 1; + int left = mid - 1; + int right = end - 1; + Highlights.markArray(2, left); + while (right > left && left >= start) { + if (Reads.compareValues(arr[left], aux[auxPtr]) > 0) { + Writes.write(arr, right--, arr[left--], 1, true, false); + if (left >= 0) Highlights.markArray(2, left); + } else { + Writes.write(arr, right--, aux[auxPtr--], 1, true, false); + } + } + while (right > left) { + Writes.write(arr, right--, aux[auxPtr--], 1, true, false); + } + } + + public void wrapper(int[] arr, int start, int stop) { + if (stop - start > 1) { + if (stop - start == 2 && compare(arr, start, stop - 1) == 1) { + Writes.swap(arr, start, stop - 1, 1, true, false); + } + if (stop - start > 2) { + int third = (int) Math.ceil((stop - start) / 3.0) + start; + int twoThird = (int) Math.ceil((stop - start) / 3.0 * 2) + start; + if (twoThird - third < third) { + twoThird--; + } + if ((stop - start - 2) % 3 == 0) { + twoThird--; + } + wrapper(arr, third, twoThird); + wrapper(arr, twoThird, stop); + int left = third; + int right = twoThird; + int bufferStart = start; + while (left < twoThird && right < stop) { + if (compare(arr, left, right) == 1) { + Writes.swap(arr, bufferStart, right, 1, true, false); + right++; + } else { + Writes.swap(arr, bufferStart, left, 1, true, false); + left++; + } + bufferStart++; + } + while (right < stop) { + Writes.swap(arr, bufferStart, right, 1, true, false); + right++; + bufferStart++; + } + wrapper(arr, twoThird, stop); + if (stop - start > 8) { + if (stop > twoThird && twoThird > start) { + mergeOOP(arr, start, twoThird, stop); + } + } else { + int temp; + left = twoThird - 1; + right = stop - 1; + while (right > left && left >= start) { + if (compare(arr, left, right) == 1) { + temp = arr[left]; + Writes.arraycopy(arr, left + 1, arr, left, right - left, 0.5, true, false); + Writes.write(arr, right, temp, 0.5, true, false); + left--; + } + right--; + } + } + Highlights.clearMark(2); + } + } + } + + @Override + public void runSort(int[] array, int sortLength, int bucketCount) throws Exception { + aux = Writes.createExternalArray((sortLength + 2) / 3); + wrapper(array, 0, sortLength); + Writes.deleteExternalArray(aux); + } +} diff --git a/src/sorts/merge/TimBufferedStoogeSort.java b/src/sorts/merge/TimBufferedStoogeSort.java new file mode 100644 index 00000000..404c99f7 --- /dev/null +++ b/src/sorts/merge/TimBufferedStoogeSort.java @@ -0,0 +1,451 @@ +package sorts.merge; + +import main.ArrayVisualizer; + +/** + * @author _fluffyy + * @author thatsOven + * @author Gaming32 + */ +public final class TimBufferedStoogeSort extends OOPBufferedStoogeSort { + int len; + int[] a, aux; + + private static final int MIN_GALLOP = 7; + private int minGallop; + + public TimBufferedStoogeSort(ArrayVisualizer arrayVisualizer) { + super(arrayVisualizer); + this.setSortListName("Tim Buffered Stooge"); + this.setRunAllSortsName("Tim Buffered Stooge Sort"); + this.setRunSortName("Tim Buffered Stoogesort"); + this.setCategory("Merge Sorts"); + this.setComparisonBased(true); + this.setBucketSort(false); + this.setRadixSort(false); + this.setUnreasonablySlow(false); + this.setUnreasonableLimit(0); + this.setBogoSort(false); + } + + private void markArray(int marker, int markPosition) { + if(markPosition >= 0 && markPosition < this.len) { + this.Highlights.markArray(marker, markPosition); + } + } + + private static int gallopLeft(TimBufferedStoogeSort ts, int key, int[] a, int base, int len, int hint) { + int lastOfs = 0; + int ofs = 1; + + ts.markArray(3, base + hint); + ts.Delays.sleep(1); + + if (ts.Reads.compareValues(key, a[base + hint]) > 0) { + // Gallop right until a[base+hint+lastOfs] < key <= a[base+hint+ofs] + int maxOfs = len - hint; + + ts.markArray(3, base + hint + ofs); + ts.Delays.sleep(1); + + while (ofs < maxOfs && ts.Reads.compareValues(key, a[base + hint + ofs]) > 0) { + lastOfs = ofs; + ofs = (ofs * 2) + 1; + if (ofs <= 0) // int overflow + ofs = maxOfs; + + ts.markArray(3, base + hint + ofs); + ts.Delays.sleep(1); + } + 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; + + ts.markArray(3, base + hint - ofs); + ts.Delays.sleep(1); + + while (ofs < maxOfs && ts.Reads.compareValues(key, a[base + hint - ofs]) <= 0) { + lastOfs = ofs; + ofs = (ofs * 2) + 1; + if (ofs <= 0) // int overflow + ofs = maxOfs; + + ts.markArray(3, base + hint - ofs); + ts.Delays.sleep(1); + } + if (ofs > maxOfs) + ofs = maxOfs; + + // Make offsets relative to base + int tmp = lastOfs; + lastOfs = hint - ofs; + ofs = hint - tmp; + } + + /* + * 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); + + ts.markArray(3, base + m); + ts.Delays.sleep(1); + + if (ts.Reads.compareValues(key, a[base + m]) > 0) + lastOfs = m + 1; // a[base + m] < key + else + ofs = m; // key <= a[base + m] + } + ts.Highlights.clearMark(3); + return ofs; + } + + private static int gallopRight(TimBufferedStoogeSort ts, int key, int[] a, int base, int len, int hint) { + int ofs = 1; + int lastOfs = 0; + + ts.markArray(3, base + hint); + ts.Delays.sleep(1); + + if (ts.Reads.compareValues(key, a[base + hint]) < 0) { + // Gallop left until a[b+hint - ofs] <= key < a[b+hint - lastOfs] + int maxOfs = hint + 1; + + ts.markArray(3, base + hint - ofs); + ts.Delays.sleep(1); + + while (ofs < maxOfs && ts.Reads.compareValues(key, a[base + hint - ofs]) < 0) { + lastOfs = ofs; + ofs = (ofs * 2) + 1; + if (ofs <= 0) // int overflow + ofs = maxOfs; + + ts.markArray(3, base + hint - ofs); + ts.Delays.sleep(1); + } + 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; + + ts.markArray(3, base + hint + ofs); + ts.Delays.sleep(1); + + while (ofs < maxOfs && ts.Reads.compareValues(key, a[base + hint + ofs]) >= 0) { + lastOfs = ofs; + ofs = (ofs * 2) + 1; + if (ofs <= 0) // int overflow + ofs = maxOfs; + + ts.markArray(3, base + hint + ofs); + ts.Delays.sleep(1); + } + if (ofs > maxOfs) + ofs = maxOfs; + + // Make offsets relative to b + lastOfs += hint; + ofs += hint; + } + + /* + * 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); + + ts.markArray(3, base + m); + ts.Delays.sleep(1); + + if (ts.Reads.compareValues(key, a[base + m]) < 0) + ofs = m; // key < a[b + m] + else + lastOfs = m + 1; // a[b + m] <= key + } + ts.Highlights.clearMark(3); + return ofs; + } + + private static void mergeLo(TimBufferedStoogeSort ts, int base1, int len1, int base2, int len2) { + // Copy first run into temp array + int[] a = ts.a; // For performance + int[] tmp = ts.aux; + ts.Writes.arraycopy(a, base1, tmp, 0, len1, 1, true, true); + + int cursor1 = 0; // Indexes into tmp array + int cursor2 = base2; // Indexes int a + int dest = base1; // Indexes int a + + // Move first element of second run and deal with degenerate cases + ts.Writes.write(a, dest++, a[cursor2++], 1, false, false); + ts.markArray(1, dest); + ts.markArray(2, cursor2); + if (--len2 == 0) { + ts.Writes.arraycopy(tmp, cursor1, a, dest, len1, 1, true, false); + return; + } + if (len1 == 1) { + ts.Writes.arraycopy(a, cursor2, a, dest, len2, 1, true, false); + ts.Writes.write(a, dest + len2, tmp[cursor1], 1, false, false); // Last elt of run 1 to end of merge + ts.markArray(1, dest + len2); + return; + } + + int minGallop = ts.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 { + if (ts.Reads.compareValues(a[cursor2], tmp[cursor1]) < 0) { + ts.Writes.write(a, dest++, a[cursor2++], 1, false, false); + ts.markArray(1, dest); + ts.markArray(2, cursor2); + count2++; + count1 = 0; + if (--len2 == 0) + break outer; + } else { + ts.Writes.write(a, dest++, tmp[cursor1++], 1, false, false); + ts.markArray(1, dest); + 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 { + count1 = gallopRight(ts, a[cursor2], tmp, cursor1, len1, 0); + if (count1 != 0) { + ts.Writes.arraycopy(tmp, cursor1, a, dest, count1, 1, true, false); + dest += count1; + cursor1 += count1; + len1 -= count1; + if (len1 <= 1) // len1 == 1 || len1 == 0 + break outer; + } + ts.Writes.write(a, dest++, a[cursor2++], 1, false, false); + ts.markArray(1, dest); + ts.markArray(2, cursor2); + if (--len2 == 0) + break outer; + + count2 = gallopLeft(ts, tmp[cursor1], a, cursor2, len2, 0); + if (count2 != 0) { + ts.Writes.arraycopy(a, cursor2, a, dest, count2, 1, true, false); + dest += count2; + cursor2 += count2; + len2 -= count2; + if (len2 == 0) + break outer; + } + ts.Writes.write(a, dest++, tmp[cursor1++], 1, false, false); + ts.markArray(1, dest); + 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 + ts.minGallop = minGallop < 1 ? 1 : minGallop; // Write back to field + + if (len1 == 1) { + ts.Writes.arraycopy(a, cursor2, a, dest, len2, 1, true, false); + ts.Writes.write(a, dest + len2, tmp[cursor1], 1, false, false); // Last elt of run 1 to end of merge + ts.markArray(1, dest + len2); + } else if (len1 == 0) { + throw new IllegalArgumentException( + "Comparison method violates its general contract!"); + } else { + ts.Writes.arraycopy(tmp, cursor1, a, dest, len1, 1, true, false); + } + } + + private static void mergeHi(TimBufferedStoogeSort ts, int base1, int len1, int base2, int len2) { + // Copy second run into temp array + int[] a = ts.a; // For performance + int[] tmp = ts.aux; + ts.Writes.arraycopy(a, base2, tmp, 0, len2, 1, true, true); + + int cursor1 = base1 + len1 - 1; // Indexes into a + int cursor2 = 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 + ts.Writes.write(a, dest--, a[cursor1--], 1, false, false); + ts.markArray(1, dest); + ts.markArray(2, cursor1); + if (--len1 == 0) { + ts.Writes.arraycopy(tmp, 0, a, dest - (len2 - 1), len2, 1, true, false); + return; + } + if (len2 == 1) { + dest -= len1; + cursor1 -= len1; + ts.Writes.arraycopy(a, cursor1 + 1, a, dest + 1, len1, 1, true, false); + ts.Writes.write(a, dest, tmp[cursor2], 1, false, false); + ts.markArray(1, dest); + return; + } + + int minGallop = ts.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 { + if (ts.Reads.compareValues(tmp[cursor2], a[cursor1]) < 0) { + ts.Writes.write(a, dest--, a[cursor1--], 1, false, false); + ts.markArray(1, dest); + ts.markArray(2, cursor1); + count1++; + count2 = 0; + if (--len1 == 0) + break outer; + } else { + ts.Writes.write(a, dest--, tmp[cursor2--], 1, false, false); + ts.markArray(1, dest); + 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 { + count1 = len1 - gallopRight(ts, tmp[cursor2], a, base1, len1, len1 - 1); + if (count1 != 0) { + dest -= count1; + cursor1 -= count1; + len1 -= count1; + ts.Writes.arraycopy(a, cursor1 + 1, a, dest + 1, count1, 1, true, false); + if (len1 == 0) + break outer; + } + ts.Writes.write(a, dest--, tmp[cursor2--], 1, false, false); + ts.markArray(1, dest); + if (--len2 == 1) + break outer; + + count2 = len2 - gallopLeft(ts, a[cursor1], tmp, 0, len2, len2 - 1); + if (count2 != 0) { + dest -= count2; + cursor2 -= count2; + len2 -= count2; + ts.Writes.arraycopy(tmp, cursor2 + 1, a, dest + 1, count2, 1, true, false); + if (len2 <= 1) // len2 == 1 || len2 == 0 + break outer; + } + ts.Writes.write(a, dest--, a[cursor1--], 1, false, false); + ts.markArray(1, dest); + ts.markArray(2, 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 + ts.minGallop = minGallop < 1 ? 1 : minGallop; // Write back to field + + if (len2 == 1) { + dest -= len1; + cursor1 -= len1; + ts.Writes.arraycopy(a, cursor1 + 1, a, dest + 1, len1, 1, true, false); + ts.Writes.write(a, dest, tmp[cursor2], 1, false, false); // Move first elt of run2 to front of merge + ts.markArray(1, dest); + } else if (len2 == 0) { + throw new IllegalArgumentException( + "Comparison method violates its general contract!"); + } else { + ts.Writes.arraycopy(tmp, 0, a, dest - (len2 - 1), len2, 1, true, false); + } + } + + @Override + protected void mergeOOP(int[] arr, int start, int mid, int end) { + this.Highlights.clearMark(1); + this.Highlights.clearMark(2); + + int base1 = start, base2 = mid, + len1 = mid - start, len2 = end - mid; + + /* + * 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(this, arr[base2], arr, base1, len1, 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(this, arr[base1 + len1 - 1], arr, base2, len2, len2 - 1); + if (len2 == 0) + return; + + // Merge remaining runs, using tmp array with min(len1, len2) elements + if (len1 <= len2) + mergeLo(this, base1, len1, base2, len2); + else + mergeHi(this, base1, len1, base2, len2); + + this.Highlights.clearMark(1); + this.Highlights.clearMark(2); + } + + @Override + public void runSort(int[] array, int sortLength, int bucketCount) throws Exception { + this.len = sortLength; + this.a = array; + minGallop = MIN_GALLOP; + aux = Writes.createExternalArray((sortLength + 2) / 3); + wrapper(array, 0, sortLength); + Writes.deleteExternalArray(aux); + } +} diff --git a/src/utils/SortingNetworkGenerator.java b/src/utils/SortingNetworkGenerator.java index 41a38968..8e61bc5d 100644 --- a/src/utils/SortingNetworkGenerator.java +++ b/src/utils/SortingNetworkGenerator.java @@ -1,111 +1,133 @@ package utils; import java.awt.Desktop; -import java.io.BufferedReader; -import java.io.BufferedWriter; import java.io.File; import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.lang.ProcessBuilder.Redirect; -import java.util.stream.Collectors; -import java.text.DecimalFormat; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import javax.swing.JOptionPane; -import frames.UtilFrame; import panes.JErrorPane; -import resources.sorting_network_master.SortingNetworkFetcher; public class SortingNetworkGenerator { - static DecimalFormat formatter = new DecimalFormat(); + private static final class Comparator { + int i1, i2; - static boolean hasPython = false; - static String pythonCommand = null; + Comparator(int i1, int i2) { + this.i1 = i1; + this.i2 = i2; + } - final static int LIMIT = 20000; + @Override + public String toString() { + return i1 + ":" + i2; + } - static boolean verifyPythonVersion(String minVersion, String command) { - try { - ProcessBuilder builder = new ProcessBuilder(command, "-c", - String.format("import sys; print (sys.version_info >= (%s))", minVersion)); - Process p = builder.start(); - if (p.waitFor() != 0) { - return false; - } - BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream())); - if (r.readLine().equals("True")) { - pythonCommand = command; - return true; - } - return false; + @Override + public int hashCode() { + return (i1 << 16) + i2; } - catch (IOException e) { - return false; + + boolean overlaps(Comparator other) { + return (this.i1 < other.i1 && other.i1 < this.i2) || + (this.i1 < other.i2 && other.i2 < this.i2) || + (other.i1 < this.i1 && this.i1 < other.i2) || + (other.i1 < this.i2 && this.i2 < other.i2); } - catch (Exception e) { - e.printStackTrace(); - return false; + + boolean hasSameInput(Comparator other) { + return this.i1 == other.i1 || + this.i1 == other.i2 || + this.i2 == other.i1 || + this.i2 == other.i2; } } - public static boolean verifyPythonVersion() { - return (hasPython = hasPython // This caches the result if it's true - || verifyPythonVersion("3, 2, 0", "python3") - || verifyPythonVersion("3, 2, 0", "python") - || verifyPythonVersion("3, 2, 0", "py")); - } + final static int LIMIT = 20000; public static boolean verifyPythonVersionAndDialog() { - boolean hasVersion = verifyPythonVersion(); - if (!hasVersion) { - JOptionPane.showMessageDialog(null, "It appears that you do not have Python 3.2 or later installed on your computer! Please install it before using this mode.", - "Sorting Network Visualizer", JOptionPane.WARNING_MESSAGE); - } - return hasVersion; + // TODO: Remove this method + return true; } - public static boolean encodeNetwork(int[] indices, String path) { - if (indices.length < 2) { - JOptionPane.showMessageDialog(null, "Sort does not compare indices; An empty sorting network cannot be generated.", - "File not saved", JOptionPane.ERROR_MESSAGE); + private static int getMaxInput(List comparators) { + int maxInput = 0; + for (Comparator c : comparators) { + if (c.i2 > maxInput) { + maxInput = c.i2; + } + } + return maxInput; + } - return false; + public static boolean encodeNetwork(Integer[] indices, String path) { + List comparators = new ArrayList<>(indices.length / 2); + for (int i = 1; i < indices.length; i += 2) { + comparators.add(new Comparator(indices[i - 1], indices[i])); } - else if (indices.length > 2*LIMIT) { - String[] options = {"Yes", "Cancel"}; - int choice = JOptionPane.showOptionDialog(null, "Sorting network is very large and exceeds the " + formatter.format(LIMIT) + " comparator limit. Generate anyway?", - "Warning!", 2, JOptionPane.WARNING_MESSAGE, null, options, options[1]); - if (choice == 1) { - return false; + int scale = 1; + int xScale = scale * 35; + int yScale = scale * 20; + + StringBuilder comparatorsSvg = new StringBuilder(); + double w = xScale; + Map group = new HashMap<>(); + for (Comparator c : comparators) { + for (Comparator other : group.keySet()) { + if (c.hasSameInput(other)) { + for (double pos : group.values()) { + if (pos > w) { + w = pos; + } + } + w += xScale; + group.clear(); + break; + } } - } - String result = indices[0] + ":" + indices[1]; - for (int i = 3; i < indices.length; i += 2) { - result += "," + indices[i - 1] + ":" + indices[i]; - } - SortingNetworkFetcher fetcher = new SortingNetworkFetcher(); - try { - ProcessBuilder builder = new ProcessBuilder(pythonCommand, "-c", - new BufferedReader(new InputStreamReader(fetcher.getStream())).lines().collect(Collectors.joining("\n")), - "--svg", path); - builder.redirectOutput(Redirect.INHERIT); - Process p = builder.start(); - BufferedWriter w = new BufferedWriter(new OutputStreamWriter(p.getOutputStream())); - w.write(result); - w.close(); - if (p.waitFor() != 0) { - BufferedReader r = new BufferedReader(new InputStreamReader(p.getErrorStream())); - JErrorPane.invokeCustomErrorMessage(r.lines().collect(Collectors.joining("\n"))); - return false; + + double cx = w; + for (Entry entry : group.entrySet()) { + Comparator other = entry.getKey(); + double otherPos = entry.getValue(); + if (otherPos >= cx && c.overlaps(other)) { + cx = otherPos + xScale / 3.0; + } } + + int y0 = yScale + c.i1 * yScale; + int y1 = yScale + c.i2 * yScale; + comparatorsSvg.append(String.format("", cx, y0)) + .append(String.format("", cx, y0, y1)) + .append(String.format("", cx, y1)); + group.put(c, cx); } - catch (IOException e) { - JErrorPane.invokeErrorMessage(e, "Sorting Network Visualizer"); - return false; + + StringBuilder linesSvg = new StringBuilder(); + w += xScale; + int n = getMaxInput(comparators) + 1; + for (int i = 0; i < n; i++) { + int y = yScale + i * yScale; + linesSvg.append(String.format("", y, w)); } - catch (Exception e) { + + int h = (n + 1) * yScale; + try (PrintWriter writer = new PrintWriter(path, "UTF-8")) { + writer.write( + "" + + "" + + String.format("", w, h) + + comparatorsSvg + + linesSvg + + "" + ); + } catch (Exception e) { JErrorPane.invokeErrorMessage(e, "Sorting Network Visualizer"); return false; } @@ -114,11 +136,7 @@ else if (indices.length > 2*LIMIT) { public static String encodeNetworkAndDisplay(String name, Integer[] indices, int arrayLength) { String path = "network_" + name + "_" + arrayLength + ".svg"; - int[] indicesInt = new int[indices.length]; - for (int i = 0; i < indices.length; i++) { - indicesInt[i] = indices[i]; - } - if (!encodeNetwork(indicesInt, path)) { + if (!encodeNetwork(indices, path)) { return null; } JOptionPane.showMessageDialog(null, "Successfully saved output to file \"" + path + "\"", diff --git a/src/utils/sorting_networks_min.py b/src/utils/sorting_networks_min.py new file mode 100644 index 00000000..8853932d --- /dev/null +++ b/src/utils/sorting_networks_min.py @@ -0,0 +1,88 @@ +from typing import Any + + +class Comparator: + i1: int + i2: int + + def __init__(self, i1: int, i2: int) -> None: + self.i1 = i1 + self.i2 = i2 + + def overlaps(self, other: 'Comparator') -> bool: + return ((self.i1 < other.i1 < self.i2) or + (self.i1 < other.i2 < self.i2) or + (other.i1 < self.i1 < other.i2) or + (other.i1 < self.i2 < other.i2)) + + def has_same_input(self, other: 'Comparator') -> bool: + return (self.i1 == other.i1 or + self.i1 == other.i2 or + self.i2 == other.i1 or + self.i2 == other.i2) + + +def get_max_input(comparators: list[Comparator]) -> int: + max_input = 0 + for c in comparators: + if c.i2 > max_input: + max_input = c.i2 + return max_input + + +def convert(indices: list[int], path: str) -> None: + comparators: list[Comparator] = [] + for i in range(1, len(indices), 2): + comparators.append(Comparator(indices[i - 1], indices[i])) + + scale = 1 + x_scale = scale * 35 + y_scale = scale * 20 + + comparators_svg = '' + w = x_scale + group: dict[Comparator, float] = {} + for c in comparators: + for other in group: + if c.has_same_input(other): + for (_, pos) in group.items(): + if pos > w: + w = pos + w += x_scale + group.clear() + break + + cx = w + for (other, other_pos) in group.items(): + if other_pos >= cx and c.overlaps(other): + cx = other_pos + x_scale / 3 + + y0 = y_scale + c.i1 * y_scale + y1 = y_scale + c.i2 * y_scale + comparators_svg += ( + "" % (cx, y0, 3) + + "" % (cx, y0, cx, y1, 1) + + "" % (cx, y1, 3) + ) + group[c] = cx + + lines_svg = '' + w += x_scale + n = get_max_input(comparators) + 1 + for i in range(n): + y = y_scale + i * y_scale + lines_svg += ( + "" % + (0, y, w, y, 1) + ) + + h = (n + 1) * y_scale + with open(path, 'w') as fp: + fp.write( + "" + + "" + + "" % (w, h) + + comparators_svg + + lines_svg + + "" + ) From 349e986767b00423c6947a397b2ce9c68858803d Mon Sep 17 00:00:00 2001 From: "Josiah (Gaming32) Glosson" Date: Thu, 25 Nov 2021 08:27:09 -0600 Subject: [PATCH 02/23] Optimize slightly Remove String.format usage --- src/utils/SortingNetworkGenerator.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/utils/SortingNetworkGenerator.java b/src/utils/SortingNetworkGenerator.java index 8e61bc5d..36492a66 100644 --- a/src/utils/SortingNetworkGenerator.java +++ b/src/utils/SortingNetworkGenerator.java @@ -103,9 +103,9 @@ public static boolean encodeNetwork(Integer[] indices, String path) { int y0 = yScale + c.i1 * yScale; int y1 = yScale + c.i2 * yScale; - comparatorsSvg.append(String.format("", cx, y0)) - .append(String.format("", cx, y0, y1)) - .append(String.format("", cx, y1)); + comparatorsSvg.append("") + .append("") + .append(""); group.put(c, cx); } @@ -114,15 +114,14 @@ public static boolean encodeNetwork(Integer[] indices, String path) { int n = getMaxInput(comparators) + 1; for (int i = 0; i < n; i++) { int y = yScale + i * yScale; - linesSvg.append(String.format("", y, w)); + linesSvg.append(""); } int h = (n + 1) * yScale; try (PrintWriter writer = new PrintWriter(path, "UTF-8")) { writer.write( - "" + - "" + - String.format("", w, h) + + "" + + "" + comparatorsSvg + linesSvg + "" From 7926d91119d8eb66c91358a9cb12a994011ef2fd Mon Sep 17 00:00:00 2001 From: "Josiah (Gaming32) Glosson" Date: Thu, 25 Nov 2021 08:29:29 -0600 Subject: [PATCH 03/23] Use File more --- src/utils/SortingNetworkGenerator.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/utils/SortingNetworkGenerator.java b/src/utils/SortingNetworkGenerator.java index 36492a66..c29560b2 100644 --- a/src/utils/SortingNetworkGenerator.java +++ b/src/utils/SortingNetworkGenerator.java @@ -65,7 +65,7 @@ private static int getMaxInput(List comparators) { return maxInput; } - public static boolean encodeNetwork(Integer[] indices, String path) { + public static boolean encodeNetwork(Integer[] indices, File file) { List comparators = new ArrayList<>(indices.length / 2); for (int i = 1; i < indices.length; i += 2) { comparators.add(new Comparator(indices[i - 1], indices[i])); @@ -118,7 +118,7 @@ public static boolean encodeNetwork(Integer[] indices, String path) { } int h = (n + 1) * yScale; - try (PrintWriter writer = new PrintWriter(path, "UTF-8")) { + try (PrintWriter writer = new PrintWriter(file, "UTF-8")) { writer.write( "" + "" + @@ -135,12 +135,12 @@ public static boolean encodeNetwork(Integer[] indices, String path) { public static String encodeNetworkAndDisplay(String name, Integer[] indices, int arrayLength) { String path = "network_" + name + "_" + arrayLength + ".svg"; - if (!encodeNetwork(indices, path)) { + File file = new File(path); + if (!encodeNetwork(indices, file)) { return null; } JOptionPane.showMessageDialog(null, "Successfully saved output to file \"" + path + "\"", "Sorting Network Visualizer", JOptionPane.INFORMATION_MESSAGE); - File file = new File(path); Desktop desktop = Desktop.getDesktop(); try { desktop.open(file); From 3854ccf52d92432961ca471bf0360ea9f4d8947c Mon Sep 17 00:00:00 2001 From: "Josiah (Gaming32) Glosson" Date: Thu, 25 Nov 2021 10:28:38 -0600 Subject: [PATCH 04/23] Force GC with F12 --- src/main/ArrayVisualizer.java | 210 +++++++++++++++++----------------- 1 file changed, 106 insertions(+), 104 deletions(-) diff --git a/src/main/ArrayVisualizer.java b/src/main/ArrayVisualizer.java index e8c55783..755e3eb3 100644 --- a/src/main/ArrayVisualizer.java +++ b/src/main/ArrayVisualizer.java @@ -55,7 +55,7 @@ import visuals.misc.*; /* - * + * The MIT License (MIT) Copyright (c) 2019 w0rthy @@ -192,6 +192,8 @@ public void keyTyped(KeyEvent e) { public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_K || e.getKeyCode() == KeyEvent.VK_SPACE) { ArrayVisualizer.this.getDelays().togglePaused(); + } else if (e.getKeyCode() == KeyEvent.VK_F12) { + System.gc(); } } @Override @@ -293,10 +295,10 @@ public void run() { FileDialog.initialize(); } }.start(); - + this.MIN_ARRAY_VAL = 2; this.MAX_ARRAY_VAL = (int)Math.pow(2, MAX_LENGTH_POWER); - + int[] array; try { array = new int[this.MAX_ARRAY_VAL]; @@ -306,21 +308,21 @@ public void run() { array = null; } this.array = array; - + this.sortLength = this.MAX_ARRAY_VAL; - + this.arrays = new ArrayList<>(); this.arrays.add(this.array); - + this.sortLength = Math.min(2048, this.MAX_ARRAY_VAL); this.uniqueItems = this.sortLength; - + this.formatter = (DecimalFormat) NumberFormat.getInstance(Locale.US); this.symbols = this.formatter.getDecimalFormatSymbols(); this.formatter.setRoundingMode(RoundingMode.HALF_UP); this.symbols.setGroupingSeparator(','); this.formatter.setDecimalFormatSymbols(this.symbols); - + this.Highlights = new Highlights(this, this.MAX_ARRAY_VAL); this.Sounds = new Sounds(this.array, this); this.Delays = new Delays(this); @@ -331,13 +333,13 @@ public void run() { this.AntiQSort = new AntiQSort(this); new Rotations(this); - + SoundFrame test = new SoundFrame(this.Sounds); test.setVisible(true); - + this.ArrayManager = new ArrayManager(this); this.SortAnalyzer = new SortAnalyzer(this); - + this.SortAnalyzer.analyzeSorts(); this.refreshSorts(); @@ -369,25 +371,25 @@ public void run() { } this.MultipleScript = new MultipleScript(this); - + this.category = ""; this.heading = ""; this.extraHeading = ""; this.fontSelection = "Times New Roman"; this.typeFace = new Font(this.fontSelection, Font.PLAIN, (int) (this.getWindowRatio() * 25)); - + this.statSnapshot = new Statistics(this); - + this.UtilFrame = new UtilFrame(this.array, this); this.ArrayFrame = new ArrayFrame(this.array, this); - + this.UtilFrame.reposition(this.ArrayFrame); - + this.SHUFFLEANIM = true; this.ANALYZE = false; this.POINTER = false; this.TEXTDRAW = true; - + this.COLOR = false; this.DISPARITYDRAW = false; this.LINEDRAW = false; @@ -399,7 +401,7 @@ public void run() { this.ANTIQSORT = false; this.STABILITY = false; this.NETWORKS = false; - + this.isCanceled = false; this.updateVisualsForced = 0; @@ -411,7 +413,7 @@ public void run() { this.cw = 0; this.ArrayManager.initializeArray(this.array); - + //TODO: Overhaul visual code to properly reflect Swing (JavaFX?) style and conventions this.toggleVisualUpdates(false); //DRAW THREAD @@ -420,15 +422,15 @@ public void run() { @Override public void run() { ArrayVisualizer.this.visualsEnabled = true; - + utils.Renderer.initializeVisuals(ArrayVisualizer.this); - + Graphics background = ArrayVisualizer.this.window.getGraphics(); background.setColor(Color.BLACK); int coltmp = 255; - + ArrayVisualizer.this.visualClasses = new Visual[15]; - + ArrayVisualizer.this.visualClasses[0] = new BarGraph(ArrayVisualizer.this); ArrayVisualizer.this.visualClasses[1] = new Rainbow(ArrayVisualizer.this); ArrayVisualizer.this.visualClasses[2] = new DisparityBarGraph(ArrayVisualizer.this); @@ -444,7 +446,7 @@ public void run() { ArrayVisualizer.this.visualClasses[12] = new PixelMesh(ArrayVisualizer.this); ArrayVisualizer.this.visualClasses[13] = new Spiral(ArrayVisualizer.this); ArrayVisualizer.this.visualClasses[14] = new SpiralDots(ArrayVisualizer.this); - + while(ArrayVisualizer.this.visualsEnabled) { if (ArrayVisualizer.this.updateVisualsForced == 0) { try { @@ -502,7 +504,7 @@ public void refreshSorts() { System.arraycopy(this.ComparisonSorts, 0, this.AllSorts, 0, this.ComparisonSorts.length); System.arraycopy(this.DistributionSorts, 0, this.AllSorts, this.ComparisonSorts.length, this.DistributionSorts.length); } - + private void drawStats(Color textColor, boolean dropShadow) { int xOffset = 15; int yOffset = 30; @@ -510,11 +512,11 @@ private void drawStats(Color textColor, boolean dropShadow) { xOffset += 3; yOffset += 3; } - + double windowRatio = this.getWindowRatio(); - + this.mainRender.setColor(textColor); - + this.mainRender.drawString(this.statSnapshot.getSortIdentity(), xOffset, (int) (windowRatio * 30) + yOffset); this.mainRender.drawString(this.statSnapshot.getArrayLength(), xOffset, (int) (windowRatio * 55) + yOffset); this.mainRender.drawString(this.statSnapshot.getSortDelay(), xOffset, (int) (windowRatio * 95) + yOffset); @@ -551,7 +553,7 @@ public void forceVisualUpdate(int count) { } public boolean enableBenchmarking(boolean enabled) { if (enabled) { - + } else if (this.benchmarking) { if (this.getCurrentLength() >= Math.pow(2, 23)) { @@ -573,45 +575,45 @@ else if (this.benchmarking) { public int[] getValidationArray() { return this.validateArray; } - + public int getStabilityValue(int n) { n = Math.max(0, Math.min(n, this.sortLength-1)); - + return this.stabilityTable[n]; } - + public int[] getStabilityTable() { return this.stabilityTable; } - + public void resetStabilityTable() { for(int i = 0; i < this.sortLength; i++) { this.stabilityTable[i] = i; } } - + public int getIndexValue(int n) { n = Math.max(0, Math.min(n, this.sortLength-1)); - + return this.indexTable[n]; } - + public int[] getIndexTable() { return this.indexTable; } - + public void setIndexTable() { for(int i = 0; i < this.sortLength; i++) { this.indexTable[array[i]] = i; } } - + public void resetIndexTable() { for(int i = 0; i < this.sortLength; i++) { this.indexTable[i] = i; } } - + public boolean isSorted() { return this.statSnapshot.findSegments(this.array, this.sortLength, this.REVERSED)[0] == 1; } @@ -623,7 +625,7 @@ public int[] getArray() { public ArrayList getArrays() { return this.arrays; } - + public ArrayManager getArrayManager() { return this.ArrayManager; } @@ -657,19 +659,19 @@ public Writes getWrites() { public MultipleScript getScriptParser() { return this.MultipleScript; } - + public Visual[] getVisuals() { return this.visualClasses; } - + public UtilFrame getUtilFrame() { return this.UtilFrame; } - + public ArrayFrame getArrayFrame() { return this.ArrayFrame; } - + public SortPair[] getAllSorts() { return this.AllSorts; } @@ -679,7 +681,7 @@ public SortPair[] getComparisonSorts() { public SortPair[] getDistributionSorts() { return this.DistributionSorts; } - + public Thread getSortingThread() { return this.sortingThread; } @@ -689,14 +691,14 @@ public void setSortingThread(Thread thread) { public void runSortingThread() { this.sortingThread.start(); } - + public int getMinimumLength() { return this.MIN_ARRAY_VAL; } public int getMaximumLength() { return this.MAX_ARRAY_VAL; } - + public void resetAllStatistics() { this.Reads.resetStatistics(); this.Writes.resetStatistics(); @@ -741,7 +743,7 @@ public void setComparator(int comparator) { break; } } - + public boolean generateSortingNetworks() { return this.NETWORKS; } @@ -775,7 +777,7 @@ public boolean doingStabilityCheck() { public boolean reversedComparator() { return this.REVERSED; } - + // These next five methods should be part of ArrayManager public int getCurrentLength() { return this.sortLength; @@ -796,21 +798,21 @@ public void setUniqueItems(int newCount) { public int getUniqueItems() { return uniqueItems; } - + public int getLogBaseNOfLength(int base) { - return (int) (Math.log(this.sortLength) / Math.log(base)); + return (int) (Math.log(this.sortLength) / Math.log(base)); } public int getLogBaseTwoOfLength() { - return getLogBaseNOfLength(2); + return getLogBaseNOfLength(2); } - + public boolean shuffleEnabled() { return this.SHUFFLEANIM; } public void toggleShuffleAnimation(boolean Bool) { this.SHUFFLEANIM = Bool; } - + public String getCategory() { return this.category; } @@ -833,22 +835,22 @@ public void setExtraHeading(String text) { public boolean pointerActive() { return this.POINTER; } - + public JFrame getMainWindow() { return this.window; } - + public void setWindowHeight() { this.ch = this.window.getHeight(); } public void setWindowWidth() { this.cw = this.window.getWidth(); } - + // TODO: // CURRENT HEIGHT/WIDTH/X/Y SHOULD CORRESPOND TO "C" VARIABLES // AND WINDOW HEIGHT/WIDTH/X/Y SHOULD CORRESPOND TO WINDOW FIELD - + public int currentHeight() { return this.window.getHeight(); } @@ -861,7 +863,7 @@ public int currentX() { public int currentY() { return this.window.getY(); } - + public int windowHeight() { return this.ch; } @@ -880,24 +882,24 @@ public int windowXCoordinate() { public int windowYCoordinate() { return this.cy; } - + public Color getHighlightColor() { if(this.colorEnabled()) { - if(this.analysisEnabled()) + if(this.analysisEnabled()) return Color.LIGHT_GRAY; - + else return Color.WHITE; } else { - if(this.analysisEnabled()) + if(this.analysisEnabled()) return Color.BLUE; - + else return Color.RED; } } - + public void createVolatileImage() { this.img = this.window.getGraphicsConfiguration().createCompatibleVolatileImage(this.cw, this.ch); } @@ -933,12 +935,12 @@ public void updateVisuals() { public void resetMainStroke() { this.mainRender.setStroke(this.getDefaultStroke()); } - + public void renderBackground() { this.mainRender.setColor(new Color(0, 0, 0)); // Pure black this.mainRender.fillRect(0, 0, this.img.getWidth(null), this.img.getHeight(null)); } - + public void updateCoordinates() { this.cx = this.window.getX(); this.cy = this.window.getY(); @@ -954,45 +956,45 @@ public void updateFontSize() { this.typeFace = new Font(this.fontSelection, Font.PLAIN, (int) (this.getWindowRatio() * 25)); this.mainRender.setFont(this.typeFace); } - + public void toggleAnalysis(boolean Bool) { this.ANALYZE = Bool; } public boolean analysisEnabled() { return this.ANALYZE; } - + public int halfCircle() { return (this.sortLength / 2); } - + //TODO: This method is *way* too long. Break it apart. public synchronized void verifySortAndSweep() { this.Highlights.toggleFancyFinish(true); this.Highlights.resetFancyFinish(); - + this.Delays.setSleepRatio(1); double sleepRatio = 256d/this.sortLength; long tempComps = this.Reads.getComparisons(); this.Reads.setComparisons(0); - + String temp = this.heading; this.heading = "Verifying sort..."; int cmpVal = this.REVERSED ? -1 : 1; - + boolean success = true, stable = true; int unstableIdx = 0; boolean validate = this.validateArray != null; boolean validateFailed = false; int invalidateIdx = 0; - + for(int i = 0; i < this.sortLength + this.getLogBaseTwoOfLength(); i++) { if(i < this.sortLength) this.Highlights.markArray(1, i); this.Highlights.incrementFancyFinishPosition(); - + if(i < this.sortLength - 1) { if (validate && !validateFailed && this.Reads.compareOriginalValues(this.array[i], this.validateArray[i]) != 0) { validateFailed = true; @@ -1004,27 +1006,27 @@ public synchronized void verifySortAndSweep() { } if(this.Reads.compareValues(this.array[i], this.array[i + 1]) == cmpVal) { this.Highlights.clearMark(1); - + boolean tempSound = this.Sounds.isEnabled(); this.Sounds.toggleSound(false); this.Highlights.toggleFancyFinish(false); - + for(int j = i + 1; j < this.sortLength; j++) { this.Highlights.markArray(j, j); this.Delays.sleep(sleepRatio); } - + JOptionPane.showMessageDialog(this.window, "The sort was unsuccessful;\nIndices " + i + " and " + (i + 1) + " are out of order!", "Error", JOptionPane.OK_OPTION, null); success = false; - + this.Highlights.clearAllMarks(); - + i = this.sortLength + this.getLogBaseTwoOfLength(); - + this.Sounds.toggleSound(tempSound); } } - + if(this.Highlights.fancyFinishEnabled()) { this.Delays.sleep(sleepRatio); } @@ -1037,14 +1039,14 @@ public synchronized void verifySortAndSweep() { boolean tempSound = this.Sounds.isEnabled(); this.Sounds.toggleSound(false); this.Highlights.toggleFancyFinish(false); - + for(int j = unstableIdx; j < this.sortLength; j++) { this.Highlights.markArray(j, j); this.Delays.sleep(sleepRatio); } - + JOptionPane.showMessageDialog(this.window, "This sort is not stable;\nIndices " + unstableIdx + " and " + (unstableIdx + 1) + " are out of order!", "Error", JOptionPane.OK_OPTION, null); - + this.Highlights.clearAllMarks(); this.Sounds.toggleSound(tempSound); } @@ -1052,14 +1054,14 @@ else if(success && validateFailed) { boolean tempSound = this.Sounds.isEnabled(); this.Sounds.toggleSound(false); this.Highlights.toggleFancyFinish(false); - + for(int j = invalidateIdx + 1; j < this.sortLength; j++) { this.Highlights.markArray(j, j); this.Delays.sleep(sleepRatio); } - + JOptionPane.showMessageDialog(this.window, "The sort was unsuccessful;\narray[" + invalidateIdx + "] != validateArray[" + invalidateIdx + "]", "Error", JOptionPane.OK_OPTION, null); - + this.Highlights.clearAllMarks(); this.Sounds.toggleSound(tempSound); } @@ -1070,7 +1072,7 @@ else if(success && validateFailed) { if (this.benchmarking) { JOptionPane.showMessageDialog(this.window, "The sort took a total of " + this.Timer.getRealTime()); } - + if(this.Highlights.fancyFinishActive()) { this.Highlights.toggleFancyFinish(false); } @@ -1098,7 +1100,7 @@ public void endSort() { this.isCanceled = false; this.Delays.changeSkipped(false); - double speed = this.Delays.getSleepRatio(); + double speed = this.Delays.getSleepRatio(); this.verifySortAndSweep(); this.Delays.setSleepRatio(speed); @@ -1107,7 +1109,7 @@ public void endSort() { this.Highlights.clearAllMarks(); } - + public void togglePointer(boolean Bool) { this.POINTER = Bool; } @@ -1138,7 +1140,7 @@ public void toggleWave(boolean Bool) { public void toggleExternalArrays(boolean Bool) { this.EXTARRAYS = Bool; } - + public void setVisual(VisualStyles choice) { if(choice == visuals.VisualStyles.CUSTOM_IMAGE) { ((CustomImage) this.visualClasses[9]).enableImgMenu(); @@ -1148,7 +1150,7 @@ public void setVisual(VisualStyles choice) { this.updateNow(); } } - + public int getCurrentGap() { return this.currentGap; } @@ -1162,12 +1164,12 @@ public boolean sortCanceled() { public void setCanceled(boolean canceled) { this.isCanceled = canceled; } - + public void repositionFrames() { this.ArrayFrame.reposition(); this.UtilFrame.reposition(this.ArrayFrame); } - + public boolean rainbowEnabled() { return this.RAINBOW; } @@ -1192,11 +1194,11 @@ public boolean waveEnabled() { public boolean externalArraysEnabled() { return this.EXTARRAYS; } - + public DecimalFormat getNumberFormat() { return this.formatter; } - + private static String parseStringArray(String[] stringArray) { String parsed = ""; for(int i = 0; i < stringArray.length; i++) { @@ -1204,20 +1206,20 @@ private static String parseStringArray(String[] stringArray) { } return parsed; } - + private void drawWindows() { this.VisualStyles = visuals.VisualStyles.BARS; this.category = "Select a Sort"; - + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); this.window.setSize((int) (screenSize.getWidth() / 2), (int) (screenSize.getHeight() / 2)); - + this.window.setLocation(0, 0); this.window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); this.window.setTitle("w0rthy's Array Visualizer - " + (this.ComparisonSorts.length + this.DistributionSorts.length) + " Sorts, 15 Visual Styles, and Infinite Inputs to Sort"); this.window.setBackground(Color.BLACK); this.window.setIgnoreRepaint(true); - + this.window.addWindowListener(new java.awt.event.WindowAdapter() { @Override public void windowClosing(WindowEvent close) { @@ -1228,7 +1230,7 @@ public void windowClosing(WindowEvent close) { } } }); - + //TODO: Consider removing insets from window size this.cw = this.window.getWidth(); this.ch = this.window.getHeight(); @@ -1237,9 +1239,9 @@ public void windowClosing(WindowEvent close) { this.visualsThread.start(); this.UtilFrame.setVisible(true); this.ArrayFrame.setVisible(true); - + this.window.createBufferStrategy(2); - + if(this.InvalidSorts != null) { String output = parseStringArray(this.InvalidSorts); JOptionPane.showMessageDialog(this.window, "The following algorithms were not loaded:\n" + output, "Warning", JOptionPane.WARNING_MESSAGE); From 3949c527452af7158bc927b2e9d6ee955cbc1139 Mon Sep 17 00:00:00 2001 From: "Josiah (Gaming32) Glosson" Date: Thu, 25 Nov 2021 10:33:16 -0600 Subject: [PATCH 05/23] Work on memory usage things There appears to be a memory leak somewhere, but I can't find it. --- src/frames/UtilFrame.java | 18 ++++----- src/panes/JErrorPane.java | 28 +++++++------ src/threads/RunComparisonSort.java | 28 ++++++------- src/utils/SortingNetworkGenerator.java | 54 ++++++++++++++------------ 4 files changed, 66 insertions(+), 62 deletions(-) diff --git a/src/frames/UtilFrame.java b/src/frames/UtilFrame.java index f13b1283..b57000a1 100644 --- a/src/frames/UtilFrame.java +++ b/src/frames/UtilFrame.java @@ -29,9 +29,9 @@ import utils.SortingNetworkGenerator; import utils.Sounds; import utils.Timer; - + /* - * + * MIT License Copyright (c) 2019 w0rthy @@ -66,7 +66,7 @@ final public class UtilFrame extends javax.swing.JFrame { private boolean jCheckBox9WarningShown = true; //set to false to enable warning private int[] array; - + private ArrayManager ArrayManager; private ArrayVisualizer ArrayVisualizer; private Delays Delays; @@ -78,16 +78,16 @@ final public class UtilFrame extends javax.swing.JFrame { public UtilFrame(int[] array, ArrayVisualizer arrayVisualizer) { this.array = array; - + this.ArrayVisualizer = arrayVisualizer; this.ArrayManager = ArrayVisualizer.getArrayManager(); - + this.Delays = ArrayVisualizer.getDelays(); this.Frame = ArrayVisualizer.getMainWindow(); this.Highlights = ArrayVisualizer.getHighlights(); this.RealTimer = ArrayVisualizer.getTimer(); this.Sounds = ArrayVisualizer.getSounds(); - + setUndecorated(true); initComponents(); setLocation(Math.min((int) Toolkit.getDefaultToolkit().getScreenSize().getWidth() - getWidth(), Frame.getX() + Frame.getWidth()), Frame.getY() + 29); @@ -440,7 +440,7 @@ public void jButton2ResetText() { private void jButton3ActionPerformed() {//GEN-FIRST:event_jButton3ActionPerformed boolean speedPromptAllowed; - + if(this.abstractFrame == null) { speedPromptAllowed = true; } @@ -450,7 +450,7 @@ else if(!this.abstractFrame.isVisible()) { else { speedPromptAllowed = false; } - + if(speedPromptAllowed) { boolean showPrompt = true; while(showPrompt) { @@ -595,8 +595,6 @@ private void jComboBox1ActionPerformed() {//GEN-FIRST:event_jButton4ActionPerfor break; jButton6.setEnabled(true); ArrayVisualizer.setComparator(4); - if (!SortingNetworkGenerator.verifyPythonVersionAndDialog()) - jComboBox1.setSelectedIndex(0); // Failure to find Python installation if (ArrayVisualizer.getCurrentLength() > 256) { JOptionPane.showMessageDialog(null, "Large sorting networks take too long and will not be generated. Array lengths less than or equal to 256 are recommended.", "Sorting Network Visualizer", JOptionPane.WARNING_MESSAGE); diff --git a/src/panes/JErrorPane.java b/src/panes/JErrorPane.java index 3c4d9d2a..564c3d5d 100644 --- a/src/panes/JErrorPane.java +++ b/src/panes/JErrorPane.java @@ -8,12 +8,12 @@ final public class JErrorPane extends JOptionPane { /** - * + * */ private static final long serialVersionUID = 1L; - + public volatile static boolean errorMessageActive = false; - + private static JTextArea createTextArea(String errorMsg) { JTextArea error = new JTextArea(); error.setText(errorMsg); @@ -21,30 +21,28 @@ private static JTextArea createTextArea(String errorMsg) { error.setEditable(false); return error; } - - public static void invokeErrorMessage(Exception e, String title) { + + public static void invokeErrorMessage(Throwable e, String title) { errorMessageActive = true; - + StringWriter exceptionString = new StringWriter(); e.printStackTrace(new PrintWriter(exceptionString)); String printException = exceptionString.toString(); - + JTextArea error = createTextArea(printException); - + JOptionPane.showMessageDialog(null, error, title, JOptionPane.ERROR_MESSAGE); errorMessageActive = false; } - - public static void invokeErrorMessage(Exception e) { + + public static void invokeErrorMessage(Throwable e) { JErrorPane.invokeErrorMessage(e, "Error"); } - + public static void invokeCustomErrorMessage(String errorMsg) { errorMessageActive = true; - - JTextArea error = createTextArea(errorMsg); - - JOptionPane.showMessageDialog(null, error, "Error", JOptionPane.ERROR_MESSAGE); + + JOptionPane.showMessageDialog(null, errorMsg, "Error", JOptionPane.ERROR_MESSAGE); errorMessageActive = false; } } \ No newline at end of file diff --git a/src/threads/RunComparisonSort.java b/src/threads/RunComparisonSort.java index d04750d2..59b13e5b 100644 --- a/src/threads/RunComparisonSort.java +++ b/src/threads/RunComparisonSort.java @@ -1,6 +1,7 @@ package threads; import java.lang.reflect.Constructor; +import java.util.ArrayList; import javax.swing.JOptionPane; @@ -16,7 +17,7 @@ import utils.Timer; /* - * + * MIT License Copyright (c) 2019 w0rthy @@ -49,7 +50,7 @@ final public class RunComparisonSort { private Timer realTimer; private Object[] inputOptions; - + public RunComparisonSort(ArrayVisualizer arrayVisualizer) { this.arrayVisualizer = arrayVisualizer; this.arrayManager = arrayVisualizer.getArrayManager(); @@ -65,7 +66,7 @@ private int getCustomInput(String text) throws Exception { int integer = Integer.parseInt(input); return Math.abs(integer); } - + public void ReportComparativeSort(int[] array, int selection) { if(arrayVisualizer.isActive()) return; @@ -95,13 +96,13 @@ public void run() { extra = sort.getDefaultAnswer(); } } - + boolean goAhead; - + if(sort.isUnreasonablySlow() && arrayVisualizer.getCurrentLength() > sort.getUnreasonableLimit()) { goAhead = false; Object[] options = { "Let's see how bad " + sort.getRunSortName() + " is!", "Cancel" }; - + if(sort.isBogoSort()) { int warning = JOptionPane.showOptionDialog(arrayVisualizer.getMainWindow(), "Even at a high speed, " + sort.getRunSortName() + "ing " + arrayVisualizer.getCurrentLength() @@ -112,7 +113,7 @@ public void run() { else goAhead = false; } else { - int warning = JOptionPane.showOptionDialog(arrayVisualizer.getMainWindow(), "Even at a high speed, " + int warning = JOptionPane.showOptionDialog(arrayVisualizer.getMainWindow(), "Even at a high speed, " + sort.getRunSortName() + "ing " + arrayVisualizer.getCurrentLength() + " numbers will not finish in a reasonable amount of time. " + "Are you sure you want to continue?", "Warning!", 2, JOptionPane.WARNING_MESSAGE, @@ -125,21 +126,19 @@ public void run() { else { goAhead = true; } - + if(goAhead) { arrayManager.toggleMutableLength(false); arrayManager.refreshArray(array, arrayVisualizer.getCurrentLength(), arrayVisualizer); arrayVisualizer.setHeading(sort.getRunSortName()); arrayVisualizer.setCategory(sort.getCategory()); - + realTimer.enableRealTimer(); boolean antiq = arrayVisualizer.useAntiQSort(); boolean networks = arrayVisualizer.generateSortingNetworks(); if (antiq) arrayVisualizer.initAntiQSort(); - else if (networks) - arrayVisualizer.getReads().networkIndices.clear(); try { sort.runSort(array, arrayVisualizer.getCurrentLength(), extra); @@ -152,12 +151,14 @@ else if (networks) if (antiq) arrayVisualizer.finishAntiQSort(sort.getClass().getSimpleName()); - else if (networks) + else if (networks) { + ArrayList indicesList = arrayVisualizer.getReads().networkIndices; SortingNetworkGenerator.encodeNetworkAndDisplay( sort.getClass().getSimpleName(), - arrayVisualizer.getReads().networkIndices.toArray(new Integer[] {}), + indicesList, arrayVisualizer.getCurrentLength() ); + } } else { arrayManager.initializeArray(array); @@ -169,6 +170,7 @@ else if (networks) arrayVisualizer.endSort(); arrayManager.toggleMutableLength(true); sounds.toggleSound(false); + System.gc(); // Reduce RAM usage from any high-memory tasks (e.g. visualizing a sorting network) } }); diff --git a/src/utils/SortingNetworkGenerator.java b/src/utils/SortingNetworkGenerator.java index c29560b2..7a264e15 100644 --- a/src/utils/SortingNetworkGenerator.java +++ b/src/utils/SortingNetworkGenerator.java @@ -6,7 +6,6 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -48,14 +47,7 @@ boolean hasSameInput(Comparator other) { } } - final static int LIMIT = 20000; - - public static boolean verifyPythonVersionAndDialog() { - // TODO: Remove this method - return true; - } - - private static int getMaxInput(List comparators) { + private static int getMaxInput(Comparator[] comparators) { int maxInput = 0; for (Comparator c : comparators) { if (c.i2 > maxInput) { @@ -65,12 +57,7 @@ private static int getMaxInput(List comparators) { return maxInput; } - public static boolean encodeNetwork(Integer[] indices, File file) { - List comparators = new ArrayList<>(indices.length / 2); - for (int i = 1; i < indices.length; i += 2) { - comparators.add(new Comparator(indices[i - 1], indices[i])); - } - + public static boolean encodeNetwork(Comparator[] comparators, File file) { int scale = 1; int xScale = scale * 35; int yScale = scale * 20; @@ -119,13 +106,11 @@ public static boolean encodeNetwork(Integer[] indices, File file) { int h = (n + 1) * yScale; try (PrintWriter writer = new PrintWriter(file, "UTF-8")) { - writer.write( - "" + - "" + - comparatorsSvg + - linesSvg + - "" - ); + writer.write(""); + writer.write(""); + writer.write(comparatorsSvg.toString()); + writer.write(linesSvg.toString()); + writer.write(""); } catch (Exception e) { JErrorPane.invokeErrorMessage(e, "Sorting Network Visualizer"); return false; @@ -133,10 +118,31 @@ public static boolean encodeNetwork(Integer[] indices, File file) { return true; } - public static String encodeNetworkAndDisplay(String name, Integer[] indices, int arrayLength) { + public static String encodeNetworkAndDisplay(String name, ArrayList indices, int arrayLength) { + Comparator[] comparators; + try { + comparators = new Comparator[indices.size() / 2]; + for (int i = 0, j = 1; i < comparators.length; i++, j += 2) { + comparators[i] = new Comparator(indices.get(j - 1), indices.get(j)); + } + } catch (OutOfMemoryError e) { + JErrorPane.invokeErrorMessage(e, "Sorting Network Visualizer"); + return null; + } + System.out.println("Length: " + arrayLength + "\tComparators: " + comparators.length / 2); + indices.clear(); + indices.trimToSize(); String path = "network_" + name + "_" + arrayLength + ".svg"; File file = new File(path); - if (!encodeNetwork(indices, file)) { + try { + if (!encodeNetwork(comparators, file)) { + return null; + } + } catch (OutOfMemoryError e) { + JErrorPane.invokeCustomErrorMessage( + "ArrayV ran out of memory trying to visualize this sorting network.\n" + + "Either run ArrayV with more memory (or a smaller maximum length) or contemplate your life choices." + ); return null; } JOptionPane.showMessageDialog(null, "Successfully saved output to file \"" + path + "\"", From a98e4d33b0081ad10a64a7f46a2bfcbedf6a55e1 Mon Sep 17 00:00:00 2001 From: "Josiah (Gaming32) Glosson" Date: Thu, 25 Nov 2021 17:37:22 -0600 Subject: [PATCH 06/23] Delete sorting_networks_min.py --- src/utils/sorting_networks_min.py | 88 ------------------------------- 1 file changed, 88 deletions(-) delete mode 100644 src/utils/sorting_networks_min.py diff --git a/src/utils/sorting_networks_min.py b/src/utils/sorting_networks_min.py deleted file mode 100644 index 8853932d..00000000 --- a/src/utils/sorting_networks_min.py +++ /dev/null @@ -1,88 +0,0 @@ -from typing import Any - - -class Comparator: - i1: int - i2: int - - def __init__(self, i1: int, i2: int) -> None: - self.i1 = i1 - self.i2 = i2 - - def overlaps(self, other: 'Comparator') -> bool: - return ((self.i1 < other.i1 < self.i2) or - (self.i1 < other.i2 < self.i2) or - (other.i1 < self.i1 < other.i2) or - (other.i1 < self.i2 < other.i2)) - - def has_same_input(self, other: 'Comparator') -> bool: - return (self.i1 == other.i1 or - self.i1 == other.i2 or - self.i2 == other.i1 or - self.i2 == other.i2) - - -def get_max_input(comparators: list[Comparator]) -> int: - max_input = 0 - for c in comparators: - if c.i2 > max_input: - max_input = c.i2 - return max_input - - -def convert(indices: list[int], path: str) -> None: - comparators: list[Comparator] = [] - for i in range(1, len(indices), 2): - comparators.append(Comparator(indices[i - 1], indices[i])) - - scale = 1 - x_scale = scale * 35 - y_scale = scale * 20 - - comparators_svg = '' - w = x_scale - group: dict[Comparator, float] = {} - for c in comparators: - for other in group: - if c.has_same_input(other): - for (_, pos) in group.items(): - if pos > w: - w = pos - w += x_scale - group.clear() - break - - cx = w - for (other, other_pos) in group.items(): - if other_pos >= cx and c.overlaps(other): - cx = other_pos + x_scale / 3 - - y0 = y_scale + c.i1 * y_scale - y1 = y_scale + c.i2 * y_scale - comparators_svg += ( - "" % (cx, y0, 3) + - "" % (cx, y0, cx, y1, 1) + - "" % (cx, y1, 3) - ) - group[c] = cx - - lines_svg = '' - w += x_scale - n = get_max_input(comparators) + 1 - for i in range(n): - y = y_scale + i * y_scale - lines_svg += ( - "" % - (0, y, w, y, 1) - ) - - h = (n + 1) * y_scale - with open(path, 'w') as fp: - fp.write( - "" + - "" + - "" % (w, h) + - comparators_svg + - lines_svg + - "" - ) From 43c1bf3b13c2c3a6050ec5ded06f2557a4dc0c56 Mon Sep 17 00:00:00 2001 From: "Josiah (Gaming32) Glosson" Date: Fri, 26 Nov 2021 16:51:37 -0600 Subject: [PATCH 07/23] Write to file directly Some sizing data is messed up, causing the browser to think the image is much bigger than it actually is. --- src/utils/SortingNetworkGenerator.java | 40 +++++++++++++++++--------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/utils/SortingNetworkGenerator.java b/src/utils/SortingNetworkGenerator.java index 7a264e15..2ef2d933 100644 --- a/src/utils/SortingNetworkGenerator.java +++ b/src/utils/SortingNetworkGenerator.java @@ -1,9 +1,13 @@ package utils; import java.awt.Desktop; +import java.io.BufferedWriter; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStreamWriter; import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -47,6 +51,8 @@ boolean hasSameInput(Comparator other) { } } + private static final int OUT_BUFFER_SIZE = 33_554_432; // 64 MB + private static int getMaxInput(Comparator[] comparators) { int maxInput = 0; for (Comparator c : comparators) { @@ -57,12 +63,14 @@ private static int getMaxInput(Comparator[] comparators) { return maxInput; } - public static boolean encodeNetwork(Comparator[] comparators, File file) { + private static void encodeNetwork0(final Comparator[] comparators, final PrintWriter out) { int scale = 1; int xScale = scale * 35; int yScale = scale * 20; - StringBuilder comparatorsSvg = new StringBuilder(); + out.write(""); + out.write(""); + double w = xScale; Map group = new HashMap<>(); for (Comparator c : comparators) { @@ -90,27 +98,31 @@ public static boolean encodeNetwork(Comparator[] comparators, File file) { int y0 = yScale + c.i1 * yScale; int y1 = yScale + c.i2 * yScale; - comparatorsSvg.append("") - .append("") - .append(""); + out.write("" + + "" + + ""); group.put(c, cx); } - StringBuilder linesSvg = new StringBuilder(); w += xScale; int n = getMaxInput(comparators) + 1; for (int i = 0; i < n; i++) { int y = yScale + i * yScale; - linesSvg.append(""); + out.write(""); } - int h = (n + 1) * yScale; - try (PrintWriter writer = new PrintWriter(file, "UTF-8")) { - writer.write(""); - writer.write(""); - writer.write(comparatorsSvg.toString()); - writer.write(linesSvg.toString()); - writer.write(""); + out.write(""); + } + + public static boolean encodeNetwork(Comparator[] comparators, File file) { + try (PrintWriter out = new PrintWriter( + new BufferedWriter( + new OutputStreamWriter( + new FileOutputStream(file), StandardCharsets.UTF_8 + ), OUT_BUFFER_SIZE), + false) + ) { + encodeNetwork0(comparators, out); } catch (Exception e) { JErrorPane.invokeErrorMessage(e, "Sorting Network Visualizer"); return false; From 707aa263835735038f33a7cb74a8d76b2e8e92d9 Mon Sep 17 00:00:00 2001 From: "Josiah (Gaming32) Glosson" Date: Tue, 30 Nov 2021 07:15:15 -0600 Subject: [PATCH 08/23] Fix size-related bugs --- src/utils/SortingNetworkGenerator.java | 91 +++++++++++++++++++++++--- 1 file changed, 82 insertions(+), 9 deletions(-) diff --git a/src/utils/SortingNetworkGenerator.java b/src/utils/SortingNetworkGenerator.java index 2ef2d933..41470ecb 100644 --- a/src/utils/SortingNetworkGenerator.java +++ b/src/utils/SortingNetworkGenerator.java @@ -19,7 +19,7 @@ public class SortingNetworkGenerator { private static final class Comparator { - int i1, i2; + final int i1, i2; Comparator(int i1, int i2) { this.i1 = i1; @@ -51,6 +51,40 @@ boolean hasSameInput(Comparator other) { } } + private static final class WriterBuilderProxy { + final PrintWriter writer; + final StringBuilder builder; + + WriterBuilderProxy(PrintWriter writer) { + this.writer = writer; + this.builder = null; + } + + WriterBuilderProxy(StringBuilder builder) { + this.writer = null; + this.builder = builder; + } + + void write(String s) { + if (builder == null) + writer.write(s); + else + builder.append(s); + } + + @Override + public String toString() { + return builder == null ? writer.toString() : builder.toString(); + } + + String getValue() { + if (builder == null) { + throw new IllegalStateException("Cannot getValue() of PrintWriter"); + } + return builder.toString(); + } + } + private static final int OUT_BUFFER_SIZE = 33_554_432; // 64 MB private static int getMaxInput(Comparator[] comparators) { @@ -67,12 +101,48 @@ private static void encodeNetwork0(final Comparator[] comparators, final PrintWr int scale = 1; int xScale = scale * 35; int yScale = scale * 20; + boolean small = comparators.length < 500_000; - out.write(""); - out.write(""); - + int n = getMaxInput(comparators) + 1; + int h = (n + 1) * yScale; double w = xScale; Map group = new HashMap<>(); + + WriterBuilderProxy writer; + out.write(""); + if (small) { + writer = new WriterBuilderProxy(new StringBuilder()); + } else { + for (Comparator c : comparators) { + for (Comparator other : group.keySet()) { + if (c.hasSameInput(other)) { + for (double pos : group.values()) { + if (pos > w) { + w = pos; + } + } + w += xScale; + group.clear(); + break; + } + } + double cx = w; + for (Entry entry : group.entrySet()) { + Comparator other = entry.getKey(); + double otherPos = entry.getValue(); + if (otherPos >= cx && c.overlaps(other)) { + cx = otherPos + xScale / 3.0; + } + } + group.put(c, cx); + } + group.clear(); + out.write(""); + w = xScale; + + writer = new WriterBuilderProxy(out); + } + for (Comparator c : comparators) { for (Comparator other : group.keySet()) { if (c.hasSameInput(other)) { @@ -98,19 +168,22 @@ private static void encodeNetwork0(final Comparator[] comparators, final PrintWr int y0 = yScale + c.i1 * yScale; int y1 = yScale + c.i2 * yScale; - out.write("" + - "" + - ""); + writer.write("" + + "" + + ""); group.put(c, cx); } w += xScale; - int n = getMaxInput(comparators) + 1; for (int i = 0; i < n; i++) { int y = yScale + i * yScale; - out.write(""); + writer.write(""); } + if (small) { + out.write(""); + out.write(writer.getValue()); + } out.write(""); } From 730e87f1d0298b4d7d2f68564c6143eaa981951d Mon Sep 17 00:00:00 2001 From: "Josiah (Gaming32) Glosson" Date: Tue, 30 Nov 2021 09:05:51 -0600 Subject: [PATCH 09/23] Add progress bar --- src/main/ArrayVisualizer.java | 15 +++++++++++ src/utils/SortingNetworkGenerator.java | 35 +++++++++++++++++++++++--- 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/src/main/ArrayVisualizer.java b/src/main/ArrayVisualizer.java index 755e3eb3..d23365dd 100644 --- a/src/main/ArrayVisualizer.java +++ b/src/main/ArrayVisualizer.java @@ -84,6 +84,8 @@ of this software and associated documentation files (the "Software"), to deal */ final public class ArrayVisualizer { + private static ArrayVisualizer INSTANCE = null; + final JFrame window; final private int MIN_ARRAY_VAL; @@ -183,6 +185,11 @@ final public class ArrayVisualizer { private volatile boolean frameSkipped; public ArrayVisualizer() { + if (INSTANCE != null) { + throw new IllegalStateException("Cannot create more than one ArrayVisualizer"); + } + INSTANCE = this; + this.window = new JFrame(); this.window.addKeyListener(new KeyListener() { @Override @@ -494,6 +501,14 @@ public void run() { this.drawWindows(); } + public static ArrayVisualizer getInstance() { + return INSTANCE; + } + + public JFrame getWindow() { + return window; + } + public void refreshSorts() { this.ComparisonSorts = this.SortAnalyzer.getComparisonSorts(); this.DistributionSorts = this.SortAnalyzer.getDistributionSorts(); diff --git a/src/utils/SortingNetworkGenerator.java b/src/utils/SortingNetworkGenerator.java index 41470ecb..5d9aee68 100644 --- a/src/utils/SortingNetworkGenerator.java +++ b/src/utils/SortingNetworkGenerator.java @@ -14,7 +14,9 @@ import java.util.Map.Entry; import javax.swing.JOptionPane; +import javax.swing.ProgressMonitor; +import main.ArrayVisualizer; import panes.JErrorPane; public class SortingNetworkGenerator { @@ -85,7 +87,7 @@ String getValue() { } } - private static final int OUT_BUFFER_SIZE = 33_554_432; // 64 MB + private static final int OUT_BUFFER_SIZE = 16_777_216; // 32 MB private static int getMaxInput(Comparator[] comparators) { int maxInput = 0; @@ -97,7 +99,7 @@ private static int getMaxInput(Comparator[] comparators) { return maxInput; } - private static void encodeNetwork0(final Comparator[] comparators, final PrintWriter out) { + private static boolean encodeNetwork0(final Comparator[] comparators, final PrintWriter out) { int scale = 1; int xScale = scale * 35; int yScale = scale * 20; @@ -109,10 +111,19 @@ private static void encodeNetwork0(final Comparator[] comparators, final PrintWr Map group = new HashMap<>(); WriterBuilderProxy writer; + ProgressMonitor monitor; + int progress = 0; out.write(""); if (small) { writer = new WriterBuilderProxy(new StringBuilder()); + monitor = null; } else { + monitor = new ProgressMonitor( + ArrayVisualizer.getInstance().getWindow(), + "Visualizing sorting network...", + "Pre-Calculating Image Width", + 0, comparators.length * 2 + ); for (Comparator c : comparators) { for (Comparator other : group.keySet()) { if (c.hasSameInput(other)) { @@ -135,8 +146,14 @@ private static void encodeNetwork0(final Comparator[] comparators, final PrintWr } } group.put(c, cx); + + if (monitor != null && (progress++ & 1023) == 0) { + monitor.setProgress(progress); + if (monitor.isCanceled()) return true; + } } group.clear(); + monitor.setNote("Writing SVG"); out.write(""); w = xScale; @@ -172,6 +189,11 @@ private static void encodeNetwork0(final Comparator[] comparators, final PrintWr "" + ""); group.put(c, cx); + + if (monitor != null && (progress++ & 1023) == 0) { + monitor.setProgress(progress); + if (monitor.isCanceled()) return true; + } } w += xScale; @@ -185,6 +207,8 @@ private static void encodeNetwork0(final Comparator[] comparators, final PrintWr out.write(writer.getValue()); } out.write(""); + if (monitor != null) monitor.close(); + return false; } public static boolean encodeNetwork(Comparator[] comparators, File file) { @@ -195,7 +219,12 @@ public static boolean encodeNetwork(Comparator[] comparators, File file) { ), OUT_BUFFER_SIZE), false) ) { - encodeNetwork0(comparators, out); + boolean cancelled = encodeNetwork0(comparators, out); + if (cancelled) { + JOptionPane.showMessageDialog(null, "Sorting network visualization cancelled", + "Sorting Network Visualizer", JOptionPane.INFORMATION_MESSAGE); + return false; + } } catch (Exception e) { JErrorPane.invokeErrorMessage(e, "Sorting Network Visualizer"); return false; From 14acb32904db0f0be275524f3ce81c4e674614ea Mon Sep 17 00:00:00 2001 From: "Josiah (Gaming32) Glosson" Date: Wed, 1 Dec 2021 11:41:31 -0600 Subject: [PATCH 10/23] Remove sorting-network/master clone --- .../sorting_network_master/.gitignore | 2 - src/resources/sorting_network_master/LICENSE | 21 -- .../sorting_network_master/README.md | 132 ---------- .../SortingNetworkFetcher.java | 42 --- .../examples/16-input.cn | 10 - .../examples/16-input.png | Bin 10076 -> 0 bytes .../examples/16-input.svg | 1 - .../examples/4-input.cn | 3 - .../examples/4-input.png | Bin 842 -> 0 bytes .../examples/4-input.svg | 1 - .../examples/5-input.cn | 6 - .../examples/5-input.png | Bin 1465 -> 0 bytes .../examples/5-input.svg | 1 - src/resources/sorting_network_master/out.svg | 1 - .../sorting_network_master/sortingnetwork.py | 243 ------------------ 15 files changed, 463 deletions(-) delete mode 100644 src/resources/sorting_network_master/.gitignore delete mode 100644 src/resources/sorting_network_master/LICENSE delete mode 100644 src/resources/sorting_network_master/README.md delete mode 100644 src/resources/sorting_network_master/SortingNetworkFetcher.java delete mode 100644 src/resources/sorting_network_master/examples/16-input.cn delete mode 100644 src/resources/sorting_network_master/examples/16-input.png delete mode 100644 src/resources/sorting_network_master/examples/16-input.svg delete mode 100644 src/resources/sorting_network_master/examples/4-input.cn delete mode 100644 src/resources/sorting_network_master/examples/4-input.png delete mode 100644 src/resources/sorting_network_master/examples/4-input.svg delete mode 100644 src/resources/sorting_network_master/examples/5-input.cn delete mode 100644 src/resources/sorting_network_master/examples/5-input.png delete mode 100644 src/resources/sorting_network_master/examples/5-input.svg delete mode 100644 src/resources/sorting_network_master/out.svg delete mode 100644 src/resources/sorting_network_master/sortingnetwork.py diff --git a/src/resources/sorting_network_master/.gitignore b/src/resources/sorting_network_master/.gitignore deleted file mode 100644 index e04276f9..00000000 --- a/src/resources/sorting_network_master/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.idea -venv diff --git a/src/resources/sorting_network_master/LICENSE b/src/resources/sorting_network_master/LICENSE deleted file mode 100644 index 5c0026a1..00000000 --- a/src/resources/sorting_network_master/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Brian Pursley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/src/resources/sorting_network_master/README.md b/src/resources/sorting_network_master/README.md deleted file mode 100644 index 3086d992..00000000 --- a/src/resources/sorting_network_master/README.md +++ /dev/null @@ -1,132 +0,0 @@ -# sorting-network -Python script to check sorting networks and generate sorting network diagrams - -## Usage - -``` -usage: sortingnetwork.py [-h] [-i inputfile] [-o [outputfile]] [-c] [-s [list]] [--svg [outputfile]] - -optional arguments: - -h, --help show this help message and exit - -i inputfile, --input inputfile specify a file containing comparison network definition - -o [outputfile], --output [outputfile] specify a file for saving the comparison network definition - -c, --check check whether it is a sorting network - --show-progress show percent complete while checking whether it is a - sorting network - -s [list], --sort [list] sorts the list using the input comparison network - --svg [outputfile] generate SVG - -``` - -Comparison networks can be specified like this: `0:1,2:3,0:2,1:3,1:2` and can either be loaded from a file using the `--input` argument or if no input file is specified, read from stdin. - -Multiple lines can be used as well, to logically group the comparators at each depth. `0:1,2:3,0:2,1:3,1:2` is the same as this: -``` -0:1,2:3 -0:2,1:3 -1:2 -``` - -## Examples -##### Read a comparison network from a file called example.cn and check whether it is is a sorting network. -``` -./sortingnetwork.py --input example.cn --check -``` - -##### Pipe a comparison network from stdin and check whether it is is a sorting network. -``` -echo "0:1,2:3,0:2,1:3,1:2" | ./sortingnetwork.py --check -``` - -##### Read a comparison network from a file called example.cn and generate SVG to stdout. -``` -./sortingnetwork.py --input example.cn --svg -``` - -##### Read a comparison network from a file called example.cn and generate SVG, saved to a file called output.svg. -``` -./sortingnetwork.py --input example.cn --svg output.svg -``` - -##### Pipe the output to rsvg-convert to generate a PNG (or other format) instead of SVG. -(*rsvg-convert can be installed by using `sudo apt-get install librsvg2-bin` on Ubuntu.*) - -4-input sorting network: -``` -./sortingnetwork.py --input examples/4-input.cn --svg | rsvg-convert > examples/4-input.png -``` - -5-input sorting network: -``` -./sortingnetwork.py --input examples/5-input.cn --svg | rsvg-convert > examples/5-input.png -``` - -##### Use a specified sorting network to sort a list. - -Using a 4-input sorting network to sort a list containing 4 items: -``` -./sortingnetwork.py --input examples/4-input.cn --sort 2,4,1,3 -``` -Outputs -``` -1 -2 -3 -4 -``` - -Using a 5-input sorting network to sort a list containing 5 items: -``` -./sortingnetwork.py --input examples/5-input.cn --sort 5,2,4,1,3 -``` -Outputs -``` -1 -2 -3 -4 -5 -``` - -## Example sorting networks - -### 4-Input - -```text -0:1,2:3 -0:2,1:3 -1:2 -``` - -![4-Input Sorting Network](https://github.com/brianpursley/sorting-network/blob/master/examples/4-input.png) - -### 5-Input - -```text -0:1,3:4 -2:4 -2:3,1:4 -0:3 -0:2,1:3 -1:2 -``` - -![5-Input Sorting Network](https://github.com/brianpursley/sorting-network/blob/master/examples/5-input.png) - -### 16-Input - -```text -0:1,2:3,4:5,6:7,8:9,10:11,12:13,14:15 -0:2,1:3,4:6,5:7,8:10,9:11,12:14,13:15 -0:4,1:5,2:6,3:7,8:12,9:13,10:14,11:15 -0:8,1:9,2:10,3:11,4:12,5:13,6:14,7:15 -5:10,6:9,3:12,13:14,7:11,1:2,4:8 -1:4,7:13,2:8,11:14 -2:4,5:6,9:10,11:13,3:8,7:12 -6:8,10:12,3:5,7:9 -3:4,5:6,7:8,9:10,11:12 -6:7,8:9 -``` - -![16-Input Sorting Network](https://github.com/brianpursley/sorting-network/blob/master/examples/16-input.png) - diff --git a/src/resources/sorting_network_master/SortingNetworkFetcher.java b/src/resources/sorting_network_master/SortingNetworkFetcher.java deleted file mode 100644 index 8ea2c3f8..00000000 --- a/src/resources/sorting_network_master/SortingNetworkFetcher.java +++ /dev/null @@ -1,42 +0,0 @@ -package resources.sorting_network_master; - -import java.io.File; - -import resources.Fetcher; - -/* - * -MIT License - -Copyright (c) 2021 ArrayV 4.0 Team - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - * - */ - -//TODO: Create abstract "fetcher" class for both sound effects and custom image -final public class SortingNetworkFetcher extends Fetcher { - public SortingNetworkFetcher() { - super("sortingnetwork.py"); - } - - public SortingNetworkFetcher(File file) { - super(file); - } -} \ No newline at end of file diff --git a/src/resources/sorting_network_master/examples/16-input.cn b/src/resources/sorting_network_master/examples/16-input.cn deleted file mode 100644 index d1b11b83..00000000 --- a/src/resources/sorting_network_master/examples/16-input.cn +++ /dev/null @@ -1,10 +0,0 @@ -0:1,2:3,4:5,6:7,8:9,10:11,12:13,14:15 -0:2,1:3,4:6,5:7,8:10,9:11,12:14,13:15 -0:4,1:5,2:6,3:7,8:12,9:13,10:14,11:15 -0:8,1:9,2:10,3:11,4:12,5:13,6:14,7:15 -5:10,6:9,3:12,13:14,7:11,1:2,4:8 -1:4,7:13,2:8,11:14 -2:4,5:6,9:10,11:13,3:8,7:12 -6:8,10:12,3:5,7:9 -3:4,5:6,7:8,9:10,11:12 -6:7,8:9 diff --git a/src/resources/sorting_network_master/examples/16-input.png b/src/resources/sorting_network_master/examples/16-input.png deleted file mode 100644 index 87c7d9041487b9fd812658696273f9a475b15243..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10076 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 ZJn$?8?*q2S0mtP)2t!kY;_q(U{U6cR?B)Of diff --git a/src/resources/sorting_network_master/examples/16-input.svg b/src/resources/sorting_network_master/examples/16-input.svg deleted file mode 100644 index 6ecb1d6d..00000000 --- a/src/resources/sorting_network_master/examples/16-input.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/resources/sorting_network_master/examples/4-input.cn b/src/resources/sorting_network_master/examples/4-input.cn deleted file mode 100644 index 10305967..00000000 --- a/src/resources/sorting_network_master/examples/4-input.cn +++ /dev/null @@ -1,3 +0,0 @@ -0:1,2:3 -0:2,1:3 -1:2 diff --git a/src/resources/sorting_network_master/examples/4-input.png b/src/resources/sorting_network_master/examples/4-input.png deleted file mode 100644 index 5cf2480c1a14ca0741d27044685f3ffa0caa92d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 842 zcmeAS@N?(olHy`uVBq!ia0vp^Gk`dSgAGVlP5S8!q}Y|gW!U_%O^81F#Y#* zaSW-L^Y+gEERjTs){p9j%QlK|pY~nYnwq05)@1%bb%sdUBi@|s%V`g}P@RHH3|wt0m!^8?SnT7NGq1y8#d ztu4D?8~dKzn%JOaI(w)8blx|ufi+lzds%>(&qAFUPLT$!n-aKE4~m>>(wqX3h-2GB40~?b%5uD%kJOIWgtlL4M2Hm(_d~Ts4gQnAs256_^@D z@NZf&sq~5YlP^uS4^qC}Kd}2mg6)Y<{i3JxKjkw&@8A1hxWaL#?4Ps0&R-AycaE>1 z^3d=74ekfF=PCP6)%2b``wwf%sp*>DT5(FdCu(|IJ(jKcoOu0`^$*3j_D|#)+Cz4J zZ`7W6uxf(pQpV7W+fHt5mcR6G^GmT0oIChqI8I#-Tc$HB=|s-{KW~_>J54&H7cBN) zJ$@s0|G_{nq`F*2L^WjL#PuT~HKRuuRHRqSl zohSMV)pie6gZ?`nEB \ No newline at end of file diff --git a/src/resources/sorting_network_master/examples/5-input.cn b/src/resources/sorting_network_master/examples/5-input.cn deleted file mode 100644 index 256f1226..00000000 --- a/src/resources/sorting_network_master/examples/5-input.cn +++ /dev/null @@ -1,6 +0,0 @@ -0:1,3:4 -2:4 -2:3,1:4 -0:3 -0:2,1:3 -1:2 diff --git a/src/resources/sorting_network_master/examples/5-input.png b/src/resources/sorting_network_master/examples/5-input.png deleted file mode 100644 index 7a219ec960eeaf3cae727e874e7e237909add276..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1465 zcma)6YfzGD6vhZCGo9TwSEHDzDJB(k)_W*zi#BSapsg2DMs&byYTj`*#oE+zNke3X zkO z3bj_gOEX4PVxxEt+dKU#t@KW*d!lxn)cK!BVs^QIYd{Q)bHtHz7w!`Gw%F?$?|@H2 z?acOWzgBbTOfs!Df63LqDn2zX191LS2##bO9k?HlCudj^dQJSfhrgP(6`2p=Sz+u6 zb|@GQwm(jHfiEcTDwrS=?4i2sx)1MEbT7X^xHV!%(re+VCcW^YZJr7m_>Zlo&L-lf zd0A%dvF`Vu{gR7^;{)I<+B$?mw(?%V-Ztmf5PF`4a1_PTa8c@OI|TWK_% zMQnQ9rdmCjdSPPm?m-TW!_{Z2c_*DgT>qc_S*S|e@;JuD_jQ|Nv`!v}@~~kpVa8r zWo`kU(Vi#bFNH|pf3HmCJj3E5rT1Qu6}~)`cVPTZmJO>U1T+Y!8G27bsd9SBP#ZM9 ztRf+M4pEya<0+-S3#@WHb4nn)6;nKPmVvvHm_jcIptg4#t=eCsaOe5PT4|y5%_TUx z7uHoF0)nqEzRmLp$h+9(-My>|P@oi!)j-kw9V~g9rllx4Z6^!GN-7)6~1}UH8_$g7oRDp0)9=DMJ;R=m_poH1CRF` z+&iRZ3y9zcX-Hx0?>q1RcssQ>K>}%pbl5gg>?t43e(cj>mlK zc-_TW!gp(FRUJn>YefJ@t*x)I4ajL~t`-5iSNM#NN%4uF_)mj0riP8WKFiR?F-N>x zz>>S3vV`qx9({@QIxv=6?zwo6LJV;9iz3inF$+$Y#Y1 z@~~cS?3+wOttYKy2MT2J#nt7cK?2zK;$X>)f%n~OMdg;jXVULcR6%YHMWB7v-cy1h zyQL=e17GJ1(7wEzAUuURT@jZ?+`z~RX(h_($a%y5>3TsiLDM*AIJj!&Jkm??Xsa3*Nf)JAAFZwK3 z8&eSnclwa<5u=?mEKV>V*~}27Zzj=$=8MB##F8sLmh5RozV7YZQ#_s}ci8YfGArR^ z=fS#&dT{}I{hRd~x8uM{K1cFyXh&=s>PiIby};$D4(fsD5-5YAZ{fA o(6^*Y#$qcZU$;8Q|2Xd*cObmgOj>Cs \ No newline at end of file diff --git a/src/resources/sorting_network_master/out.svg b/src/resources/sorting_network_master/out.svg deleted file mode 100644 index e63a5200..00000000 --- a/src/resources/sorting_network_master/out.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/resources/sorting_network_master/sortingnetwork.py b/src/resources/sorting_network_master/sortingnetwork.py deleted file mode 100644 index 86c41636..00000000 --- a/src/resources/sorting_network_master/sortingnetwork.py +++ /dev/null @@ -1,243 +0,0 @@ - - -''' -The MIT License (MIT) - -Copyright (c) 2015 Brian Pursley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the 'Software'), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -''' - -import argparse -import sys - - -class Comparator: - def __init__(self, s): - inputs = s.strip().split(':') - input1 = int(inputs[0]) - input2 = int(inputs[1]) - if input1 < input2: - self.i1 = input1 - self.i2 = input2 - else: - self.i1 = input2 - self.i2 = input1 - - def __str__(self): - return '%s:%s' % (self.i1, self.i2) - - def __hash__(self): - return ('%s:%s' % (self.i1, self.i2)).__hash__() - - def overlaps(self, other): - return (self.i1 < other.i1 < self.i2) or \ - (self.i1 < other.i2 < self.i2) or \ - (other.i1 < self.i1 < other.i2) or \ - (other.i1 < self.i2 < other.i2) - - def has_same_input(self, other): - return self.i1 == other.i1 or \ - self.i1 == other.i2 or \ - self.i2 == other.i1 or \ - self.i2 == other.i2 - - -class ComparisonNetwork(list): - def __str__(self): - result = '' - group = [] - for c in self: - for other in group: - if c.has_same_input(other): - result += ','.join(map(str, group)) + '\n' - del group[:] - break - group.append(c) - result += ','.join(map(str, group)) - return result - - def is_sorting_network(self, show_progress): - - number_of_inputs = self.get_max_input() + 1 - max_sequence_to_check = (1 << number_of_inputs) - 1 - for i in range(0, max_sequence_to_check): - ones_count = count_ones(i) - if ones_count > 0: - zeros_count = number_of_inputs - ones_count - expected_sorted_sequence = ((1 << ones_count) - 1) << zeros_count - else: - expected_sorted_sequence = 0 - if self.sort_binary_sequence(i) != expected_sorted_sequence: - return False - if show_progress and i % 100 == 0: - print('\rChecking... %s%%' % round(i * 100 / max_sequence_to_check), end='') - if show_progress: - print('\r', end='') - return True - - def sort_binary_sequence(self, sequence): - result = sequence - - for c in self: - - pos0 = (result >> c.i1) & 1 - pos1 = (result >> c.i2) & 1 - if pos0 > pos1: - result ^= (1 << c.i1) | (1 << c.i2) - return result - - def sort_sequence(self, sequence): - result = list(sequence) - for c in self: - if result[c.i1] > result[c.i2]: - result[c.i1], result[c.i2] = result[c.i2], result[c.i1] - return result - - def get_max_input(self): - max_input = 0 - for c in self: - if c.i2 > max_input: - max_input = c.i2 - return max_input - - def svg(self): - scale = 1 - x_scale = scale * 35 - y_scale = scale * 20 - - comparators_svg = '' - w = x_scale - group = {} - for c in self: - - - for other in group: - if c.has_same_input(other): - for _, pos in group.items(): - if pos > w: - w = pos - w += x_scale - group = {} - break - - - cx = w - for other, other_pos in group.items(): - if other_pos >= cx and c.overlaps(other): - cx = other_pos + x_scale / 3 - - - y0 = y_scale + c.i1 * y_scale - y1 = y_scale + c.i2 * y_scale - comparators_svg += \ - '' % (cx, y0, 3) + \ - '' % (cx, y0, cx, y1, 1) + \ - '' % (cx, y1, 3) - - group[c] = cx - - - lines_svg = '' - w += x_scale - n = self.get_max_input() + 1 - for i in range(0, n): - y = y_scale + i * y_scale - lines_svg += '' % ( - 0, y, w, y, 1) - - h = (n + 1) * y_scale - return \ - '' + \ - '' + \ - '' % (w, h) + \ - comparators_svg + \ - lines_svg + \ - '' - - -def count_ones(x): - result = 0 - while x > 0: - result += x & 1 - x = x >> 1 - return result - - -def read_comparison_network(filename): - cn = ComparisonNetwork() - if filename: - with open(filename, 'r') as f: - for line in f: - for c in line.split(','): - cn.append(Comparator(c)) - else: - for line in sys.stdin: - for c in line.split(','): - cn.append(Comparator(c)) - return cn - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument('-i', '--input', metavar='inputfile', - help='specify a file containing comparison network definition') - parser.add_argument('-o', '--output', metavar='outputfile', nargs='?', const='', - help='specify a file for saving the comparison network definition') - parser.add_argument('-c', '--check', action='store_true', help='check whether it is a sorting network') - parser.add_argument('--show-progress', action='store_true', help='show percent complete while checking whether it is a sorting network') - parser.add_argument('-s', '--sort', metavar='list', nargs='?', const='', - help='sorts the list using the input comparison network') - parser.add_argument('--svg', metavar='outputfile', nargs='?', const='', help='generate SVG') - args = parser.parse_args() - - if args.check: - cn = read_comparison_network(args.input) - if cn.is_sorting_network(args.show_progress): - print('It is a sorting network!') - else: - print('It is not a sorting network.') - - if args.svg or args.svg == '': - cn = read_comparison_network(args.input) - if args.svg == '': - print(cn.svg()) - else: - with open(args.svg, 'w') as f: - f.write(cn.svg()) - - if args.output or args.output == '': - cn = read_comparison_network(args.input) - if args.output == '': - print(str(cn)) - else: - with open(args.output, 'w') as f: - f.write(str(cn)) - - if args.sort or args.sort == '': - cn = read_comparison_network(args.input) - if args.sort == '': - input_sequence = eval(sys.stdin.readline()) - else: - input_sequence = eval(args.sort) - for sorted_item in cn.sort_sequence(input_sequence): - print(sorted_item) - - -main() From a8f373cb77a9271535b2db6d31cc69fe3fdc7b32 Mon Sep 17 00:00:00 2001 From: "Josiah (Gaming32) Glosson" Date: Wed, 1 Dec 2021 11:44:33 -0600 Subject: [PATCH 11/23] Change warning message --- src/frames/UtilFrame.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/frames/UtilFrame.java b/src/frames/UtilFrame.java index b57000a1..7a2db5a5 100644 --- a/src/frames/UtilFrame.java +++ b/src/frames/UtilFrame.java @@ -595,10 +595,9 @@ private void jComboBox1ActionPerformed() {//GEN-FIRST:event_jButton4ActionPerfor break; jButton6.setEnabled(true); ArrayVisualizer.setComparator(4); - if (ArrayVisualizer.getCurrentLength() > 256) { - JOptionPane.showMessageDialog(null, "Large sorting networks take too long and will not be generated. Array lengths less than or equal to 256 are recommended.", + if (ArrayVisualizer.getCurrentLength() > 1024) { + JOptionPane.showMessageDialog(null, "Large sorting networks can take a long time (and high RAM usage) to visualize.", "Sorting Network Visualizer", JOptionPane.WARNING_MESSAGE); - ArrayVisualizer.getArrayFrame().setLengthSlider(256); } break; From b70d0a667ce548ace84ab3080db5281a3351aca9 Mon Sep 17 00:00:00 2001 From: "Josiah (Gaming32) Glosson" Date: Fri, 24 Dec 2021 06:23:10 -0600 Subject: [PATCH 12/23] Update UtilFrame.java --- src/frames/UtilFrame.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/frames/UtilFrame.java b/src/frames/UtilFrame.java index 7a2db5a5..34310c7e 100644 --- a/src/frames/UtilFrame.java +++ b/src/frames/UtilFrame.java @@ -596,8 +596,12 @@ private void jComboBox1ActionPerformed() {//GEN-FIRST:event_jButton4ActionPerfor jButton6.setEnabled(true); ArrayVisualizer.setComparator(4); if (ArrayVisualizer.getCurrentLength() > 1024) { - JOptionPane.showMessageDialog(null, "Large sorting networks can take a long time (and high RAM usage) to visualize.", - "Sorting Network Visualizer", JOptionPane.WARNING_MESSAGE); + JOptionPane.showMessageDialog( + null, + "Large sorting networks can take a long time (and high RAM usage) to visualize.\n" + + "A length of 1024 or less is recommended.", + "Sorting Network Visualizer", JOptionPane.WARNING_MESSAGE + ); } break; From 1a27cd3dc1d02269ecdec2fabf9d21281e865ee2 Mon Sep 17 00:00:00 2001 From: "Josiah (Gaming32) Glosson" Date: Fri, 24 Dec 2021 06:57:48 -0600 Subject: [PATCH 13/23] Put sorting networks in subdirectory --- src/utils/SortingNetworkGenerator.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/utils/SortingNetworkGenerator.java b/src/utils/SortingNetworkGenerator.java index 5d9aee68..5d327f9b 100644 --- a/src/utils/SortingNetworkGenerator.java +++ b/src/utils/SortingNetworkGenerator.java @@ -20,6 +20,12 @@ import panes.JErrorPane; public class SortingNetworkGenerator { + private static final File SORTING_NETWORKS_DIR = new File("sorting_networks"); + + static { + SORTING_NETWORKS_DIR.mkdirs(); + } + private static final class Comparator { final int i1, i2; @@ -232,7 +238,7 @@ public static boolean encodeNetwork(Comparator[] comparators, File file) { return true; } - public static String encodeNetworkAndDisplay(String name, ArrayList indices, int arrayLength) { + public static File encodeNetworkAndDisplay(String name, ArrayList indices, int arrayLength) { Comparator[] comparators; try { comparators = new Comparator[indices.size() / 2]; @@ -246,8 +252,7 @@ public static String encodeNetworkAndDisplay(String name, ArrayList ind System.out.println("Length: " + arrayLength + "\tComparators: " + comparators.length / 2); indices.clear(); indices.trimToSize(); - String path = "network_" + name + "_" + arrayLength + ".svg"; - File file = new File(path); + File file = new File(SORTING_NETWORKS_DIR, "network_" + name + "_" + arrayLength + ".svg"); try { if (!encodeNetwork(comparators, file)) { return null; @@ -259,7 +264,7 @@ public static String encodeNetworkAndDisplay(String name, ArrayList ind ); return null; } - JOptionPane.showMessageDialog(null, "Successfully saved output to file \"" + path + "\"", + JOptionPane.showMessageDialog(null, "Successfully saved output to file \"" + file + "\"", "Sorting Network Visualizer", JOptionPane.INFORMATION_MESSAGE); Desktop desktop = Desktop.getDesktop(); try { @@ -268,6 +273,6 @@ public static String encodeNetworkAndDisplay(String name, ArrayList ind catch (IOException e) { e.printStackTrace(); } - return path; + return file; } } From 60327e527b29ccba69adf4357105403c6cd46fb9 Mon Sep 17 00:00:00 2001 From: "Josiah (Gaming32) Glosson" Date: Mon, 27 Dec 2021 07:15:26 -0600 Subject: [PATCH 14/23] Rely on ProgressMonitor to decide whether to show itself --- src/utils/SortingNetworkGenerator.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/utils/SortingNetworkGenerator.java b/src/utils/SortingNetworkGenerator.java index 5d327f9b..5ce0c2b1 100644 --- a/src/utils/SortingNetworkGenerator.java +++ b/src/utils/SortingNetworkGenerator.java @@ -122,12 +122,17 @@ private static boolean encodeNetwork0(final Comparator[] comparators, final Prin out.write(""); if (small) { writer = new WriterBuilderProxy(new StringBuilder()); - monitor = null; + monitor = new ProgressMonitor( + ArrayVisualizer.getInstance().getWindow(), + "Visualizing sorting network...", + "Generating SVG", + 0, comparators.length + ); } else { monitor = new ProgressMonitor( ArrayVisualizer.getInstance().getWindow(), "Visualizing sorting network...", - "Pre-Calculating Image Width", + "Pre-calculating image width", 0, comparators.length * 2 ); for (Comparator c : comparators) { @@ -153,7 +158,7 @@ private static boolean encodeNetwork0(final Comparator[] comparators, final Prin } group.put(c, cx); - if (monitor != null && (progress++ & 1023) == 0) { + if ((progress++ & 1023) == 0) { monitor.setProgress(progress); if (monitor.isCanceled()) return true; } @@ -196,7 +201,7 @@ private static boolean encodeNetwork0(final Comparator[] comparators, final Prin ""); group.put(c, cx); - if (monitor != null && (progress++ & 1023) == 0) { + if ((progress++ & 1023) == 0) { monitor.setProgress(progress); if (monitor.isCanceled()) return true; } @@ -209,11 +214,12 @@ private static boolean encodeNetwork0(final Comparator[] comparators, final Prin } if (small) { + monitor.setNote("Writing SVG to file"); out.write(""); out.write(writer.getValue()); } out.write(""); - if (monitor != null) monitor.close(); + monitor.close(); return false; } From e4dfec1866d724c97fd2e8f0a960471064c08ecb Mon Sep 17 00:00:00 2001 From: "Josiah (Gaming32) Glosson" Date: Mon, 27 Dec 2021 07:22:29 -0600 Subject: [PATCH 15/23] Remove O(n log n) Buffered Stooge Sorts --- src/sorts/merge/OOPBufferedStoogeSort.java | 110 ----- .../merge/OOPBufferedStoogeSort_backup.java | 115 ----- src/sorts/merge/TimBufferedStoogeSort.java | 451 ------------------ 3 files changed, 676 deletions(-) delete mode 100644 src/sorts/merge/OOPBufferedStoogeSort.java delete mode 100644 src/sorts/merge/OOPBufferedStoogeSort_backup.java delete mode 100644 src/sorts/merge/TimBufferedStoogeSort.java diff --git a/src/sorts/merge/OOPBufferedStoogeSort.java b/src/sorts/merge/OOPBufferedStoogeSort.java deleted file mode 100644 index c42eb2a5..00000000 --- a/src/sorts/merge/OOPBufferedStoogeSort.java +++ /dev/null @@ -1,110 +0,0 @@ -package sorts.merge; - -import main.ArrayVisualizer; -import sorts.templates.Sort; - -/** - * @author _fluffyy - * @author thatsOven - * @author Gaming32 - */ -public class OOPBufferedStoogeSort extends Sort { - int[] aux; - - public OOPBufferedStoogeSort(ArrayVisualizer arrayVisualizer) { - super(arrayVisualizer); - this.setSortListName("OOP Buffered Stooge"); - this.setRunAllSortsName("OOP Buffered Stooge Sort"); - this.setRunSortName("OOP Buffered Stoogesort"); - this.setCategory("Merge Sorts"); - this.setComparisonBased(true); - this.setBucketSort(false); - this.setRadixSort(false); - this.setUnreasonablySlow(false); - this.setUnreasonableLimit(0); - this.setBogoSort(false); - } - - protected int compare(int[] arr, int x, int y) { - return Reads.compareIndices(arr, x, y, 0, true); - } - - protected void mergeOOP(int[] arr, int start, int mid, int end) { - Writes.arraycopy(arr, mid, aux, 0, end - mid, 1, true, true); - int auxPtr = end - mid - 1; - int left = mid - 1; - int right = end - 1; - Highlights.markArray(2, left); - while (right > left && left >= start) { - if (Reads.compareValues(aux[auxPtr], arr[left]) < 0) { - Writes.write(arr, right--, arr[left--], 1, true, false); - if (left >= 0) Highlights.markArray(2, left); - } else { - Writes.write(arr, right--, aux[auxPtr--], 1, true, false); - } - } - while (right > left) { - Writes.write(arr, right--, aux[auxPtr--], 1, true, false); - } - } - - public void wrapper(int[] arr, int start, int stop) { - if (stop - start > 1) { - if (stop - start == 2 && compare(arr, start, stop - 1) == 1) { - Writes.swap(arr, start, stop - 1, 1, true, false); - } - if (stop - start > 2) { - int third = (int) Math.ceil((stop - start) / 3.0) + start; - int twoThird = (int) Math.ceil((stop - start) / 3.0 * 2) + start; - if (twoThird - third < third) { - twoThird--; - } - if ((stop - start - 2) % 3 == 0) { - twoThird--; - } - wrapper(arr, third, twoThird); - wrapper(arr, twoThird, stop); - int left = third; - int right = twoThird; - int bufferStart = start; - while (left < twoThird && right < stop) { - if (compare(arr, left, right) < 0) { - Writes.swap(arr, bufferStart++, left++, 1, true, false); - } else { - Writes.swap(arr, bufferStart++, right++, 1, true, false); - } - } - while (right < stop) { - Writes.swap(arr, bufferStart++, right++, 1, true, false); - } - wrapper(arr, twoThird, stop); - if (stop - start > 8) { - if (stop > twoThird && twoThird > start) { - mergeOOP(arr, start, twoThird, stop); - } - } else { - int temp; - left = twoThird - 1; - right = stop - 1; - while (right > left && left >= start) { - if (compare(arr, left, right) > 0) { - temp = arr[left]; - Writes.arraycopy(arr, left + 1, arr, left, right - left, 0.5, true, false); - Writes.write(arr, right, temp, 0.5, true, false); - left--; - } - right--; - } - } - Highlights.clearMark(2); - } - } - } - - @Override - public void runSort(int[] array, int sortLength, int bucketCount) throws Exception { - aux = Writes.createExternalArray((sortLength + 2) / 3); - wrapper(array, 0, sortLength); - Writes.deleteExternalArray(aux); - } -} diff --git a/src/sorts/merge/OOPBufferedStoogeSort_backup.java b/src/sorts/merge/OOPBufferedStoogeSort_backup.java deleted file mode 100644 index 313311b1..00000000 --- a/src/sorts/merge/OOPBufferedStoogeSort_backup.java +++ /dev/null @@ -1,115 +0,0 @@ -package sorts.merge; - -import main.ArrayVisualizer; -import sorts.templates.Sort; - -/** - * @author _fluffyy - * @author thatsOven - * @author Gaming32 - */ -public class OOPBufferedStoogeSort_backup extends Sort { - int[] aux; - - public OOPBufferedStoogeSort_backup(ArrayVisualizer arrayVisualizer) { - super(arrayVisualizer); - this.setSortListName("OOP Buffered Stooge (old)"); - this.setRunAllSortsName("OOP Buffered Stooge Sort"); - this.setRunSortName("OOP Buffered Stoogesort"); - this.setCategory("Merge Sorts"); - this.setComparisonBased(true); - this.setBucketSort(false); - this.setRadixSort(false); - this.setUnreasonablySlow(false); - this.setUnreasonableLimit(0); - this.setBogoSort(false); - } - - protected int compare(int[] arr, int x, int y) { - return Reads.compareIndices(arr, x, y, 0, true); - } - - protected void mergeOOP(int[] arr, int start, int mid, int end) { - Writes.arraycopy(arr, mid, aux, 0, end - mid, 1, true, true); - int auxPtr = end - mid - 1; - int left = mid - 1; - int right = end - 1; - Highlights.markArray(2, left); - while (right > left && left >= start) { - if (Reads.compareValues(arr[left], aux[auxPtr]) > 0) { - Writes.write(arr, right--, arr[left--], 1, true, false); - if (left >= 0) Highlights.markArray(2, left); - } else { - Writes.write(arr, right--, aux[auxPtr--], 1, true, false); - } - } - while (right > left) { - Writes.write(arr, right--, aux[auxPtr--], 1, true, false); - } - } - - public void wrapper(int[] arr, int start, int stop) { - if (stop - start > 1) { - if (stop - start == 2 && compare(arr, start, stop - 1) == 1) { - Writes.swap(arr, start, stop - 1, 1, true, false); - } - if (stop - start > 2) { - int third = (int) Math.ceil((stop - start) / 3.0) + start; - int twoThird = (int) Math.ceil((stop - start) / 3.0 * 2) + start; - if (twoThird - third < third) { - twoThird--; - } - if ((stop - start - 2) % 3 == 0) { - twoThird--; - } - wrapper(arr, third, twoThird); - wrapper(arr, twoThird, stop); - int left = third; - int right = twoThird; - int bufferStart = start; - while (left < twoThird && right < stop) { - if (compare(arr, left, right) == 1) { - Writes.swap(arr, bufferStart, right, 1, true, false); - right++; - } else { - Writes.swap(arr, bufferStart, left, 1, true, false); - left++; - } - bufferStart++; - } - while (right < stop) { - Writes.swap(arr, bufferStart, right, 1, true, false); - right++; - bufferStart++; - } - wrapper(arr, twoThird, stop); - if (stop - start > 8) { - if (stop > twoThird && twoThird > start) { - mergeOOP(arr, start, twoThird, stop); - } - } else { - int temp; - left = twoThird - 1; - right = stop - 1; - while (right > left && left >= start) { - if (compare(arr, left, right) == 1) { - temp = arr[left]; - Writes.arraycopy(arr, left + 1, arr, left, right - left, 0.5, true, false); - Writes.write(arr, right, temp, 0.5, true, false); - left--; - } - right--; - } - } - Highlights.clearMark(2); - } - } - } - - @Override - public void runSort(int[] array, int sortLength, int bucketCount) throws Exception { - aux = Writes.createExternalArray((sortLength + 2) / 3); - wrapper(array, 0, sortLength); - Writes.deleteExternalArray(aux); - } -} diff --git a/src/sorts/merge/TimBufferedStoogeSort.java b/src/sorts/merge/TimBufferedStoogeSort.java deleted file mode 100644 index 404c99f7..00000000 --- a/src/sorts/merge/TimBufferedStoogeSort.java +++ /dev/null @@ -1,451 +0,0 @@ -package sorts.merge; - -import main.ArrayVisualizer; - -/** - * @author _fluffyy - * @author thatsOven - * @author Gaming32 - */ -public final class TimBufferedStoogeSort extends OOPBufferedStoogeSort { - int len; - int[] a, aux; - - private static final int MIN_GALLOP = 7; - private int minGallop; - - public TimBufferedStoogeSort(ArrayVisualizer arrayVisualizer) { - super(arrayVisualizer); - this.setSortListName("Tim Buffered Stooge"); - this.setRunAllSortsName("Tim Buffered Stooge Sort"); - this.setRunSortName("Tim Buffered Stoogesort"); - this.setCategory("Merge Sorts"); - this.setComparisonBased(true); - this.setBucketSort(false); - this.setRadixSort(false); - this.setUnreasonablySlow(false); - this.setUnreasonableLimit(0); - this.setBogoSort(false); - } - - private void markArray(int marker, int markPosition) { - if(markPosition >= 0 && markPosition < this.len) { - this.Highlights.markArray(marker, markPosition); - } - } - - private static int gallopLeft(TimBufferedStoogeSort ts, int key, int[] a, int base, int len, int hint) { - int lastOfs = 0; - int ofs = 1; - - ts.markArray(3, base + hint); - ts.Delays.sleep(1); - - if (ts.Reads.compareValues(key, a[base + hint]) > 0) { - // Gallop right until a[base+hint+lastOfs] < key <= a[base+hint+ofs] - int maxOfs = len - hint; - - ts.markArray(3, base + hint + ofs); - ts.Delays.sleep(1); - - while (ofs < maxOfs && ts.Reads.compareValues(key, a[base + hint + ofs]) > 0) { - lastOfs = ofs; - ofs = (ofs * 2) + 1; - if (ofs <= 0) // int overflow - ofs = maxOfs; - - ts.markArray(3, base + hint + ofs); - ts.Delays.sleep(1); - } - 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; - - ts.markArray(3, base + hint - ofs); - ts.Delays.sleep(1); - - while (ofs < maxOfs && ts.Reads.compareValues(key, a[base + hint - ofs]) <= 0) { - lastOfs = ofs; - ofs = (ofs * 2) + 1; - if (ofs <= 0) // int overflow - ofs = maxOfs; - - ts.markArray(3, base + hint - ofs); - ts.Delays.sleep(1); - } - if (ofs > maxOfs) - ofs = maxOfs; - - // Make offsets relative to base - int tmp = lastOfs; - lastOfs = hint - ofs; - ofs = hint - tmp; - } - - /* - * 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); - - ts.markArray(3, base + m); - ts.Delays.sleep(1); - - if (ts.Reads.compareValues(key, a[base + m]) > 0) - lastOfs = m + 1; // a[base + m] < key - else - ofs = m; // key <= a[base + m] - } - ts.Highlights.clearMark(3); - return ofs; - } - - private static int gallopRight(TimBufferedStoogeSort ts, int key, int[] a, int base, int len, int hint) { - int ofs = 1; - int lastOfs = 0; - - ts.markArray(3, base + hint); - ts.Delays.sleep(1); - - if (ts.Reads.compareValues(key, a[base + hint]) < 0) { - // Gallop left until a[b+hint - ofs] <= key < a[b+hint - lastOfs] - int maxOfs = hint + 1; - - ts.markArray(3, base + hint - ofs); - ts.Delays.sleep(1); - - while (ofs < maxOfs && ts.Reads.compareValues(key, a[base + hint - ofs]) < 0) { - lastOfs = ofs; - ofs = (ofs * 2) + 1; - if (ofs <= 0) // int overflow - ofs = maxOfs; - - ts.markArray(3, base + hint - ofs); - ts.Delays.sleep(1); - } - 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; - - ts.markArray(3, base + hint + ofs); - ts.Delays.sleep(1); - - while (ofs < maxOfs && ts.Reads.compareValues(key, a[base + hint + ofs]) >= 0) { - lastOfs = ofs; - ofs = (ofs * 2) + 1; - if (ofs <= 0) // int overflow - ofs = maxOfs; - - ts.markArray(3, base + hint + ofs); - ts.Delays.sleep(1); - } - if (ofs > maxOfs) - ofs = maxOfs; - - // Make offsets relative to b - lastOfs += hint; - ofs += hint; - } - - /* - * 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); - - ts.markArray(3, base + m); - ts.Delays.sleep(1); - - if (ts.Reads.compareValues(key, a[base + m]) < 0) - ofs = m; // key < a[b + m] - else - lastOfs = m + 1; // a[b + m] <= key - } - ts.Highlights.clearMark(3); - return ofs; - } - - private static void mergeLo(TimBufferedStoogeSort ts, int base1, int len1, int base2, int len2) { - // Copy first run into temp array - int[] a = ts.a; // For performance - int[] tmp = ts.aux; - ts.Writes.arraycopy(a, base1, tmp, 0, len1, 1, true, true); - - int cursor1 = 0; // Indexes into tmp array - int cursor2 = base2; // Indexes int a - int dest = base1; // Indexes int a - - // Move first element of second run and deal with degenerate cases - ts.Writes.write(a, dest++, a[cursor2++], 1, false, false); - ts.markArray(1, dest); - ts.markArray(2, cursor2); - if (--len2 == 0) { - ts.Writes.arraycopy(tmp, cursor1, a, dest, len1, 1, true, false); - return; - } - if (len1 == 1) { - ts.Writes.arraycopy(a, cursor2, a, dest, len2, 1, true, false); - ts.Writes.write(a, dest + len2, tmp[cursor1], 1, false, false); // Last elt of run 1 to end of merge - ts.markArray(1, dest + len2); - return; - } - - int minGallop = ts.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 { - if (ts.Reads.compareValues(a[cursor2], tmp[cursor1]) < 0) { - ts.Writes.write(a, dest++, a[cursor2++], 1, false, false); - ts.markArray(1, dest); - ts.markArray(2, cursor2); - count2++; - count1 = 0; - if (--len2 == 0) - break outer; - } else { - ts.Writes.write(a, dest++, tmp[cursor1++], 1, false, false); - ts.markArray(1, dest); - 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 { - count1 = gallopRight(ts, a[cursor2], tmp, cursor1, len1, 0); - if (count1 != 0) { - ts.Writes.arraycopy(tmp, cursor1, a, dest, count1, 1, true, false); - dest += count1; - cursor1 += count1; - len1 -= count1; - if (len1 <= 1) // len1 == 1 || len1 == 0 - break outer; - } - ts.Writes.write(a, dest++, a[cursor2++], 1, false, false); - ts.markArray(1, dest); - ts.markArray(2, cursor2); - if (--len2 == 0) - break outer; - - count2 = gallopLeft(ts, tmp[cursor1], a, cursor2, len2, 0); - if (count2 != 0) { - ts.Writes.arraycopy(a, cursor2, a, dest, count2, 1, true, false); - dest += count2; - cursor2 += count2; - len2 -= count2; - if (len2 == 0) - break outer; - } - ts.Writes.write(a, dest++, tmp[cursor1++], 1, false, false); - ts.markArray(1, dest); - 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 - ts.minGallop = minGallop < 1 ? 1 : minGallop; // Write back to field - - if (len1 == 1) { - ts.Writes.arraycopy(a, cursor2, a, dest, len2, 1, true, false); - ts.Writes.write(a, dest + len2, tmp[cursor1], 1, false, false); // Last elt of run 1 to end of merge - ts.markArray(1, dest + len2); - } else if (len1 == 0) { - throw new IllegalArgumentException( - "Comparison method violates its general contract!"); - } else { - ts.Writes.arraycopy(tmp, cursor1, a, dest, len1, 1, true, false); - } - } - - private static void mergeHi(TimBufferedStoogeSort ts, int base1, int len1, int base2, int len2) { - // Copy second run into temp array - int[] a = ts.a; // For performance - int[] tmp = ts.aux; - ts.Writes.arraycopy(a, base2, tmp, 0, len2, 1, true, true); - - int cursor1 = base1 + len1 - 1; // Indexes into a - int cursor2 = 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 - ts.Writes.write(a, dest--, a[cursor1--], 1, false, false); - ts.markArray(1, dest); - ts.markArray(2, cursor1); - if (--len1 == 0) { - ts.Writes.arraycopy(tmp, 0, a, dest - (len2 - 1), len2, 1, true, false); - return; - } - if (len2 == 1) { - dest -= len1; - cursor1 -= len1; - ts.Writes.arraycopy(a, cursor1 + 1, a, dest + 1, len1, 1, true, false); - ts.Writes.write(a, dest, tmp[cursor2], 1, false, false); - ts.markArray(1, dest); - return; - } - - int minGallop = ts.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 { - if (ts.Reads.compareValues(tmp[cursor2], a[cursor1]) < 0) { - ts.Writes.write(a, dest--, a[cursor1--], 1, false, false); - ts.markArray(1, dest); - ts.markArray(2, cursor1); - count1++; - count2 = 0; - if (--len1 == 0) - break outer; - } else { - ts.Writes.write(a, dest--, tmp[cursor2--], 1, false, false); - ts.markArray(1, dest); - 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 { - count1 = len1 - gallopRight(ts, tmp[cursor2], a, base1, len1, len1 - 1); - if (count1 != 0) { - dest -= count1; - cursor1 -= count1; - len1 -= count1; - ts.Writes.arraycopy(a, cursor1 + 1, a, dest + 1, count1, 1, true, false); - if (len1 == 0) - break outer; - } - ts.Writes.write(a, dest--, tmp[cursor2--], 1, false, false); - ts.markArray(1, dest); - if (--len2 == 1) - break outer; - - count2 = len2 - gallopLeft(ts, a[cursor1], tmp, 0, len2, len2 - 1); - if (count2 != 0) { - dest -= count2; - cursor2 -= count2; - len2 -= count2; - ts.Writes.arraycopy(tmp, cursor2 + 1, a, dest + 1, count2, 1, true, false); - if (len2 <= 1) // len2 == 1 || len2 == 0 - break outer; - } - ts.Writes.write(a, dest--, a[cursor1--], 1, false, false); - ts.markArray(1, dest); - ts.markArray(2, 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 - ts.minGallop = minGallop < 1 ? 1 : minGallop; // Write back to field - - if (len2 == 1) { - dest -= len1; - cursor1 -= len1; - ts.Writes.arraycopy(a, cursor1 + 1, a, dest + 1, len1, 1, true, false); - ts.Writes.write(a, dest, tmp[cursor2], 1, false, false); // Move first elt of run2 to front of merge - ts.markArray(1, dest); - } else if (len2 == 0) { - throw new IllegalArgumentException( - "Comparison method violates its general contract!"); - } else { - ts.Writes.arraycopy(tmp, 0, a, dest - (len2 - 1), len2, 1, true, false); - } - } - - @Override - protected void mergeOOP(int[] arr, int start, int mid, int end) { - this.Highlights.clearMark(1); - this.Highlights.clearMark(2); - - int base1 = start, base2 = mid, - len1 = mid - start, len2 = end - mid; - - /* - * 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(this, arr[base2], arr, base1, len1, 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(this, arr[base1 + len1 - 1], arr, base2, len2, len2 - 1); - if (len2 == 0) - return; - - // Merge remaining runs, using tmp array with min(len1, len2) elements - if (len1 <= len2) - mergeLo(this, base1, len1, base2, len2); - else - mergeHi(this, base1, len1, base2, len2); - - this.Highlights.clearMark(1); - this.Highlights.clearMark(2); - } - - @Override - public void runSort(int[] array, int sortLength, int bucketCount) throws Exception { - this.len = sortLength; - this.a = array; - minGallop = MIN_GALLOP; - aux = Writes.createExternalArray((sortLength + 2) / 3); - wrapper(array, 0, sortLength); - Writes.deleteExternalArray(aux); - } -} From c192eaee3619cbbe73246a3d5c7eef03166c3b29 Mon Sep 17 00:00:00 2001 From: "Josiah (Gaming32) Glosson" Date: Mon, 27 Dec 2021 07:26:02 -0600 Subject: [PATCH 16/23] Remember array size --- src/utils/SortingNetworkGenerator.java | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/utils/SortingNetworkGenerator.java b/src/utils/SortingNetworkGenerator.java index 5ce0c2b1..499fdf58 100644 --- a/src/utils/SortingNetworkGenerator.java +++ b/src/utils/SortingNetworkGenerator.java @@ -95,23 +95,12 @@ String getValue() { private static final int OUT_BUFFER_SIZE = 16_777_216; // 32 MB - private static int getMaxInput(Comparator[] comparators) { - int maxInput = 0; - for (Comparator c : comparators) { - if (c.i2 > maxInput) { - maxInput = c.i2; - } - } - return maxInput; - } - - private static boolean encodeNetwork0(final Comparator[] comparators, final PrintWriter out) { + private static boolean encodeNetwork0(final Comparator[] comparators, final int n, final PrintWriter out) { int scale = 1; int xScale = scale * 35; int yScale = scale * 20; boolean small = comparators.length < 500_000; - int n = getMaxInput(comparators) + 1; int h = (n + 1) * yScale; double w = xScale; Map group = new HashMap<>(); @@ -223,7 +212,7 @@ private static boolean encodeNetwork0(final Comparator[] comparators, final Prin return false; } - public static boolean encodeNetwork(Comparator[] comparators, File file) { + public static boolean encodeNetwork(Comparator[] comparators, int inputLength, File file) { try (PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter( @@ -231,7 +220,7 @@ public static boolean encodeNetwork(Comparator[] comparators, File file) { ), OUT_BUFFER_SIZE), false) ) { - boolean cancelled = encodeNetwork0(comparators, out); + boolean cancelled = encodeNetwork0(comparators, inputLength, out); if (cancelled) { JOptionPane.showMessageDialog(null, "Sorting network visualization cancelled", "Sorting Network Visualizer", JOptionPane.INFORMATION_MESSAGE); @@ -260,7 +249,7 @@ public static File encodeNetworkAndDisplay(String name, ArrayList indic indices.trimToSize(); File file = new File(SORTING_NETWORKS_DIR, "network_" + name + "_" + arrayLength + ".svg"); try { - if (!encodeNetwork(comparators, file)) { + if (!encodeNetwork(comparators, arrayLength, file)) { return null; } } catch (OutOfMemoryError e) { From 17a5340710a598cd2bb7af86643dbb871654fd31 Mon Sep 17 00:00:00 2001 From: "Josiah (Gaming32) Glosson" Date: Mon, 27 Dec 2021 07:27:01 -0600 Subject: [PATCH 17/23] Make code more consistent --- src/utils/SortingNetworkGenerator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/SortingNetworkGenerator.java b/src/utils/SortingNetworkGenerator.java index 499fdf58..3ce88dda 100644 --- a/src/utils/SortingNetworkGenerator.java +++ b/src/utils/SortingNetworkGenerator.java @@ -183,8 +183,8 @@ private static boolean encodeNetwork0(final Comparator[] comparators, final int } } - int y0 = yScale + c.i1 * yScale; - int y1 = yScale + c.i2 * yScale; + int y0 = (c.i1 + 1) * yScale; + int y1 = y0; writer.write("" + "" + ""); From 65504d261425f74867fc815cf9307a7863ab8d3e Mon Sep 17 00:00:00 2001 From: "Josiah (Gaming32) Glosson" Date: Mon, 27 Dec 2021 13:57:44 -0600 Subject: [PATCH 18/23] Change progress++ to ++progress --- src/utils/SortingNetworkGenerator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/SortingNetworkGenerator.java b/src/utils/SortingNetworkGenerator.java index 3ce88dda..bcb69104 100644 --- a/src/utils/SortingNetworkGenerator.java +++ b/src/utils/SortingNetworkGenerator.java @@ -147,7 +147,7 @@ private static boolean encodeNetwork0(final Comparator[] comparators, final int } group.put(c, cx); - if ((progress++ & 1023) == 0) { + if ((++progress & 1023) == 0) { monitor.setProgress(progress); if (monitor.isCanceled()) return true; } @@ -190,7 +190,7 @@ private static boolean encodeNetwork0(final Comparator[] comparators, final int ""); group.put(c, cx); - if ((progress++ & 1023) == 0) { + if ((++progress & 1023) == 0) { monitor.setProgress(progress); if (monitor.isCanceled()) return true; } From ac6ffaa1d04e85543d2a6ed51ad52a81dba56c9e Mon Sep 17 00:00:00 2001 From: "Josiah (Gaming32) Glosson" Date: Tue, 28 Dec 2021 06:21:55 -0600 Subject: [PATCH 19/23] Fix bug --- src/utils/SortingNetworkGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/SortingNetworkGenerator.java b/src/utils/SortingNetworkGenerator.java index bcb69104..d79337a6 100644 --- a/src/utils/SortingNetworkGenerator.java +++ b/src/utils/SortingNetworkGenerator.java @@ -184,7 +184,7 @@ private static boolean encodeNetwork0(final Comparator[] comparators, final int } int y0 = (c.i1 + 1) * yScale; - int y1 = y0; + int y1 = (c.i2 + 1) * yScale; writer.write("" + "" + ""); From 0bfb56ef5191fe9965d333460e82e06e2af99568 Mon Sep 17 00:00:00 2001 From: "Josiah (Gaming32) Glosson" Date: Tue, 28 Dec 2021 06:22:36 -0600 Subject: [PATCH 20/23] Optimize SortingNetworkGenerator.Comparator.overlaps() --- src/utils/SortingNetworkGenerator.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/utils/SortingNetworkGenerator.java b/src/utils/SortingNetworkGenerator.java index d79337a6..6d29f100 100644 --- a/src/utils/SortingNetworkGenerator.java +++ b/src/utils/SortingNetworkGenerator.java @@ -45,10 +45,7 @@ public int hashCode() { } boolean overlaps(Comparator other) { - return (this.i1 < other.i1 && other.i1 < this.i2) || - (this.i1 < other.i2 && other.i2 < this.i2) || - (other.i1 < this.i1 && this.i1 < other.i2) || - (other.i1 < this.i2 && this.i2 < other.i2); + return this.i2 > other.i1 && other.i2 > this.i1; } boolean hasSameInput(Comparator other) { From 7af0f0d1021a6574a7fc1391a21988e0d7a758b9 Mon Sep 17 00:00:00 2001 From: "Josiah (Gaming32) Glosson" Date: Tue, 28 Dec 2021 06:34:36 -0600 Subject: [PATCH 21/23] Use two Lists instead of a Map to store the group It's much faster now. --- src/utils/SortingNetworkGenerator.java | 49 ++++++++++++++++---------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/src/utils/SortingNetworkGenerator.java b/src/utils/SortingNetworkGenerator.java index 6d29f100..1a945275 100644 --- a/src/utils/SortingNetworkGenerator.java +++ b/src/utils/SortingNetworkGenerator.java @@ -8,9 +8,10 @@ import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; +import java.util.AbstractMap; import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; +import java.util.Iterator; +import java.util.List; import java.util.Map.Entry; import javax.swing.JOptionPane; @@ -100,7 +101,8 @@ private static boolean encodeNetwork0(final Comparator[] comparators, final int int h = (n + 1) * yScale; double w = xScale; - Map group = new HashMap<>(); + List groupComparators = new ArrayList<>(); + List groupPositions = new ArrayList<>(); WriterBuilderProxy writer; ProgressMonitor monitor; @@ -122,34 +124,39 @@ private static boolean encodeNetwork0(final Comparator[] comparators, final int 0, comparators.length * 2 ); for (Comparator c : comparators) { - for (Comparator other : group.keySet()) { + for (Comparator other : groupComparators) { if (c.hasSameInput(other)) { - for (double pos : group.values()) { + for (double pos : groupPositions) { if (pos > w) { w = pos; } } w += xScale; - group.clear(); + groupComparators.clear(); + groupPositions.clear(); break; } } double cx = w; - for (Entry entry : group.entrySet()) { - Comparator other = entry.getKey(); - double otherPos = entry.getValue(); + Iterator groupPositionIterator = groupPositions.iterator(); + for (Comparator other : groupComparators) { + // We don't need hasNext checks because groupPositions and + // groupComparators have the same length + double otherPos = groupPositionIterator.next(); if (otherPos >= cx && c.overlaps(other)) { cx = otherPos + xScale / 3.0; } } - group.put(c, cx); + groupComparators.add(c); + groupPositions.add(cx); if ((++progress & 1023) == 0) { monitor.setProgress(progress); if (monitor.isCanceled()) return true; } } - group.clear(); + groupComparators.clear(); + groupPositions.clear(); monitor.setNote("Writing SVG"); out.write(""); w = xScale; @@ -158,23 +165,26 @@ private static boolean encodeNetwork0(final Comparator[] comparators, final int } for (Comparator c : comparators) { - for (Comparator other : group.keySet()) { + for (Comparator other : groupComparators) { if (c.hasSameInput(other)) { - for (double pos : group.values()) { + for (double pos : groupPositions) { if (pos > w) { w = pos; } } w += xScale; - group.clear(); + groupComparators.clear(); + groupPositions.clear(); break; } } double cx = w; - for (Entry entry : group.entrySet()) { - Comparator other = entry.getKey(); - double otherPos = entry.getValue(); + Iterator groupPositionIterator = groupPositions.iterator(); + for (Comparator other : groupComparators) { + // We don't need hasNext checks because groupPositions and + // groupComparators have the same length + double otherPos = groupPositionIterator.next(); if (otherPos >= cx && c.overlaps(other)) { cx = otherPos + xScale / 3.0; } @@ -185,13 +195,16 @@ private static boolean encodeNetwork0(final Comparator[] comparators, final int writer.write("" + "" + ""); - group.put(c, cx); + groupComparators.add(c); + groupPositions.add(cx); if ((++progress & 1023) == 0) { monitor.setProgress(progress); if (monitor.isCanceled()) return true; } } + groupComparators.clear(); + groupPositions.clear(); w += xScale; for (int i = 0; i < n; i++) { From 699b6353edb1777a47848554f96c81054608b589 Mon Sep 17 00:00:00 2001 From: "Josiah (Gaming32) Glosson" Date: Tue, 28 Dec 2021 13:27:44 -0600 Subject: [PATCH 22/23] Rename some variables --- src/utils/SortingNetworkGenerator.java | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/utils/SortingNetworkGenerator.java b/src/utils/SortingNetworkGenerator.java index 1a945275..2f445e0d 100644 --- a/src/utils/SortingNetworkGenerator.java +++ b/src/utils/SortingNetworkGenerator.java @@ -8,11 +8,9 @@ import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; -import java.util.AbstractMap; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.Map.Entry; import javax.swing.JOptionPane; import javax.swing.ProgressMonitor; @@ -126,9 +124,9 @@ private static boolean encodeNetwork0(final Comparator[] comparators, final int for (Comparator c : comparators) { for (Comparator other : groupComparators) { if (c.hasSameInput(other)) { - for (double pos : groupPositions) { - if (pos > w) { - w = pos; + for (double otherX : groupPositions) { + if (otherX > w) { + w = otherX; } } w += xScale; @@ -142,9 +140,9 @@ private static boolean encodeNetwork0(final Comparator[] comparators, final int for (Comparator other : groupComparators) { // We don't need hasNext checks because groupPositions and // groupComparators have the same length - double otherPos = groupPositionIterator.next(); - if (otherPos >= cx && c.overlaps(other)) { - cx = otherPos + xScale / 3.0; + double otherX = groupPositionIterator.next(); + if (otherX >= cx && c.overlaps(other)) { + cx = otherX + xScale / 3.0; } } groupComparators.add(c); @@ -167,9 +165,9 @@ private static boolean encodeNetwork0(final Comparator[] comparators, final int for (Comparator c : comparators) { for (Comparator other : groupComparators) { if (c.hasSameInput(other)) { - for (double pos : groupPositions) { - if (pos > w) { - w = pos; + for (double otherX : groupPositions) { + if (otherX > w) { + w = otherX; } } w += xScale; @@ -184,9 +182,9 @@ private static boolean encodeNetwork0(final Comparator[] comparators, final int for (Comparator other : groupComparators) { // We don't need hasNext checks because groupPositions and // groupComparators have the same length - double otherPos = groupPositionIterator.next(); - if (otherPos >= cx && c.overlaps(other)) { - cx = otherPos + xScale / 3.0; + double otherX = groupPositionIterator.next(); + if (otherX >= cx && c.overlaps(other)) { + cx = otherX + xScale / 3.0; } } From 071add07a24f0d1d8b5851ad2cc0014c787b5cdf Mon Sep 17 00:00:00 2001 From: "Josiah (Gaming32) Glosson" Date: Tue, 28 Dec 2021 13:29:47 -0600 Subject: [PATCH 23/23] Remove doubles --- src/utils/SortingNetworkGenerator.java | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/utils/SortingNetworkGenerator.java b/src/utils/SortingNetworkGenerator.java index 2f445e0d..02e7590e 100644 --- a/src/utils/SortingNetworkGenerator.java +++ b/src/utils/SortingNetworkGenerator.java @@ -93,14 +93,14 @@ String getValue() { private static boolean encodeNetwork0(final Comparator[] comparators, final int n, final PrintWriter out) { int scale = 1; - int xScale = scale * 35; + int xScale = scale * 36; int yScale = scale * 20; boolean small = comparators.length < 500_000; int h = (n + 1) * yScale; - double w = xScale; + int w = xScale; List groupComparators = new ArrayList<>(); - List groupPositions = new ArrayList<>(); + List groupPositions = new ArrayList<>(); WriterBuilderProxy writer; ProgressMonitor monitor; @@ -124,7 +124,7 @@ private static boolean encodeNetwork0(final Comparator[] comparators, final int for (Comparator c : comparators) { for (Comparator other : groupComparators) { if (c.hasSameInput(other)) { - for (double otherX : groupPositions) { + for (int otherX : groupPositions) { if (otherX > w) { w = otherX; } @@ -135,14 +135,14 @@ private static boolean encodeNetwork0(final Comparator[] comparators, final int break; } } - double cx = w; - Iterator groupPositionIterator = groupPositions.iterator(); + int cx = w; + Iterator groupPositionIterator = groupPositions.iterator(); for (Comparator other : groupComparators) { // We don't need hasNext checks because groupPositions and // groupComparators have the same length - double otherX = groupPositionIterator.next(); + int otherX = groupPositionIterator.next(); if (otherX >= cx && c.overlaps(other)) { - cx = otherX + xScale / 3.0; + cx = otherX + xScale / 3; } } groupComparators.add(c); @@ -165,7 +165,7 @@ private static boolean encodeNetwork0(final Comparator[] comparators, final int for (Comparator c : comparators) { for (Comparator other : groupComparators) { if (c.hasSameInput(other)) { - for (double otherX : groupPositions) { + for (int otherX : groupPositions) { if (otherX > w) { w = otherX; } @@ -177,14 +177,14 @@ private static boolean encodeNetwork0(final Comparator[] comparators, final int } } - double cx = w; - Iterator groupPositionIterator = groupPositions.iterator(); + int cx = w; + Iterator groupPositionIterator = groupPositions.iterator(); for (Comparator other : groupComparators) { // We don't need hasNext checks because groupPositions and // groupComparators have the same length - double otherX = groupPositionIterator.next(); + int otherX = groupPositionIterator.next(); if (otherX >= cx && c.overlaps(other)) { - cx = otherX + xScale / 3.0; + cx = otherX + xScale / 3; } }