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();
}
The question as asked in the title has already been answered, but there are some constraints i am bound by that require a different solution.
The answer to finding the closest value in an array to a number:
int myNumber = 490;
int distance = Math.abs(numbers[0] - myNumber);
int idx = 0;
for(int c = 1; c < numbers.length; c++)
{
int cdistance = Math.abs(numbers[c] - myNumber);
if(cdistance < distance)
{
idx = c;
distance = cdistance;
}
}
int theNumber = numbers[idx];
For some background on what makes my problem specific enough to ask:
My program takes in a PriorityQueue of hospital patients. There are 3 operating rooms, and the program will output the 8 hour(a work day) schedule for those 3 operating rooms, in addition my "postpone" array, containing patients that did not make the cut for that day. I have an array called roomCapacity which contains the remaining hours in each room. Heres where my problem is more specific than the title. The above answer uses the distances between each number and in my case picks the roomCapacity with the least distance(best fit). But there are times when the DIFFERENCE is -1. I realize the Math.abs ensures the DISTANCE is positive, but in this particular case I have no reason to use absolute value for the reason being an operation may not be scheduled in a room if the duration of the operation is longer than the capacity of the room. The DISTANCE(absolute value of the difference) must be greater than OR equal to zero. I've spent what I have decided counterproductive trying to find a solution, and would greatly appreciate some hints.
In a hurry to get this done i slapped the above code into my method, and only after using the debugger realized that I was placing patients in rooms whos capacities were less than the operations duration, but would be the best fit neglecting said constraint.
(EDIT)Specific question: How do I find the closest number in my roomCapacity array to a value(int d) using a similar approach to the one shown above, while taking into account the difference may not be less than 0?
(This is my first question, appologies for the ambiguity)
my method:
public int getBestRoom(int d)//int d = currentOperationDuration
{
int roomNumber;
/**
*int distance = Math.abs(roomCapacity[0] - d);
*int idx = 0;
*for(int c = 1; c < 3; c++)
*{
* int cdistance = Math.abs(roomCapacity[c] - d);
* if(cdistance < distance)
* {
* idx = c;
* distance = cdistance;
* }
*roomNumber = idx;
*}
**/
return roomNumber;
}
Easy, remove all Math.abs and test for positive distances only:
int myNumber = 490;
int distance = Integer.MAX_VALUE;
int idx = 0;
for(int c = 0; c < numbers.length; c++)
{
int cdistance = numbers[c] - myNumber;
if (cdistance < distance && cdistance >= 0)
{
idx = c;
distance = cdistance;
}
}
int theNumber = numbers[idx];
I've been trying to generate a pattern of circles using a for loop. However, when it runs everything looks fine except for the 9th ring of circles which is ever so slightly. Having looked at a print out of numbers for that circle everything looks fine, so I can't work out what is going wrong. However, when I add one to the angle value of that ring. i.e. j (the commented out code) it pretty much corrects.
Any idea why this might happen. having looked at all the numbers I can only think it is some math error that I haven't factored in or am I missing something obvious.
Thanks!
ellipse(325,325,15,15);
float div = 1;
for (int i = i; i < 25; i++)
{
div = i*6
float segment = 360/div;
float radius = (i*20);
for (int j = 0; j < 360; j+=segment)
{
//if (i==8)
//{
//println("before " + j);
//j+=1;
//println("after " + j);
//}
float x = 325 + (radius*cos(radians(j)));
float y = 325 + (radius*sin(radians(j)));
ellipse(x, y, 15, 15);
}
}
Ok, three things, in order of importance. Two of these have already been mentioned.
1) Clean out the ints. Variable i can be an int, but none of the others (especially j since it is an angle, not a counter or index), and you want to make sure that all math operations treat numbers as doubles. Go so far as to designate your constants as doubles (e.g. use 1d instead of 1).
2) Avoid cumulative errors. In your inner for loop, you repeatedly add to j. Bad. Instead, compute your angle directly based on which circle you're computing.
3) Use double, not float. You'll get better precision.
I'd do it like this...
ellipse(325,325,15,15);
for (int i = i; i < 25; i++)
{
double div = i*6d;
double radius = (i*20d);
for (int j = 0; j < div; j++)
{
double theta = j * 360d / div;
double x = 325d + (radius*cos(radians(theta)));
double y = 325d + (radius*sin(radians(theta)));
ellipse(x, y, 15, 15);
}
}
You get the segment as a float, but then you use an int to calculate the degrees.
for (int j=0; j < 360; j+=segment)
and
float x = 325 + (radius*cos(radians(j)));
This is what is causing the rounding errors.
And if you make i to get a value bigger than 60 the program will never end.
Use double instead of float to minimise representation error.
Change the for loop to reduce error.
for (int k = 0; k < div; k++) {
int j = k * 360 / div;
This will give you different values for j which are likely to be more correct.
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).
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