From 462f6bc2c03b5427e5fd786683aaaed9b77b807d Mon Sep 17 00:00:00 2001 From: Andrew Lawson Date: Fri, 28 Nov 2014 21:53:11 -0500 Subject: [PATCH 01/11] Middle of working on DP distance problem. --- geometric_separators.pde | 94 ++++++++++++++++++++++++++++++---------- 1 file changed, 70 insertions(+), 24 deletions(-) diff --git a/geometric_separators.pde b/geometric_separators.pde index 169c56f..f408aa7 100644 --- a/geometric_separators.pde +++ b/geometric_separators.pde @@ -1,3 +1,5 @@ +import java.util.*; + // Reset button coordinates int reset_x = 140; int reset_y = 460; @@ -11,9 +13,11 @@ int calc_h = 25; // Button Shapes PShape reset; PShape calculate; -// Input list +// Input lists ArrayList input = new ArrayList(); - +ArrayList inputX, inputY; +// Misc +Comparator pointComparator; // Setup void setup() { background(255); @@ -22,24 +26,47 @@ void setup() { reset = createShape(RECT, reset_x, reset_y, reset_w, reset_h); calculate = createShape(RECT, calc_x, calc_y, calc_w, calc_h); noLoop(); + // Define new comparator + pointComparator = new Comparator() { + public int compare(Float p1, Float p2) { + if (p1 < p2) { + return -1; + } + else if (p2 < p1) { + return 1; + } + else { + return 0; + } + } + }; } // On mouse press void mousePressed() { // If mouse presses reset button if ((mouseX >= reset_x && mouseX <= (reset_x + reset_w)) && - (mouseY >= reset_y && mouseY <= (reset_y + reset_h))) { - // Reset input and background - input.clear(); + (mouseY >= reset_y && mouseY <= (reset_y + reset_h))) { + // Reset input and background + input.clear(); } // If mouse presses calculate button - else if ((mouseX >= reset_x && mouseX <= (reset_x + reset_w)) && - (mouseY >= reset_y && mouseY <= (reset_y + reset_h))) { - // Get sorted input points + else if ((mouseX >= calc_x && mouseX <= (calc_x + calc_w)) && + (mouseY >= calc_y && mouseY <= (calc_y + calc_h))) { + // Build component lists + inputX = new ArrayList(); + inputY = new ArrayList(); + for (PVector point : input) { + inputX.add(point.x); + inputY.add(point.y); + } + // Sort lists + Collections.sort(inputX, pointComparator); + Collections.sort(inputY, pointComparator); } else { - PVector new_point = new PVector(mouseX, mouseY); - input.add(new_point); + PVector new_point = new PVector(mouseX, mouseY); + input.add(new_point); } redraw(); } @@ -47,26 +74,45 @@ void mousePressed() { // Estimate centerpoint void approxCenter(ArrayList input) { if (input.size() == 1) { - // Do nothing + // Do nothing } else { - // Sample points - + // Do nothing } } // Estimate the geometric median - dynamic programming void geomMedian() { // Memoization hash tables - HashMap left = new HashMap(); - HashMap right = new HashMap(); - HashMap up = new HashMap(); - HashMap down = new HashMap(); - // Sum of squares values - ArrayList leftSq = new ArrayList(); - ArrayList rightSq = new ArrayList(); - ArrayList upSq = new ArrayList(); - ArrayList downSq = new ArrayList(); + HashMap xMemoize = new HashMap(); + HashMap yMemoize = new HashMap(); + // Calculate for x-axis + // For each point + for (int i = 0; i < inputX.size(); i++) { + float currentPoint = inputX.get(i); + ArrayList leftSquares = new ArrayList(); + ArrayList rightSquares = new ArrayList(); + ArrayList upSquares = new ArrayList(); + ArrayList downSquares = new ArrayList(); + // Get distance to every previous point + } +} + +// Calculate the distance with the input, memoization +void calcDist(float point, ArrayList input, HashMap memoize) { + if (memoize.contains(currentPoint)) { + // Reuse solution + return memoize.get(currentPoint); + } + else { + int dist = point - prevPoint; + for (int j = 0; j < i; j++) { + float prevPoint = input.get(j); + sum += currentPoint - prevPoint; + } + memoize.put(currentPoint, sum); + return sum; + } } // Draw @@ -78,7 +124,7 @@ void draw() { text("Reset.", reset_x + 30, reset_y + 15); text("Calculate.", calc_x + 25, calc_y + 15); for (PVector point : input) { - strokeWeight(4); - point(point.x, point.y); + strokeWeight(4); + point(point.x, point.y); } } From 2f04f364bf99a258409f22561ab002a57e8f7739 Mon Sep 17 00:00:00 2001 From: Andrew Lawson Date: Sat, 29 Nov 2014 23:08:49 -0500 Subject: [PATCH 02/11] In the middle of implementing radon points == geometric median. --- geometric_separators.pde | 64 +++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 20 deletions(-) diff --git a/geometric_separators.pde b/geometric_separators.pde index f408aa7..bc64044 100644 --- a/geometric_separators.pde +++ b/geometric_separators.pde @@ -83,36 +83,60 @@ void approxCenter(ArrayList input) { // Estimate the geometric median - dynamic programming void geomMedian() { - // Memoization hash tables - HashMap xMemoize = new HashMap(); - HashMap yMemoize = new HashMap(); - // Calculate for x-axis - // For each point - for (int i = 0; i < inputX.size(); i++) { - float currentPoint = inputX.get(i); - ArrayList leftSquares = new ArrayList(); - ArrayList rightSquares = new ArrayList(); - ArrayList upSquares = new ArrayList(); - ArrayList downSquares = new ArrayList(); - // Get distance to every previous point - } + // Nothing yet } // Calculate the distance with the input, memoization -void calcDist(float point, ArrayList input, HashMap memoize) { - if (memoize.contains(currentPoint)) { - // Reuse solution - return memoize.get(currentPoint); - } - else { +float calcDist(float point, ArrayList input) { int dist = point - prevPoint; + // For each point before i, calculate distance to i for (int j = 0; j < i; j++) { float prevPoint = input.get(j); sum += currentPoint - prevPoint; } - memoize.put(currentPoint, sum); return sum; +} + +// Calculate last sum and its distance from i +float calcLastSum(int i, ArrayList input, HashMap memoize) { + // Calculate for squares + float sum; + // If possible, reuse solution + if (memoize.contains(i)) { + sum = memoize.get(i); + } + // Otherwise, calculate + else { + sum = calcDist(currentPoint, input); + } + float currentPoint = input.get(i); + float nextPoint = input.get(i + 1); + float dist = nextPoint - currentPoint; + return sum, dist; +} + +// Get sums and sums of squares of distances for an input +float getSums(ArrayList input) { + // Memoization hash tables + HashMap sumMemoize = new HashMap(); + HashMap sumSquaresMemoize = new HashMap(); + for (int i = 0; i < input.size() - 1; i++) { + float sum, dist; + // Calculate sum + sum, dist = calcLastSum(i, input, sumMemoize); + sumMemoize.put(i + 1, sum + (i * dist)); + // Calculate sum of squares + sum, dist = calcLastSum(i, input, sumSquaresMemoize); + sumSquaresMemoize.put(i + 1, sum + (i * Math.pow(d, 2)) + (2 * i * dist)); + } + // Sum results for input + float sum = 0; + float sumSquares = 0; + for (int i = 0; i < input.size(); i++) { + sum += sumMemoize.get(i); + sumSquares += sumSquaresMemoize.get(i); } + return sum, sumSquares; } // Draw From db94974bfabf77d3981a8c3a8cb01874fdfc4c72 Mon Sep 17 00:00:00 2001 From: Andrew Lawson Date: Sat, 29 Nov 2014 23:57:17 -0500 Subject: [PATCH 03/11] Almost finished framework for geometric median - need to map minimum point back to original vector. --- geometric_separators.pde | 83 ++++++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 34 deletions(-) diff --git a/geometric_separators.pde b/geometric_separators.pde index bc64044..f6cd7b2 100644 --- a/geometric_separators.pde +++ b/geometric_separators.pde @@ -1,24 +1,21 @@ import java.util.*; -// Reset button coordinates int reset_x = 140; int reset_y = 460; int reset_w = 100; int reset_h = 25; -// Calculate button coordinates + int calc_x = 250; int calc_y = 460; int calc_w = 100; int calc_h = 25; -// Button Shapes + PShape reset; PShape calculate; -// Input lists -ArrayList input = new ArrayList(); +ArrayList rawInput = new ArrayList(); ArrayList inputX, inputY; -// Misc -Comparator pointComparator; -// Setup +Comparator pointComp, pointCompReverse; + void setup() { background(255); size(500,500,P2D); @@ -27,7 +24,7 @@ void setup() { calculate = createShape(RECT, calc_x, calc_y, calc_w, calc_h); noLoop(); // Define new comparator - pointComparator = new Comparator() { + pointComp = new Comparator() { public int compare(Float p1, Float p2) { if (p1 < p2) { return -1; @@ -40,6 +37,19 @@ void setup() { } } }; + pointCompReverse = new Comparator() { + public int compare(Float p1, Float p2) { + if (p1 > p2) { + return -1; + } + else if (p2 > p1) { + return 1; + } + else { + return 0; + } + } + }; } // On mouse press @@ -48,7 +58,7 @@ void mousePressed() { if ((mouseX >= reset_x && mouseX <= (reset_x + reset_w)) && (mouseY >= reset_y && mouseY <= (reset_y + reset_h))) { // Reset input and background - input.clear(); + rawInput.clear(); } // If mouse presses calculate button else if ((mouseX >= calc_x && mouseX <= (calc_x + calc_w)) && @@ -56,17 +66,14 @@ void mousePressed() { // Build component lists inputX = new ArrayList(); inputY = new ArrayList(); - for (PVector point : input) { + for (PVector point : rawInput) { inputX.add(point.x); inputY.add(point.y); - } - // Sort lists - Collections.sort(inputX, pointComparator); - Collections.sort(inputY, pointComparator); + } } else { - PVector new_point = new PVector(mouseX, mouseY); - input.add(new_point); + PVector new_point = new PVector(mouseX, mouseY); + rawInput.add(new_point); } redraw(); } @@ -83,18 +90,18 @@ void approxCenter(ArrayList input) { // Estimate the geometric median - dynamic programming void geomMedian() { - // Nothing yet + } // Calculate the distance with the input, memoization float calcDist(float point, ArrayList input) { - int dist = point - prevPoint; - // For each point before i, calculate distance to i - for (int j = 0; j < i; j++) { - float prevPoint = input.get(j); - sum += currentPoint - prevPoint; - } - return sum; + int dist = point - prevPoint; + // For each point before i, calculate distance to i + for (int j = 0; j < i; j++) { + float prevPoint = input.get(j); + sum += currentPoint - prevPoint; + } + return sum; } // Calculate last sum and its distance from i @@ -129,14 +136,22 @@ float getSums(ArrayList input) { sum, dist = calcLastSum(i, input, sumSquaresMemoize); sumSquaresMemoize.put(i + 1, sum + (i * Math.pow(d, 2)) + (2 * i * dist)); } - // Sum results for input - float sum = 0; - float sumSquares = 0; - for (int i = 0; i < input.size(); i++) { - sum += sumMemoize.get(i); - sumSquares += sumSquaresMemoize.get(i); + return sumSquaresMemoize; +} + +// Get minimum point for given axis input +float getAxisMin(ArrayList input) { + ArrayList totalSumSquares; + HashMap sumSquaresOne, sumSquaresTwo; + Collections.sort(input, pointComp); + sumSquaresOne = getSums(input); + Collections.sort(input, pointCompReverse); + sumSquaresTwo = getSums(input); + // Calculate total sum and store it + for (int i = 0; i < sumSquaresOne.size(); i++) { + totalSumSquares.add(i, sumSquaresOne.get(i) + sumSquaresTwo.get(i)); } - return sum, sumSquares; + return Collections.min(totalSumSquares); } // Draw @@ -148,7 +163,7 @@ void draw() { text("Reset.", reset_x + 30, reset_y + 15); text("Calculate.", calc_x + 25, calc_y + 15); for (PVector point : input) { - strokeWeight(4); - point(point.x, point.y); + strokeWeight(4); + point(point.x, point.y); } } From 025ce2e6b7a2d23d39163d893dd5223188108a8e Mon Sep 17 00:00:00 2001 From: Andrew Lawson Date: Sun, 30 Nov 2014 15:25:41 -0500 Subject: [PATCH 04/11] Basic framework is completed. Has some bugs that need to be ironed out. --- geometric_separators.pde | 230 ++++++++++++++++++++++++++++----------- 1 file changed, 169 insertions(+), 61 deletions(-) diff --git a/geometric_separators.pde b/geometric_separators.pde index f6cd7b2..698a049 100644 --- a/geometric_separators.pde +++ b/geometric_separators.pde @@ -1,4 +1,6 @@ import java.util.*; +import java.util.Map.*; +import java.lang.Boolean; int reset_x = 140; int reset_y = 460; @@ -12,10 +14,23 @@ int calc_h = 25; PShape reset; PShape calculate; +PVector centerPoint; ArrayList rawInput = new ArrayList(); -ArrayList inputX, inputY; -Comparator pointComp, pointCompReverse; +Comparator compareX, compareXRev, compareY, compareYRev; +// Triple used for returning three items +private class ReturnTriple { + public float sum; + public float dist; + public HashMap memoize; + public ReturnTriple(float sum, float dist, HashMap memoize) { + this.sum = sum; + this.dist = dist; + this.memoize = memoize; + } +} + +// Setup void setup() { background(255); size(500,500,P2D); @@ -23,13 +38,25 @@ void setup() { reset = createShape(RECT, reset_x, reset_y, reset_w, reset_h); calculate = createShape(RECT, calc_x, calc_y, calc_w, calc_h); noLoop(); - // Define new comparator - pointComp = new Comparator() { - public int compare(Float p1, Float p2) { - if (p1 < p2) { + compareX = new Comparator() { + public int compare(PVector p1, PVector p2) { + if (p1.x < p2.x) { + return -1; + } + else if (p2.x < p1.x) { + return 1; + } + else { + return 0; + } + } + }; + compareXRev = new Comparator() { + public int compare(PVector p1, PVector p2) { + if (p1.x > p2.x) { return -1; } - else if (p2 < p1) { + else if (p2.x > p1.x) { return 1; } else { @@ -37,12 +64,25 @@ void setup() { } } }; - pointCompReverse = new Comparator() { - public int compare(Float p1, Float p2) { - if (p1 > p2) { + compareY = new Comparator() { + public int compare(PVector p1, PVector p2) { + if (p1.y < p2.y) { return -1; } - else if (p2 > p1) { + else if (p2.y < p1.y) { + return 1; + } + else { + return 0; + } + } + }; + compareYRev = new Comparator() { + public int compare(PVector p1, PVector p2) { + if (p1.y > p2.y) { + return -1; + } + else if (p2.y > p1.y) { return 1; } else { @@ -57,19 +97,19 @@ void mousePressed() { // If mouse presses reset button if ((mouseX >= reset_x && mouseX <= (reset_x + reset_w)) && (mouseY >= reset_y && mouseY <= (reset_y + reset_h))) { - // Reset input and background - rawInput.clear(); + // Reset input and background + rawInput.clear(); + centerPoint = null; } // If mouse presses calculate button else if ((mouseX >= calc_x && mouseX <= (calc_x + calc_w)) && (mouseY >= calc_y && mouseY <= (calc_y + calc_h))) { - // Build component lists - inputX = new ArrayList(); - inputY = new ArrayList(); - for (PVector point : rawInput) { - inputX.add(point.x); - inputY.add(point.y); - } + // Run algorithm + centerPoint = approxCenterpoint(rawInput); + if (centerPoint != null) { + System.out.println("x-coordinate: " + Float.toString(centerPoint.x)); + System.out.println("y-coordinate: " + Float.toString(centerPoint.y)); + } } else { PVector new_point = new PVector(mouseX, mouseY); @@ -78,80 +118,138 @@ void mousePressed() { redraw(); } -// Estimate centerpoint -void approxCenter(ArrayList input) { - if (input.size() == 1) { - // Do nothing +// Get geometric median +PVector getGeometricMedian(ArrayList input) { + if (input.size() == 0) { + return null; + } + else if (input.size() == 1) { + return input.get(0); } else { - // Do nothing + // Get the point + float x = getAxisMin(input, false); + float y = getAxisMin(input, true); + return new PVector(x, y); } } -// Estimate the geometric median - dynamic programming -void geomMedian() { - +// Approximate the centerpoint +PVector approxCenterpoint(ArrayList input) { + PVector point = getGeometricMedian(input); + if (point == null) { + System.out.println("You don't have any input points!"); + return null; + } + else { + return point; + } } // Calculate the distance with the input, memoization -float calcDist(float point, ArrayList input) { - int dist = point - prevPoint; +float calcDist(int i, PVector currentPoint, ArrayList input, boolean isY) { // For each point before i, calculate distance to i + PVector prevPoint; + float sum = 0; for (int j = 0; j < i; j++) { - float prevPoint = input.get(j); - sum += currentPoint - prevPoint; + prevPoint = input.get(j); + if (isY) { + sum += currentPoint.y - prevPoint.y; + } + else { + sum += currentPoint.x - prevPoint.x; + } } return sum; } -// Calculate last sum and its distance from i -float calcLastSum(int i, ArrayList input, HashMap memoize) { +// Calculate prev sum (i - 1) and the point distance from i +ReturnTriple calcLastSum(int i, PVector currentPoint, PVector nextPoint, ArrayList input, HashMap memoize, boolean isY) { // Calculate for squares - float sum; + float sum, dist; // If possible, reuse solution - if (memoize.contains(i)) { - sum = memoize.get(i); + if (memoize.containsKey(currentPoint)) { + sum = memoize.get(currentPoint); } // Otherwise, calculate else { - sum = calcDist(currentPoint, input); + sum = calcDist(i, currentPoint, input, isY); + memoize.put(currentPoint, sum); + } + if (isY) { + dist = nextPoint.y - currentPoint.y; } - float currentPoint = input.get(i); - float nextPoint = input.get(i + 1); - float dist = nextPoint - currentPoint; - return sum, dist; + else { + dist = nextPoint.x - currentPoint.x; + } + return new ReturnTriple(sum, dist, memoize); } // Get sums and sums of squares of distances for an input -float getSums(ArrayList input) { +HashMap getSums(ArrayList input, boolean isY) { // Memoization hash tables - HashMap sumMemoize = new HashMap(); - HashMap sumSquaresMemoize = new HashMap(); + HashMap sumMemoize = new HashMap(); + HashMap sumSquaresMemoize = new HashMap(); + ReturnTriple returnTriple = new ReturnTriple(0, 0, null); + PVector currentPoint, nextPoint; + float sum, dist; for (int i = 0; i < input.size() - 1; i++) { - float sum, dist; + currentPoint = input.get(i); + nextPoint = input.get(i + 1); // Calculate sum - sum, dist = calcLastSum(i, input, sumMemoize); - sumMemoize.put(i + 1, sum + (i * dist)); + returnTriple = calcLastSum(i, currentPoint, nextPoint, input, sumMemoize, isY); + sumMemoize = returnTriple.memoize; + sumMemoize.put(nextPoint, returnTriple.sum + (i * returnTriple.dist)); // Calculate sum of squares - sum, dist = calcLastSum(i, input, sumSquaresMemoize); - sumSquaresMemoize.put(i + 1, sum + (i * Math.pow(d, 2)) + (2 * i * dist)); + returnTriple = calcLastSum(i, currentPoint, nextPoint, input, sumSquaresMemoize, isY); + sumSquaresMemoize = returnTriple.memoize; + sumSquaresMemoize.put(nextPoint, returnTriple.sum + (float)(i * Math.pow(returnTriple.dist, 2)) + (2 * i * returnTriple.dist)); } + System.out.println("Printing dict..."); + System.out.println(sumSquaresMemoize); return sumSquaresMemoize; } // Get minimum point for given axis input -float getAxisMin(ArrayList input) { - ArrayList totalSumSquares; - HashMap sumSquaresOne, sumSquaresTwo; - Collections.sort(input, pointComp); - sumSquaresOne = getSums(input); - Collections.sort(input, pointCompReverse); - sumSquaresTwo = getSums(input); +Float getAxisMin(ArrayList input, boolean isY) { + HashMap sumSquaresLeft, sumSquaresRight; + HashMap totalSumSquares = new HashMap(); + // Get left distances + if (isY) { + Collections.sort(input, compareY); + } + else { + Collections.sort(input, compareX); + } + sumSquaresLeft = getSums(input, isY); + System.out.println(sumSquaresLeft); + // Get right distances + if (isY) { + Collections.sort(input, compareYRev); + } + else { + Collections.sort(input, compareXRev); + } + sumSquaresRight = getSums(input, isY); + System.out.println(sumSquaresRight); // Calculate total sum and store it - for (int i = 0; i < sumSquaresOne.size(); i++) { - totalSumSquares.add(i, sumSquaresOne.get(i) + sumSquaresTwo.get(i)); + for (int i = 0; i < sumSquaresLeft.size(); i++) { + PVector point = input.get(i); + totalSumSquares.put(point, sumSquaresLeft.get(point) + sumSquaresRight.get(point)); + } + ArrayList> sortedList = new ArrayList>(totalSumSquares.entrySet()); + Collections.sort(sortedList, new Comparator>() { + public int compare(Entry entry1, Entry entry2) { + return (int)(entry1.getValue() - entry2.getValue()); + } + }); + // Return final point coordinate + if (isY) { + return sortedList.get(0).getKey().y; + } + else { + return sortedList.get(0).getKey().x; } - return Collections.min(totalSumSquares); } // Draw @@ -160,10 +258,20 @@ void draw() { shape(reset); shape(calculate); fill(50); + textSize(20); + text("Geometric Separators", 140, 20); + textSize(12); text("Reset.", reset_x + 30, reset_y + 15); text("Calculate.", calc_x + 25, calc_y + 15); - for (PVector point : input) { + // Draw input + for (PVector point : rawInput) { strokeWeight(4); point(point.x, point.y); } + // Draw center point + if (centerPoint != null) { + strokeWeight(6); + fill (255, 0, 0); + point(centerPoint.x, centerPoint.y); + } } From 893c6ce8bc306a6f50179651e346bb68264941e0 Mon Sep 17 00:00:00 2001 From: Andrew Lawson Date: Sun, 30 Nov 2014 16:41:57 -0500 Subject: [PATCH 05/11] Added remainder of centerpoint algorithm. --- geometric_separators.pde | 45 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/geometric_separators.pde b/geometric_separators.pde index 698a049..b79ba99 100644 --- a/geometric_separators.pde +++ b/geometric_separators.pde @@ -134,15 +134,52 @@ PVector getGeometricMedian(ArrayList input) { } } +// Sample input points into sets of 4 +ArrayList> samplePoints(ArrayList input) { + ArrayList setList = new ArrayList>(); + Set pointSet = new Set(); + // While there are still points, split into sets + while (input.size() > 0) { + int rnd = new Random().nextInt(); + int index = (rnd * (input.size())); + // Add to set + pointSet.add(input.get(index)); + // Create new set on max size + if (pointSet.size() == 4) { + setList.add(pointSet); + pointSet = new Set(); + } + } + // Add most recent unempty set to list + if (pointSet.size() > 0) { + setList.add(pointSet) + } + return setList; +} + // Approximate the centerpoint PVector approxCenterpoint(ArrayList input) { - PVector point = getGeometricMedian(input); - if (point == null) { + if (input.size() == 0) { System.out.println("You don't have any input points!"); - return null; } else { - return point; + // Algorithm + // Repeat 1 - 3 until one point remains and return that point + while (input.size > 1) { + // 1. Sample points into groups of 4 + ArrayList> setList = samplePoints(input); + // 2. Compute radon point of each group (geometric median) + ArrayList radonList = new ArrayList(); + for (Set set : setList) { + PVector radonPoint = getGeometricMedian(input); + else { + radonList.add(radonPoint); + } + // 3. Set input to be new radon points + input = radonList; + } + } + return input.get(0); } } From c4d6a486a799bc6cc4f8d26bd4c75d3fa119db28 Mon Sep 17 00:00:00 2001 From: Andrew Lawson Date: Sun, 30 Nov 2014 16:41:57 -0500 Subject: [PATCH 06/11] Added remainder of centerpoint algorithm. --- geometric_separators.pde | 45 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/geometric_separators.pde b/geometric_separators.pde index 698a049..b79ba99 100644 --- a/geometric_separators.pde +++ b/geometric_separators.pde @@ -134,15 +134,52 @@ PVector getGeometricMedian(ArrayList input) { } } +// Sample input points into sets of 4 +ArrayList> samplePoints(ArrayList input) { + ArrayList setList = new ArrayList>(); + Set pointSet = new Set(); + // While there are still points, split into sets + while (input.size() > 0) { + int rnd = new Random().nextInt(); + int index = (rnd * (input.size())); + // Add to set + pointSet.add(input.get(index)); + // Create new set on max size + if (pointSet.size() == 4) { + setList.add(pointSet); + pointSet = new Set(); + } + } + // Add most recent unempty set to list + if (pointSet.size() > 0) { + setList.add(pointSet) + } + return setList; +} + // Approximate the centerpoint PVector approxCenterpoint(ArrayList input) { - PVector point = getGeometricMedian(input); - if (point == null) { + if (input.size() == 0) { System.out.println("You don't have any input points!"); - return null; } else { - return point; + // Algorithm + // Repeat 1 - 3 until one point remains and return that point + while (input.size > 1) { + // 1. Sample points into groups of 4 + ArrayList> setList = samplePoints(input); + // 2. Compute radon point of each group (geometric median) + ArrayList radonList = new ArrayList(); + for (Set set : setList) { + PVector radonPoint = getGeometricMedian(input); + else { + radonList.add(radonPoint); + } + // 3. Set input to be new radon points + input = radonList; + } + } + return input.get(0); } } From 26a52593f61b9c9b331f8dfd68f153abfa372661 Mon Sep 17 00:00:00 2001 From: Andrew Lawson Date: Sun, 30 Nov 2014 17:17:08 -0500 Subject: [PATCH 07/11] Fixed some bugs. --- geometric_separators.pde | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/geometric_separators.pde b/geometric_separators.pde index b79ba99..2759947 100644 --- a/geometric_separators.pde +++ b/geometric_separators.pde @@ -120,6 +120,7 @@ void mousePressed() { // Get geometric median PVector getGeometricMedian(ArrayList input) { + System.out.println("Geometric median..."); if (input.size() == 0) { return null; } @@ -135,24 +136,25 @@ PVector getGeometricMedian(ArrayList input) { } // Sample input points into sets of 4 -ArrayList> samplePoints(ArrayList input) { - ArrayList setList = new ArrayList>(); - Set pointSet = new Set(); +ArrayList> samplePoints(ArrayList input) { + ArrayList> setList = new ArrayList>(); + HashSet pointSet = new HashSet(); // While there are still points, split into sets - while (input.size() > 0) { - int rnd = new Random().nextInt(); - int index = (rnd * (input.size())); + while (input.size() > 1) { + System.out.println("Sampling..."); + double rnd = new Random().nextDouble(); + int index = (int)(rnd * 10) % input.size(); // Add to set pointSet.add(input.get(index)); // Create new set on max size if (pointSet.size() == 4) { setList.add(pointSet); - pointSet = new Set(); + pointSet = new HashSet(); } } // Add most recent unempty set to list if (pointSet.size() > 0) { - setList.add(pointSet) + setList.add(pointSet); } return setList; } @@ -161,23 +163,22 @@ ArrayList> samplePoints(ArrayList input) { PVector approxCenterpoint(ArrayList input) { if (input.size() == 0) { System.out.println("You don't have any input points!"); + return null; } else { // Algorithm // Repeat 1 - 3 until one point remains and return that point - while (input.size > 1) { + while (input.size() > 1) { // 1. Sample points into groups of 4 - ArrayList> setList = samplePoints(input); + ArrayList> setList = samplePoints(input); // 2. Compute radon point of each group (geometric median) ArrayList radonList = new ArrayList(); - for (Set set : setList) { + for (HashSet set : setList) { PVector radonPoint = getGeometricMedian(input); - else { - radonList.add(radonPoint); - } + radonList.add(radonPoint); // 3. Set input to be new radon points - input = radonList; } + input = radonList; } return input.get(0); } From a063b77934ed2a6e978319b5d0910b3afebe7b87 Mon Sep 17 00:00:00 2001 From: Andrew Lawson Date: Mon, 1 Dec 2014 00:48:07 -0500 Subject: [PATCH 08/11] Squashed bugs. Algorithm runs successfully - centerpoint approx. is incorrect, needs some fixes. --- geometric_separators.pde | 67 +++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 36 deletions(-) diff --git a/geometric_separators.pde b/geometric_separators.pde index 2759947..df2b97a 100644 --- a/geometric_separators.pde +++ b/geometric_separators.pde @@ -104,12 +104,12 @@ void mousePressed() { // If mouse presses calculate button else if ((mouseX >= calc_x && mouseX <= (calc_x + calc_w)) && (mouseY >= calc_y && mouseY <= (calc_y + calc_h))) { - // Run algorithm - centerPoint = approxCenterpoint(rawInput); - if (centerPoint != null) { - System.out.println("x-coordinate: " + Float.toString(centerPoint.x)); - System.out.println("y-coordinate: " + Float.toString(centerPoint.y)); - } + // Run algorithm + centerPoint = approxCenterpoint(rawInput); + if (centerPoint != null) { + System.out.println("x-coordinate: " + Float.toString(centerPoint.x)); + System.out.println("y-coordinate: " + Float.toString(centerPoint.y)); + } } else { PVector new_point = new PVector(mouseX, mouseY); @@ -120,41 +120,41 @@ void mousePressed() { // Get geometric median PVector getGeometricMedian(ArrayList input) { - System.out.println("Geometric median..."); if (input.size() == 0) { + System.out.println("You don't have any input points!"); return null; } - else if (input.size() == 1) { + else if (input.size() == 1) { return input.get(0); - } - else { - // Get the point - float x = getAxisMin(input, false); - float y = getAxisMin(input, true); - return new PVector(x, y); + } + else { + // Get the point + float x = getAxisMin(input, false); + float y = getAxisMin(input, true); + return new PVector(x, y); } } // Sample input points into sets of 4 -ArrayList> samplePoints(ArrayList input) { - ArrayList> setList = new ArrayList>(); - HashSet pointSet = new HashSet(); +ArrayList> samplePoints(ArrayList input) { + ArrayList> setList = new ArrayList>(); + ArrayList pointList = new ArrayList(); // While there are still points, split into sets - while (input.size() > 1) { - System.out.println("Sampling..."); + while (input.size() > 0) { double rnd = new Random().nextDouble(); int index = (int)(rnd * 10) % input.size(); // Add to set - pointSet.add(input.get(index)); + pointList.add(input.get(index)); + input.remove(index); // Create new set on max size - if (pointSet.size() == 4) { - setList.add(pointSet); - pointSet = new HashSet(); + if (pointList.size() == 4) { + setList.add(pointList); + pointList = new ArrayList(); } } // Add most recent unempty set to list - if (pointSet.size() > 0) { - setList.add(pointSet); + if (pointList.size() > 0) { + setList.add(pointList); } return setList; } @@ -170,11 +170,11 @@ PVector approxCenterpoint(ArrayList input) { // Repeat 1 - 3 until one point remains and return that point while (input.size() > 1) { // 1. Sample points into groups of 4 - ArrayList> setList = samplePoints(input); + ArrayList> setList = samplePoints(input); // 2. Compute radon point of each group (geometric median) ArrayList radonList = new ArrayList(); - for (HashSet set : setList) { - PVector radonPoint = getGeometricMedian(input); + for (ArrayList list : setList) { + PVector radonPoint = getGeometricMedian(list); radonList.add(radonPoint); // 3. Set input to be new radon points } @@ -230,7 +230,7 @@ HashMap getSums(ArrayList input, boolean isY) { HashMap sumSquaresMemoize = new HashMap(); ReturnTriple returnTriple = new ReturnTriple(0, 0, null); PVector currentPoint, nextPoint; - float sum, dist; + float sum, dist; for (int i = 0; i < input.size() - 1; i++) { currentPoint = input.get(i); nextPoint = input.get(i + 1); @@ -243,8 +243,6 @@ HashMap getSums(ArrayList input, boolean isY) { sumSquaresMemoize = returnTriple.memoize; sumSquaresMemoize.put(nextPoint, returnTriple.sum + (float)(i * Math.pow(returnTriple.dist, 2)) + (2 * i * returnTriple.dist)); } - System.out.println("Printing dict..."); - System.out.println(sumSquaresMemoize); return sumSquaresMemoize; } @@ -260,7 +258,6 @@ Float getAxisMin(ArrayList input, boolean isY) { Collections.sort(input, compareX); } sumSquaresLeft = getSums(input, isY); - System.out.println(sumSquaresLeft); // Get right distances if (isY) { Collections.sort(input, compareYRev); @@ -269,7 +266,6 @@ Float getAxisMin(ArrayList input, boolean isY) { Collections.sort(input, compareXRev); } sumSquaresRight = getSums(input, isY); - System.out.println(sumSquaresRight); // Calculate total sum and store it for (int i = 0; i < sumSquaresLeft.size(); i++) { PVector point = input.get(i); @@ -308,8 +304,7 @@ void draw() { } // Draw center point if (centerPoint != null) { - strokeWeight(6); - fill (255, 0, 0); - point(centerPoint.x, centerPoint.y); + strokeWeight(6); + point(centerPoint.x, centerPoint.y); } } From 24e228d7f5a7707931f8e73fa951325642985c89 Mon Sep 17 00:00:00 2001 From: Andrew Lawson Date: Mon, 1 Dec 2014 13:25:06 -0500 Subject: [PATCH 09/11] Fixed input being changed globally when modified in samplePoints(). --- geometric_separators.pde | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/geometric_separators.pde b/geometric_separators.pde index df2b97a..add7705 100644 --- a/geometric_separators.pde +++ b/geometric_separators.pde @@ -137,15 +137,16 @@ PVector getGeometricMedian(ArrayList input) { // Sample input points into sets of 4 ArrayList> samplePoints(ArrayList input) { + ArrayList inputCopy = new ArrayList(input); ArrayList> setList = new ArrayList>(); ArrayList pointList = new ArrayList(); // While there are still points, split into sets - while (input.size() > 0) { + while (inputCopy.size() > 0) { double rnd = new Random().nextDouble(); - int index = (int)(rnd * 10) % input.size(); + int index = (int)(rnd * 10) % inputCopy.size(); // Add to set - pointList.add(input.get(index)); - input.remove(index); + pointList.add(inputCopy.get(index)); + inputCopy.remove(index); // Create new set on max size if (pointList.size() == 4) { setList.add(pointList); From 4cef74d116731c9d6b88cfe82e3c5e29e1540090 Mon Sep 17 00:00:00 2001 From: Andrew Lawson Date: Mon, 1 Dec 2014 13:38:12 -0500 Subject: [PATCH 10/11] Removed memoization of ordinary sums - results unused. --- README.md | 4 +++- geometric_separators.pde | 5 ----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2102fe1..aa173bf 100644 --- a/README.md +++ b/README.md @@ -3,4 +3,6 @@ geometric_separators Geometric separators project for CSE 4095 (Computational Geometry). -Click anywhere to create a circle. The left button will reset the workspace / input. The right button does nothing... for now :) +###About: + + diff --git a/geometric_separators.pde b/geometric_separators.pde index add7705..fa0526c 100644 --- a/geometric_separators.pde +++ b/geometric_separators.pde @@ -227,7 +227,6 @@ ReturnTriple calcLastSum(int i, PVector currentPoint, PVector nextPoint, ArrayLi // Get sums and sums of squares of distances for an input HashMap getSums(ArrayList input, boolean isY) { // Memoization hash tables - HashMap sumMemoize = new HashMap(); HashMap sumSquaresMemoize = new HashMap(); ReturnTriple returnTriple = new ReturnTriple(0, 0, null); PVector currentPoint, nextPoint; @@ -235,10 +234,6 @@ HashMap getSums(ArrayList input, boolean isY) { for (int i = 0; i < input.size() - 1; i++) { currentPoint = input.get(i); nextPoint = input.get(i + 1); - // Calculate sum - returnTriple = calcLastSum(i, currentPoint, nextPoint, input, sumMemoize, isY); - sumMemoize = returnTriple.memoize; - sumMemoize.put(nextPoint, returnTriple.sum + (i * returnTriple.dist)); // Calculate sum of squares returnTriple = calcLastSum(i, currentPoint, nextPoint, input, sumSquaresMemoize, isY); sumSquaresMemoize = returnTriple.memoize; From 8394787f4affbe4ba154d2af6bc84eb2b82189ea Mon Sep 17 00:00:00 2001 From: Andrew Lawson Date: Mon, 1 Dec 2014 14:19:28 -0500 Subject: [PATCH 11/11] Fixed centerpoint algorithm to return a point in the input rather than a new point. --- geometric_separators.pde | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/geometric_separators.pde b/geometric_separators.pde index fa0526c..0946cd3 100644 --- a/geometric_separators.pde +++ b/geometric_separators.pde @@ -129,9 +129,20 @@ PVector getGeometricMedian(ArrayList input) { } else { // Get the point - float x = getAxisMin(input, false); - float y = getAxisMin(input, true); - return new PVector(x, y); + HashMap total = new HashMap(); + HashMap x = getAxisMin(input, false); + HashMap y = getAxisMin(input, true); + Set keys = x.keySet(); + for (PVector key : keys) { + total.put(key, x.get(key) + y.get(key)); + } + ArrayList> sortedList = new ArrayList>(total.entrySet()); + Collections.sort(sortedList, new Comparator>() { + public int compare(Entry entry1, Entry entry2) { + return (int)(entry1.getValue() - entry2.getValue()); + } + }); + return sortedList.get(0).getKey(); } } @@ -243,7 +254,7 @@ HashMap getSums(ArrayList input, boolean isY) { } // Get minimum point for given axis input -Float getAxisMin(ArrayList input, boolean isY) { +HashMap getAxisMin(ArrayList input, boolean isY) { HashMap sumSquaresLeft, sumSquaresRight; HashMap totalSumSquares = new HashMap(); // Get left distances @@ -267,19 +278,7 @@ Float getAxisMin(ArrayList input, boolean isY) { PVector point = input.get(i); totalSumSquares.put(point, sumSquaresLeft.get(point) + sumSquaresRight.get(point)); } - ArrayList> sortedList = new ArrayList>(totalSumSquares.entrySet()); - Collections.sort(sortedList, new Comparator>() { - public int compare(Entry entry1, Entry entry2) { - return (int)(entry1.getValue() - entry2.getValue()); - } - }); - // Return final point coordinate - if (isY) { - return sortedList.get(0).getKey().y; - } - else { - return sortedList.get(0).getKey().x; - } + return totalSumSquares; } // Draw