Divide and Conquer Hull Algorithm - java

Hello my question today is to breakdown and figure out how to actually code the LOWER TANGENT part of the algorithm Ive managed to complete steps (1) and (2) but I am now on stuck on step (3).
Divide and Conquer Convex Hull
Hull(S) :
(1) If |S| <= 3, then compute the convex hull by brute force in O(1)
time and return.
(2) Otherwise, partition the point set S into two sets A and B, where
A consists of half the points with the lowest x coordinates and B
consists of half of the points with the highest x coordinates.
(3) Recursively compute HA = Hull(A) and HB = Hull(B).
(4) Merge the two hulls into a common convex hull, H, by computing the
upper and lower tangents for HA and HB and discarding all the points
lying between these two tangents.
http://www.cs.wustl.edu/~pless/506/l3_1.gif
Finding the Lower Tangent
LowerTangent(HA ; HB ) :
(1) Let a be the rightmost point of HA .
(2) Let b be the leftmost point of HB .
(3) While ab is not a lower tangent for HA and HB do
(a) While ab is not a lower tangent to HA do a = a - 1 (move a clockwise).
(b) While ab is not a lower tangent to HB do b = b + 1 (move b counterclockwise).
(4) Return ab.
Quoted from: http://www.cs.wustl.edu/~pless/506/l3.html
This explanation is the best that describe my problem.
The functions for Lexisort and convexHull have not been included as they are working, the DC hull algorithm has been included to provide context.
My current code:
public static int [][] dcHull(int [][]merged){
if(merged.length <= 3)
return convexHull(merged);
else {
lexiSort(merged);
//split(P, A, B);
//SPLIT
double p = merged.length;
int A;
int B;
if (p%2 == 0){//EVEN
A = (int) (p/2);
B = (int) (p/2);
}
else//ODD
A = (int) (1+(p/2));
B = (int) (p/2);
int arrayA[][] = new int[A][2];
int arrayB[][] = new int[B][2];
for (int i=0; i<A; i++){
arrayA[i][0] = merged[i][0];
arrayA[i][1] = merged[i][1];
}
for (int i=0; i<B; i++){
arrayB[i][0] = merged[i+A][0];
arrayB[i][1] = merged[i+A][1];
}
for ( int i=0; i<arrayA.length; i++){
System.out.println( "Merged array A Coordinates: " + arrayA[i][0] +", " + arrayA[i][1]);}
for ( int i=0; i<arrayB.length; i++){
System.out.println( "Merged array B Coordinates: " + arrayB[i][0] +", " + arrayB[i][1]);}
lowerT(arrayA, arrayB);
//upperT(arrayA, arrayB);
return merged(dcHull(convexHull(arrayA)), dcHull(convexHull(arrayB)));
}
}
public static int[][] lowerT(int [][] hulla, int [][] hullb){
int a = 0;
int b = 0;
//LOWER TANGENT
//(1) Let a be the rightmost point of HA .
for (int i=0; i<hulla.length; i++){
if (a < hulla[i][0]){
a = hulla[i][0];
}
}
//(2) Let b be the leftmost point of HB .
for (int i=0; i<hullb.length; i++){
if (b < hullb[i][0]){
b = hullb[i][0];
}
}
for (int i=0; i<hullb.length; i++){
if (b > hullb[i][0]){
b = hullb[i][0];
}
}
The code finishes after working out a of HA and b of HB however I do not understand (3) or more precisely how to code it using the elements I have.
(1) Let a be the rightmost point of HA .
(2) Let b be the leftmost point of HB .
There is an additional method of code called right turn that I believe is useful:
"Lower tangency is a condition that can be
tested locally by an orientation test of the two vertices and
neighboring vertices on the hull."
Im just not sure how to put it together.
public static boolean rightTurn(int [][] rt, int counter) //AxBxC = (Bx-Ax)(Cy-Ay)-(By-Ay)(Cx-Ax)
{
int ax = rt[counter-2][0];
int bx = rt[counter-1][0];
int cx = rt[counter][0];
int ay = rt[counter-2][1];
int by = rt[counter-1][1];
int cy = rt[counter-0][1];
int result =(bx-ax)*(cy-ay)-(by-ay)*(cx-ax);
if (result < 0){ // Result = VE+ (Right Turn), 0, VE- (Left Turn)
return true; //VE- = TRUE = Right Turn
}
else return false; //VE+ = FALSE = Left Turn
}

First,
//(2) Let b be the leftmost point of HB .
for (int i=0; i<hullb.length; i++){
if (b < hullb[i][0]){
b = hullb[i][0];
}
}
for (int i=0; i<hullb.length; i++){
if (b > hullb[i][0]){
b = hullb[i][0];
}
}
there seems to be a leftover copy-pasto.
Now, let us try to change "however I do not understand (3) or more precisely how to code it using the elements I have".
(a) While ab is not a lower tangent to HA do a = a - 1 (move a clockwise).
So you need a test whether a straight line is a lower tangent to HA. The geometrical situation here simplfies the test. Fundamental is of course the convexity of HA. The considered straight lines,L, always pass through a vertex of HA, say v, and a vertwx of HB, say b. Let the two neighbouring vertices be u and w, labelled so that u, v, w is a clockwise piece of the boundary. There are three possibilities, 1. u and w both lie above or on L, then, by convexity, L is a lower tangent to HA; 2. one of u and w lies above or on L, the other below; 3. both lie below L.
w lies below L if and only if the path bvw makes a left turn at v.
u lies below L if and only if the path bvu makes a left turn at v.
You need a function to check whether a path ABC makes a left turn (by an angle less than 180°) at B. Your rightTurn has the gist, but the wrong parameters, because one of the points you want to test belongs to the other hull. And test that you got the signs right, it's easy to slip there.
So while either of the two neighbours of v lies below the straight line through b and v, replace v by its clockwise neighbour and check again. Take care of the array bounds when picking neighbours.
After a couple of steps you've found a straight line which is a lower tangent to HA, but in general not of HB.
(b) While ab is not a lower tangent to HB do b = b + 1 (move b counterclockwise).
This is analogous, but with a change of orientation. A point p on the boundary of HB lies below the straight line through a (a vertex of HA) and b (the considered vertex of HB) if and only if the path pba makes a left turn at b.
Picking counterclockwise neighbours on the boundary of HB until a lower tangent of HB is found rotates the line about the vertex a on the boundary of HA, so that that lower tangent of HB need not be a lower tangent of HA anymore (look at the picture you linked).
So back to 3 (a). That will rotate the line about b, possibly so much that it is no longer a lower tangent to HB. 3 (b) again.
Iterate until you found a lower tangent to both.
aIndex = findRightmostA();
bIndex = findLeftmostB();
while(!(lowerTangentA (aIndex, bIndex) && lowerTangentB(aIndex, bIndex))){
aIndex = findLowerTangentA(aIndex, bIndex);
bIndex = findLowerTangentB(aIndex, bIndex);
}
lowerTangentA(aIndex, bIndex){
ux = hulla[aIndex+1][0];
uy = hulla[aIndex+1][1]; // array bounds!
ax = hulla[aIndex][0];
ay = hulla[aIndex][1];
wx = hulla[aIndex-1][0];
wy = hulla[aIndex-1][1];
bx = hullb[bIndex][0];
by = hullb[bIndex][1];
return !(leftTurn(bx,by,ax,ay,ux,uy) || leftTurn(bx,by,ax,ay,wx,wy));
}
Finding the upper tangent to both hulls is analogous. It is worthwhile to try and abstract the tangent checks so that you can use the same function for all checks (lower/upper, HA/HB).

Related

Implementation of FitzHugh-Nagumo diffusion model diverging by first iteration

I'm trying to implement the model described in this paper, which simulates the equation proposed by Alan Turing of the FitzHugh-Nagumo model in 2D as a model for forming animal skin patterns — in other words: simulating two substances diffusing across a surface, how they interact with each other, and what patterns arise. This is the paper's result:
                                            
I've implemented it (my interpretation of at least) in Processing/Java, but it's not working like it should (values are diverging lots, even by the first iteration), so I'm wondering what's going wrong in my implementation (included at the end of the post).
These are the 3 relevant parts from the paper regarding implementation:
1. U & V
There are two substances, u and v (which can be thought of as an activator and inhibitor respectively)
2. Finite difference equations
A fairly simple pixel convolution is defined for each value (pixel) of u and v. Values for a given pixel on the next generation are calculated using both it and its neighbours' current-iteration values.
The value of u on the n+1 iteration for a given pixel (i,j) is defined as:
The value of v on the n+1 iteration for a given pixel (i,j) is defined as:
3. Constants they used
So the problem I'm getting is that the values of u and v are quickly diverging to infinity/NaN (I expect they should stay within 0...1 although the paper doesn't explicitly mention this). v seems to diverge first, taking u along with it, as can be seen here (for some constant index):
0.94296926 0.77225316 // u, v after random initialisation
0.91600573 -62633.082 // values after first iteration -- v has already diverged massively
63.525314 5.19890688E8 // second iteration -- even more divergence
-520088.38 -2.98866172E14 // ...and so on...
1.40978577E14 1.2764294E19
-Infinity -1.7436987E24
NaN NaN
NaN NaN
Code
//Parallel Simulation of Pattern formation in a reactiondiffusion system of Fitzhugh-Nagumo Using GPU CUDA
// Alfredo Gormantara and Pranowo1
static final float a = 2.8e-4;
static final float b = 5.0e-3;
static final float k = -0.005;
static final float tau = 0.1;
static final float delta_t = 1e-3;
float[][] u; // activator
float[][] v; // inhibitor
void setup() {
size(512, 512);
frameRate(5);
u = new float[height][width];
v = new float[height][width];
for (int i = 0; i < u.length; i++) {
for (int j = 0; j < u[0].length; j++) {
u[i][j] = random(1); // random of max of 1 ?
v[i][j] = random(1); // random of max 1?
}
}
loadPixels();
}
void draw() {
float[][] u_n_1 = new float[height][width]; // array holding the n+1 iteration values of u
float[][] v_n_1 = new float[height][width]; // array holding the n+1 iteration values of v
float denom = 2f / width; // 2/MESH_SIZE -- I think mesh_size is dimension of the grid
denom*=denom; // square for denominator
println(u[34][45], v[34][45]); // print vals of one location to see divergence
for (int y = 0; y < height; y++) {
int negative_y_i = y-1 < 0 ? height-1 : y-1; // wrap around grid
for (int x = 0; x < width; x++) {
final float u_n = u[y][x];
final float v_n = v[y][x];
int negative_x_i = x-1 < 0 ? width-1 : x-1; // wrap around grid
// calculate laplace (12)
float u_n_1_laplace = u[y][(x+1) % (width)] + u[y][negative_x_i] + u[(y+1) % (height)][x] + u[negative_y_i][x]; //n+1th iteration
u_n_1_laplace -= (4 * u_n);
u_n_1_laplace /= denom; // divide by (2/DIM)^2
u_n_1_laplace *= a;
// calculate n+1th iteration u value
u_n_1[y][x] = u_n + delta_t*( u_n_1_laplace + u_n -(u_n*u_n*u_n) - v_n + k );
// calculate laplace (14)
float v_n_1_laplace = v[y][(x+1)% (width)] + v[y][negative_x_i] + v[(y+1)% (height)][x] + v[negative_y_i][x]; //n+1th iteration
v_n_1_laplace -= (4 * u_n);
v_n_1_laplace /= denom; // denom is really small, so value goes huge
v_n_1_laplace *=b;
v_n_1[y][x] = v_n + (tau/delta_t)*( v_n_1_laplace + u_n - v_n);
pixels[y*width + x] = color((int) ((u_n_1[y][x]-v_n_1[y][x])*255));
}
}
u = u_n_1.clone(); // copy over new iteration values
v = v_n_1.clone(); // copy over new iteration values
updatePixels();
}

RandomWalk solution issue

PROBLEM
I am working on a code where I am simulating a dog walking in a city - trying to escape the city. The dog makes random choices of which way to go to at each intersection with equal probability.If stuck at a dead end the dog will come directly back to the middle of a big city and start all over again. The dog will do this again and again until it gets out of the city or until it gets tired after T number of trials. But by the time the the dog starts again from the middle(N/2,N/2) on each try, it will have forgotten all the intersections it had visited in the previous attempt.
IDEA
The idea is to mimic a code given in our textbook and come up with the solution. We were given input N, T - where N is the number of north-south and east-west streets in the city and T is the number of times the dog will try to get out of the city before it gives up. We have to draw it out, using StdDraw. We have been given how to make random movements - generate a number between 0 and 4 - up: 0 right: 1 down: 2 left: 3
My Approach
import java.util.Random;
public class RandomWalk {
private static final Random RNG = new Random (Long.getLong ("seed",
System.nanoTime()));
public static void main(String[] args) {
int N = Integer.parseInt(args[0]); // lattice size
int T = Integer.parseInt(args[1]); // number of trials
int deadEnds = 0; // trials resulting in a dead end
StdDraw.setCanvasSize();
StdDraw.setXscale(0,N);
StdDraw.setYscale(0,N);
// simulate T self-avoiding walks
for (int t = 0; t < T; t++) {
StdDraw.clear();
StdDraw.setPenRadius(0.002);
StdDraw.setPenColor(StdDraw.LIGHT_GRAY);
for(int i=0;i<N;i++){
StdDraw.line(i, 0, i, N);
StdDraw.line(0, i, N, i);
}
StdDraw.setPenColor(StdDraw.RED);
StdDraw.setPenRadius(0.01);
boolean[][] a = new boolean[N][N]; // intersections visited
int x = N/2, y = N/2; // current position
// repeatedly take a random step, unless you've already escaped
while (x > 0 && x < N-1 && y > 0 && y < N-1) {
int t_x = x;
int t_y=y;
// dead-end, so break out of loop
if (a[x-1][y] && a[x+1][y] && a[x][y-1] && a[x][y+1]) {
deadEnds++;
break;
}
// mark (x, y) as visited
a[x][y] = true;
// take a random step to unvisited neighbor
int r = RNG.nextInt(4);
if (r ==3) {
//move left
if (!a[x-1][y])
t_x--;
}
else if (r == 1 ) {
//move right
if (!a[x+1][y])
t_x++;
}
else if (r == 2) {
//move down
if (!a[x][y-1])
t_y--;
}
else if (r == 0) {
//move up
if (!a[x][y+1])
t_y++;
}
StdDraw.line(t_x, t_y, x, y);
x = t_x;
y = t_y;
}
System.out.println("T: "+t);
}
System.out.println(100*deadEnds/T + "% dead ends");
}
}
ISSUE
Given N - 15, T - 10, -Dseed=5463786 we should get an output like - http://postimg.org/image/s5iekbkpf/
I am getting - see http://postimg.org/image/nxipit0pp/
I don't know where I am going wrong. I know this is very specific in nature, but I am really confused so as to what I am doing wrong. I tried all 24 permutations of 0,1,2,3 but none of them gave the output desired. So, I conclude that the issue in in my code.
check your StdDraw.java with:
http://introcs.cs.princeton.edu/java/stdlib/StdDraw.java.html
your code should be fine, I got the expected result

Find longest distance from a certain point (java, 2d diagram)

I'm working on a clustering program in Java. I'm trying to find the point that has the longest distance from another point in an 2-dimentional diagram with x and y axis.
I though I could use pytagoras:
Where the square of the Y-axis of the starting point + the square of the X-axis of the of the other points will determine the distance between them.
What my code does is for this certain point, check all other points to see if it finds a point with a higher distance. The code I have at the moment is the following:
// The points to find longest distance from
x_coord = 2;
y_coord = 4;
// Need to find right size
double var1 = Math.pow(y_coord, 2); // square of Y
double var2 = 0;
double var3 = 0;
int sum = 0;
/* For all coords ( of the cluster clusters)
* coordsX is an array that holds all the X coordinates
* of all other points
*/
for (int k = 0; k < coordsX.length; k++){
// Check which is furthest away from
var2 = Math.pow(coordsX[k], 2); // square of X
var3 = var1 + var2; // Sum of var1 and var2
sum = (int)Math.sqrt(var3); // Square root to find distance
if (sum > longestDistance){
longestDistance = sum;
}
}
Does anyone have any suggestions what might be wrong? Or is this an unsuited method to calculate distances?
So, to find the distance between two points, say A and B located on a xy plane, where A and B are indices, here is what you need to do:
double distanceSquared = Math.pow(coordsX[A] - coordsX(B), 2) + Math.pow(coordsY[A] - coordsY(B), 2);
And if you just want to find the most distant point, there is no need to take a square root, because it is a monotonic function, so it does not change the result of comparison at all.
Simply compare the distance squares
EDIT: code for you.
double longestDistanceSquared = 0;
int mostDistantPointIndex = -1;
for (int k = 0; k < coordsX.length; k++){
double distanceSquared = Math.pow(coordsX[k] - x_coord, 2) + Math.pow(coordsY[k] - y_coord, 2);
if (distanceSquared > longestDistanceSquared){
longestDistanceSquared = distanceSquared;
mostDistantPointIndex = k;
}
}
The first thing that jumps out of the code to me is that you are casting the result of the sqrt() call to an int. That seems like it's going to cause problems.

Selecting points such that sum of x coordinates = sum of y coordinates

I have an array of Points. I need to select a subset of points from it, such that the sum of x coordinates of the points = sum of y coordinates of the points.
If there are many such subsets, the one with largest sum of x coordinates is required.
The sum of x coordinates needs to be reported.
I have written a brute force recursive method, which tests all possibilities.
Point[] a = new Point[n];
// ...
private int rec(int i, int x, int y) {
if (i == n - 1) {
if (x + a[i].x == y + a[i].y) return x + a[i].x;
return (x == y) ? x : -1;
}
return Math.max(rec(i + 1, x, y), rec(i + 1, x + a[i].x, y + a[i].y));
}
The answer is rec(0, 0, 0).
My questions are:
1) Is there a dynamic programming solution for this?
2) If yes, could anyone please explain
I have a bit better (than brute force) algorithm.
Divided all coordinates into three sets: 1: {(x,y): x>y}, 2: {(x,y):x==y}, 3:{(x,y): x lower-than y}
Set 2 have to be always included in the solution.
for each (x,y) from 1 define net=x-y and for each (x,y) form 3 define net=y-x
check all possible values you can obtained from nets in 1 and nets in 3.
then basing on the greatest match it is easy to construct the solution.
Does it make sense?
For each point, set its value to x - y.
Now we need to find a set of points whose values sum to 0.
This is exactly the subset sum problem.
It is NP-complete (i.e. there is no known polynomial time algorithm for the generic case of the problem), but there exists a pseudo-polynomial time DP solution, which is given on Wikpedia, linked above. A brief summary:
We define a function Q(i,s) to be the value (true or false) of
there is a nonempty subset of x1, ..., xi which sums to s
Then we have the following recurrence:
Q(1,s) := (x1 == s)
Q(i,s) := Q(i − 1, s) or (xi == s) or Q(i − 1, s − xi) for A ≤ s ≤ B
Unless there are unstated constraints, the problem is NP-Hard by polynomial-time reduction of Subset-Sum, an NP-Complete problem.
One of the decision forms of Subset-Sum asks, given a set of integers, X, and an integer s, does any non-empty subset sum to s.
For each element of X, construct a Point whose x value is the element, and whose y value is zero. Construct one additional Point, whose x value is 0 and whose y value is s.
If the result of the equal-sum problem applied to that set of points is 0 or -1, then reject the subset-sum problem. If the result is s, then accept the subset-sum.
Assuming P != NP, or at least that we don't have any polynomial algorithm for any NP-Hard problem, there is no known polynomial-time algorithm for your problem.
just trying to code in java which would be helpful i felt:
for all i , diffOfCoordinates[i] = Xi - Yi
list will have the max points.
public void fun(int[] diffOfCoordinates, int indexA, int[] b, int indexB, int sum, List<Integer> list){
if(indexA == diffOfCoordinates.length){
if(sum==0){
if(list.size()<indexB){
list.clear();
for(int i=0;i<indexB;i++){
list.add(b[i]);
}
}
}
return;
}
b[indexB] = diffOfCoordinates[indexA];
fun(diffOfCoordinates, indexA+1, b, indexB+1, sum+diffOfCoordinates[indexA], list);
fun(diffOfCoordinates, indexA+1, b, indexB, sum, list);
}

Generate random numbers in increments

I need to generate n random numbers between a and b, but any two numbers cannot have a difference of less than c. All variables except n are floats (n is an int).
Solutions are preferred in java, but C/C++ is okay too.
Here is what code I have so far.:
static float getRandomNumberInRange(float min, float max) {
return (float) (min + (Math.random() * (max - min)));
}
static float[] randomNums(float a, float b, float c, int n) {
float minDistance = c;
float maxDistance = (b - a) - (n - 1) * c;
float[] randomNumArray = new float[n];
float random = getRandomNumberInRange(minDistance, maxDistance);
randomNumArray[0] = a + random;
for (int x = 1; x < n; x++) {
maxDistance = (b - a) - (randomNumArray[x - 1]) - (n - x - 1) * c;
random = getRandomNumberInRange(minDistance, maxDistance);
randomNumArray[x] = randomNumArray[x - 1] + random;
}
return randomNumArray;
}
If I run the function as such (10 times), I get the following output:
Input: randomNums(-1f, 1f, 0.1f, 10)
[-0.88, 0.85, 1.23, 1.3784, 1.49, 1.59, 1.69, 1.79, 1.89, 1.99]
[-0.73, -0.40, 0.17, 0.98, 1.47, 1.58, 1.69, 1.79, 1.89, 1.99]
[-0.49, 0.29, 0.54, 0.77, 1.09, 1.56, 1.69, 1.79, 1.89, 1.99]
I think a reasonable approach can be the following:
Total "space" is (b - a)
Remove the minimum required space (n-1)*c to obtain the remaining space
Shot (n-1) random numbers between 0 and 1 and scale them so that the sum is this just computed "optional space". Each of them will be a "slice" of space to be used.
First number is a
For each other number add c and the next "slice" to the previous number. Last number will be b.
If you don't want first and last to match a and b exactly then just create n+1 slices instead of n-1 and start with a+slice[0] instead of a.
The main idea is that once you remove the required spacing between the points (totalling (n-1)*c) the problem is just to find n-1 values so that the sum is the prescribed "optional space". To do this with a uniform distribution just shoot n-1 numbers, compute the sum and uniformly scale those numbers so that the sum is instead what you want by multiplying each of them by the constant factor k = wanted_sum / current_sum.
To obtain the final result you just use as spacing between a value and the previous one the sum of the mandatory part c and one of the randomly sampled variable parts.
An example in Python of the code needed for the computation is the following
space = b - a
slack = space - (n - 1)*c
slice = [random.random() for i in xrange(n-1)] # Pick (n-1) random numbers 0..1
k = slack / sum(slice) # Compute needed scaling
slice = [x*k for x in slice] # Scale to get slice sizes
result = [a]
for i in xrange(n-1):
result.append(result[-1] + slice[i] + c)
If you have random number X and you want another random number Y which is a minimum of A from X and a maximum of B from X, why not write that in your code?
float nextRandom(float base, float minDist, float maxDist) {
return base + minDist + (((float)Math.random()) * (maxDist - minDist));
}
by trying to keep the base out of the next number routine, you add a lot of complexity to your algorithm.
Though this does not exactly do what you need and does not incorporate the techinque being described in this thread, I believe that this code will prove to be useful as it will do what it seems like you want.
static float getRandomNumberInRange(float min, float max)
{
return (float) (min + (Math.random() * ((max - min))));
}
static float[] randomNums(float a, float b, float c, int n)
{
float averageDifference=(b-a)/n;
float[] randomNumArray = new float[n];
int random;
randomNumArray[0]=a+averageDifference/2;
for (int x = 1; x < n; x++)
randomNumArray[x]=randomNumArray[x-1]+averageDifference;
for (int x = 0; x < n; x++)
{
random = getRandomNumberInRange(-averageDifference/2, averageDifference/2);
randomNumArray[x]+=random;
}
return randomNumArray;
}
I need to generate n random numbers between a and b, but any two numbers cannot have a difference of less than c. All variables except n are floats (n is an int).
Solutions are preferred in java, but C/C++ is okay too.
First, what distribution? I'm going to assume a uniform distribution, but with that caveat that "any two numbers cannot have a difference of less than c". What you want is called "rejection sampling". There's a wikipedia article on the subject, plus a whole lot of other references on the 'net and in books (e.g. http://www.columbia.edu/~ks20/4703-Sigman/4703-07-Notes-ARM.pdf). Pseudocode, using some function random_uniform() that returns a random number drawn from U[0,1], and assuming a 1-based array (many languages use a 0-based array):
function generate_numbers (a, b, c, n, result)
result[1] = a + (b-a)*random_uniform()
for index from 2 to n
rejected = true
while (rejected)
result[index] = a + (b-a)*random_uniform()
rejected = abs (result[index] < result[index-1]) < c
end
end
Your solution was almost correct, here is the fix:
maxDistance = b - (randomNumArray[x - 1]) - (n - x - 1) * c;
I would do this by just generating n random numbers between a and b. Then I would sort them and get the first order differences, kicking out any numbers that generate a difference less than c, leaving me with m numbers. If m < n, I would just do it again, this time for n - m numbers, add those numbers to my original results, sort again, generate differences...and so on until I have n numbers.
Note, first order differences means x[1] - x[0], x[2] - x[1] and so on.
I don't have time to write this out in C but in R, it's pretty easy:
getRands<-function(n,a,b,c){
r<-c()
while(length(r) < n){
r<-sort(c(r,runif(n,a,b)))
r<-r[-(which(diff(r) <= c) + 1 )]
}
r
}
Note that if you are too aggresive with c relative to a and b, this kind of solution might take a long time to converge, or not converge at all if n * C > b -a
Also note, I don't mean for this R code to be a fully formed, production ready piece of code, just an illustration of the algorithm (for those who can follow R).
How about using a shifting range as you generate numbers to ensure that they don't appear too close?
static float[] randomNums(float min, float max, float separation, int n) {
float rangePerNumber = (max - min) / n;
// Check separation and range are consistent.
assert (rangePerNumber >= separation) : "You have a problem.";
float[] randomNumArray = new float[n];
// Set range for first random number
float lo = min;
float hi = lo + rangePerNumber;
for (int i = 0; i < n; ++i) {
float random = getRandomNumberInRange(lo, hi);
// Shift range for next random number.
lo = random + separation;
hi = lo + rangePerNumber;
randomNumArray[i] = random;
}
return randomNumArray;
}
I know you already accepted an answer, but I like this problem. I hope it's unique, I haven't gone through everyone's answers in detail just yet, and I need to run, so I'll just post this and hope it helps.
Think of it this way: Once you pick your first number, you have a chunk +/- c that you can no longer pick in.
So your first number is
range1=b-a
x=Random()*range1+a
At this point, x is somewhere between a and b (assuming Random() returns in 0 to 1). Now, we mark out the space we can no longer pick in
excludedMin=x-c
excludedMax=x+c
If x is close to either end, then it's easy, we just pick in the remaining space
if (excludedMin<=a)
{
range2=b-excludedMax
y=Random()*range2+excludedMax
}
Here, x is so close to a, that you won't get y between a and x, so you just pick between x+c and b. Likewise:
else if (excludedMax>=b)
{
range2=excludedMin-a
y=Random()*range2+a
}
Now if x is somewhere in the middle, we have to do a little magic
else
{
range2=b-a-2*c
y=Random()*range2+a
if (y>excludedMin) y+=2*c
}
What's going on here? Well, we know that the range y can lie in, is 2*c smaller than the whole space, so we pick a number somewhere in that smaller space. Now, if y is less than excludedMin, we know y "is to the left" of x-c, and we're all ok. However, if y>excluded min, we add 2*c (the total excluded space) to it, to ensure that it's greater than x+c, but it'll still be less than b because our range was reduced.
Now, it's easy to expand so n numbers, each time you just reduce the range by the excluded space among any of the other points. You continue until the excluded space equals the original range (b-a).
I know it's bad form to do a second answer, but I just thought of one...use a recursive search of the space:
Assume a global list of points: points
FillRandom(a,b,c)
{
range=b-a;
if (range>0)
{
x=Random()*range+a
points.Append(x)
FillRandom(a,x-c,c)
FillRandom(x+c,b,c)
}
}
I'll let you follow the recursion, but at the end, you'll have a list in points that fills the space with density 1/c

Categories