1

So I have created this program to randomly place objects in a room with a number of constraints. One such constraint is that every object has to be at least dis distance away from every other object already placed in the room. My entire code works well, however I often have to problem that the code stays stuck in the while loop. Here is that part of the code:

// distance vector to check whether the distance is kept
double[] dis2 = new double[k+1];
        
// distance vector to check whether the distance to the input/output is kept
double[] dis4 = new double[2];
dis4[0] = Math.abs(NewObjectX - inputX) + Math.abs(NewObjectY - inputY);
dis4[1] = Math.abs(NewObjectX - outputX) + Math.abs(NewObjectY - outputY);
        
// Check the distance constraints
int l = 0;
while (l<k+1) {
    dis2[l] = Math.abs(NewObjectX - PlacedX[l]) + Math.abs(NewObjectY - PlacedY[l]);
    if (dis2[l]<dis || dis3>2.5*dis || dis4[0]<dis || dis4[1]<dis) {
        NewObjectX = Math.random()*(dim[1]-dim[0]) + dim[0]*0.5;
        NewObjectY = Math.random()*(dim[3]-dim[2]) + dim[2]*0.5;
        dis3 = Math.abs(NewObjectX - PlacedX[k]) + Math.abs(NewObjectY - PlacedY[k]);
        dis4[0] = Math.abs(NewObjectX - inputX) + Math.abs(NewObjectY - inputY);
        dis4[1] = Math.abs(NewObjectX - outputX) + Math.abs(NewObjectY - outputY);
        l=0;
    } else {
        l++;
    }
}

What happens: I randomly place a machine in the room and then I check the distance constraints with every already placed object in the while loop:

  • In the while loop, I check the distance constraint with the first, then second and so on objects that have already been placed.
  • If the distance constraints are not met, then a new randomly selected spot is selected and I restart the while loop l=0

I am not sure why my code sometimes stays stuck in that loop and most of the time works perfectly.

Could someone help me? Did I make an error?

Thank you so much :) Sam

EDIT:

Here is a copy of the simplified code with only 1 constraint instead of 4 in the while loop:

public static double[][] initialPop(double[] dim, double dis, int WSNr, double[] ioPlace) {
    
    int[] WStoPlace = new int[WSNr-2];
    for (int i=1; i<WSNr-1; i++) {
        WStoPlace[i-1] = (i);
    }
    
    double[][] placed = new double[WSNr-2][3];
    double ObjectX;
    double ObjectY;
    
    // now place the first object
    ObjectX = dim[1]/2;
    ObjectY = dim[3]/2;
    placed[0][0] = WStoPlace[0];
    placed[0][1] = ObjectX ;
    placed[0][2] = ObjectY;
    
    for (int i=1; i<WSNr-2; i++) {
        //place the ith object
        ObjectX = Math.random()*(dim[1]-dim[0]) + dim[0]*0.5;
        ObjectY = Math.random()*(dim[3]-dim[2]) + dim[2]*0.5;
        
        int l=0;
        while (l<i) {
            double dis2 = Math.abs(ObjectX  - placed[l][1]) + Math.abs(ObjectY - placed[l][2]);
            if (dis2<dis) {
                ObjectX  = Math.random()*(dim[1]-dim[0]) + dim[0]*0.5;
                ObjectX  = Math.random()*(dim[3]-dim[2]) + dim[2]*0.5;
                l=0;
            } else {
                l++;
            }
        }
        
        // Add the newly placed object
        placed[i][0] = WStoPlace[i];
        placed[i][1] = ObjectX;
        placed[i][2] = ObjectY;
    }
    return placed;  
}

This code is then called by my main program in a for-loop:

public static void main(String[] args) {
    
    // define all the variables ...
    int popFlow = 5;
    double[] dim = new double [4];
    dim[0] = 3; // length of WS (x)
    dim[2] = 3; // width of WS (y)
    dim[1] = 100; // length of facility (x)
    dim[3] = 40;
    double dis = 8;
    int WSNr = 22;
    double[] ioPlace = new double[4];
    ioPlace[0] = 0;     // int xi = 0;
    ioPlace[1] = 5;     // int yi = 2;
    ioPlace[2] = 100;   // int xo = 50;
    ioPlace[3] = 35;
    double[][] TotalPop = new double[popFlow][2*WSNr];

    
    // Flow-related placed Workstations
    for (int i=0; i<popFlow; i++) {
        double [][] Pos = initialPop(dim, dis, WSNr, ioPlace);
        for (int j=0; j<WSNr-2; j++) {
            int Value = (int) Pos[j][0];
            TotalPop[i][Value] = Pos[j][1];
            TotalPop[i][Value+WSNr] = Pos[j][2];
        }
    }
}
10
  • You may have a situation where the constraint cannot be satisfied at all. So your while loop starts over and over again. Commented Dec 13, 2021 at 8:56
  • Ok, that was what I was thinking as well! Is there a way to force my entire code to restart, if the constraints cannot be satisfied, so if my while loop continuously restarts? Something with like a time constraint? Commented Dec 13, 2021 at 8:59
  • Time does not matter … – Try a counter for the restarts: if after x restarts, no solution could be found, give in. Commented Dec 13, 2021 at 9:08
  • Instead of giving the advice to just kill the loop after a counter, I would recommend you try to edit your question to deliver a minimal, reproducible example to recreate the problem, so that you we/you can solve the problem and not try to "patch" the problems effect. Commented Dec 13, 2021 at 9:10
  • Have you tried running it in a debugger? Or added traces so that you can see the values of the variables related to the if condition when it gets stuck in the while loop? Commented Dec 13, 2021 at 9:46

2 Answers 2

2

As mentioned in the question's comments, you need to limit the loop. As a quick solution, you can have a counter that limits the while loop functionality and reset the entire logic which its probability to NOT go into same situation again is high. But that really should be handled better and check in which case exactly the loop would not end.

If the reason found and could be handled by the breaking conditions then it would be better as it would be more definite solution. Nevertheless, limiting the iteration for emergency is almost a must have. Here is simple sample on your code that would do something similar

public static double[][] initialPop(double[] dim, double dis, int WSNr, double[] ioPlace) {
        boolean reset = false;
        double[][] placed = null;

        while (!reset) {
            int[] WStoPlace = new int[WSNr - 2];
            for (int i = 1; i < WSNr - 1; i++) {
                WStoPlace[i - 1] = (i);
            }

            placed = new double[WSNr - 2][3];
            double ObjectX;
            double ObjectY;

            // now place the first object
            ObjectX = dim[1] / 2;
            ObjectY = dim[3] / 2;
            placed[0][0] = WStoPlace[0];
            placed[0][1] = ObjectX;
            placed[0][2] = ObjectY;

            for (int i = 1; i < WSNr - 2; i++) {
                //place the ith object
                ObjectX = Math.random() * (dim[1] - dim[0]) + dim[0] * 0.5;
                ObjectY = Math.random() * (dim[3] - dim[2]) + dim[2] * 0.5;

                // Problem is the while, not the for so we define the limit here
                int limit = 100;
                int counter = 0;

                // Make sure it's false as it might be changed in some iteration before!
                // I promised, check the comments below !
                reset = false; 

                int l = 0;
                while (l < i) {
                    double dis2 = Math.abs(ObjectX - placed[l][1]) + Math.abs(ObjectY - placed[l][2]);
                    if (dis2 < dis) {
                        ObjectX = Math.random() * (dim[1] - dim[0]) + dim[0] * 0.5;
                        ObjectX = Math.random() * (dim[3] - dim[2]) + dim[2] * 0.5;
                        l = 0;
                    } else {
                        l++;
                    }
                    if (counter >= limit) { // Now that's enough !
                        reset = true;
                        break;
                    }
                    counter++;
                }

                if (reset) { // I said it's enough, I want full reset so ...
                    reset = false; // going to break to the while-loop that checking this, and we want to enter again !
                    break;
                } else {
                    // Not sure at this point this will be the last execution
                    // So just make it true, so we do not enter the entire logic again
                    // after finally settling to our result !!!!
                    // If it's not the last execution which means we are entering another for-loop iteration then
                    // we will reset this to false, i promise !
                    reset = true;
                    // Add the newly placed object
                    placed[i][0] = WStoPlace[i];
                    placed[i][1] = ObjectX;
                    placed[i][2] = ObjectY;
                }

            }
        }
        return placed;
    }
Sign up to request clarification or add additional context in comments.

Comments

0

You need a breakout. Add a counter or timer or check off coords as you try them until they are all checked. The way it is now there is no way to end the loop if your conditions in the "if" statement are always meet, it will just keep setting 'l' to 0 and your while loop just keeps looping.

1 Comment

As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.