0

I have two classes. Class Algorithm implements a method findIntersections() which is a sweep line algorithm to check for intersections in O(nLogN) time.

It also implements a function addSegments which adds objects of type Segment (two points) to a priority Queue based on the x coordinate.

public class Algorithm {
 
    public PriorityQueue pQueue = new PriortiyQueue();

    //This function adds objects of type Segments to a priority queue
    public void addSegments(List<Segment> segments) {
        pQueue.add(segments);
        //do something
    }

    //This function implements a sweep line algorithm to check for Intersections.
    public void findIntersection() {
        while (!pQueue.isEmpty()) {
            p.poll(); //removes element from Queue
            // do something
        }
    }
}

The other class Model loads data from a CSV file into the priority Queue. This is an intensive process which I only want to do once.

On the other hand, checkForCollissions is called millions of times.

  • I want to check for collisions between the supplied segment and the rest of the segments added in the priority queue from the csv file

  • I do not want to be adding elements to the priority queue from scratch each time. This would not be feasible.

     public class Model  {
         public Algorithm algoObj = new Algorithm();
         public ArrayList<Segment> algoObj = new ArrayList<>();
         public ArrayList<Segment> segments = new ArrayList<>();
         public ArrayList<Segment> single_segment = new ArrayList<>();
    
         public boolean loadCSV() {
             //read csv file
             while ((strLine = br.readLine()) != null) {
               segments.add(new Segment()); //Add all segments in CSV file to ArrayLisyt
               algo.addSegments(segments);  //Adds 4000 objects of type segment to priority Queue
             }
         }
    
         //This function is called millions of times
         public boolean checkForCollisions(segment_to_check) {
             single_segment.add(segment_to_check);    //Add 1 segment. 
             algoObj.addSegments(single_segment);     //Adds 1 object of type segment to priority Queue
             algoObj.findIntersection();
             single_segment.remove(new Segment()); //Remove above segment to get back to original data
         }
     }
    

TL;DR

The problem I am having is that after the first call of checkForCollisions the priority queue has changed since findIntersection() works by polling elements from the queue, thus altering the queue.

How do I keep the priority queue created by algoObj.addSegments() from changing between function calls?

Does this have to do witch shallow and deep copying as explained here?


I tried creating a copy of the queue at the beginning of the function and then altering the copy:

        public boolean checkForCollisions(segment_to_check) {
            Algorithm copy = algoObj;
            single_segment.add(segment_to_check);    //Add 1 segment. 
            copy.addSegments(single_segment);     //Adds 1 object of type segment to priority Queue
            copy.findIntersection();
            single_segment.remove(new Segment()); //Remove above segment to get back to original data
        }
    }

This however does not work as it still alters the priority queue of the original algoObj.

I believe this is a beginner's question and stems from my lack of proper understanding when working with OO languages. Any help would be appreciated.

Federico klez Culloca
  • 22,898
  • 15
  • 55
  • 90
rrz0
  • 1,762
  • 3
  • 17
  • 51
  • 1
    You are contradicting yourself by saying *findIntersection() works by polling elements from the queue, thus altering the queue* and *I do not want to be adding elements to the priority queue from scratch each time*. If `findIntersection` modifies the queue (that is your algo), you have to create a new queue object passing the segments you have (Note: You still read from the file only once) – user7 Oct 23 '20 at 08:06
  • They are unrelated events, sorry if I was not clear. The queue is set up once by adding, say, 10,000 line segments in `loadCSV` function. The sweep line algorithm, `findIntersection` works by polling elements from the queue, thus removing segments and altering the original queue. I do not want to stay adding the 10,000 line segments again from scratch each time I check for intersections. Is that a bit clearer? – rrz0 Oct 23 '20 at 08:09
  • That is not possible as you have removed items from queue. You can only avoid reading the file again (which I guess you have already achieved that). What is the max number of items you could be inserting and why are you worried about that? – user7 Oct 23 '20 at 08:12
  • Assignment does not copy anything - it only creates a new reference to the same object. Related: https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value – Hulk Oct 23 '20 at 08:13
  • @user7 I am inserting around 4000 segments to the priority queue. If I do this every time I need to check for an intersection it would be computationally infeasible as this occurs millions of times. Therefore I was trying to find a way where after I check for intersections once, I would be able to restore the original queue via a copy of some sort. – rrz0 Oct 23 '20 at 08:14
  • Well, to create a (shallow) copy of a collection, use the [copy constructor](https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/PriorityQueue.html#%3Cinit%3E(java.util.PriorityQueue)). Still, if you want to do this millions of times, you probably want to pick an algorithm that does not require creating a copy each time. – Hulk Oct 23 '20 at 08:17
  • 2
    Why are you using a `PriorityQueue` in the first place if you don't seem to want the semantics of a `Queue`? Why not just create a `List`, sort it once, and then iterate it as needed? – Slaw Oct 23 '20 at 08:17
  • Copying would require you to create a new Algorithm instance and call `addSegments` methods passing `segments`. Are you looking to avoid that? – user7 Oct 23 '20 at 08:17
  • Yes, exactly @user7 I am looking to avoid calling `addSegments` all over again – rrz0 Oct 23 '20 at 08:19
  • @Slaw I am implementing the Bentley Ottmann algorithm which is a sweep line algorithm. This works by adding elements to a `PriorityQueue` so they are sorted based on a given priority. If I create a `List` I would need to re-sort it every time I call `checkForCollisions` where I add another element to the `List` – rrz0 Oct 23 '20 at 08:22
  • 1
    Then I'm a little confused. Are you aware of [this "limitation" of `PriorityQueue`](https://stackoverflow.com/questions/1871253)? It seems like you have no choice but to remove and re-add the elements if the order can change between calls to `checkForCollisions`. – Slaw Oct 23 '20 at 08:27
  • @FedericoklezCulloka Sorry to ping on an unrelated post but your edit [here](https://stackoverflow.com/posts/64498330/revisions) was problematic. Please don't make cosmetic edits to content which should clearly be deleted. Removing spam links makes it harder to identify spam, too. – tripleee Oct 23 '20 at 10:45

1 Answers1

1

First of all, it is crucial to know that assigning an existing object to another variable does not create a copy of the original object:

MyObject a = new MyObject();
MyObject b = a; // does NOT create a copy!
// now a and b "point" to the same single instance of MyObject!

Some thoughts about your actual problem:

Your priority queue is just a working data structure that is used for the intersection algorithm, and just while the algorithm is running. When its done (so the intersection(s) have been found), it is empty or at least altered, as you already wrote. So the priority queue must be recreated for every algorithm run.

So what you should do:

  1. Load the segments from the CSV file into your ArrayList, but don't pass it to the priority queue yet.

  2. Refill (or recreate) the priority queue every time before calling findIntersection(). This is best be done by passing all segments to the method and creating a new prioerity queue from scratch:

    public void findIntersection(Collection<Segment> segments) {
        PriorityQueue<Segment> pQueue = new PrioerityQueue<Segment>(segments);
        while (!pQueue.isEmpty()) {
            p.poll(); //removes element from Queue
            // do something
        }
    }
    

Hint: As I've already wrote at the beginning, this does not copy the individual segments nor the segment collection. It just passes a references. Of course, the priority queue will have to create internal structures at construction time, so if the segments collection is huge, this may take some time.

If this solution is too slow for your needs, you will have to work on your algorithms. Do you really need to check for intersections so often? If you add just one segment to the list, it should be sufficient to check intersections with the other segments, but not if the other segments intersect each other. Probably you could store your segments in a binary search tree similar to the one used by the Bentley–Ottmann algorithm. Whenever a new segment "arrives", it can be checked against the search tree, which should be doable with a time complexity of about O(log n). After that, the segment can be inserted into the tree, if necessary.

Or maybe you can add all segments first and then check for intersections just once.

isnot2bad
  • 22,602
  • 2
  • 27
  • 43
  • Thank you. So, yes, I really need to check for intersections so often. However, you are correct in saying that. "If you add just one segment to the list, it should be sufficient to check intersections with the other segments, but not if the other segments intersect each other." This is what I am working on, however I do still need to fill in the whole Queue each time if I want to check intersections with other segments. The last sentence is not possible since the segments which I add in `checkForCollisions` may intersect with each other and not with the original CSV loaded segments. – rrz0 Oct 23 '20 at 08:43
  • I guess I have to find another way after all as you suggest, and work on my algorithms – rrz0 Oct 23 '20 at 08:43
  • 1
    @rrz0 I've added a suggestion, namely maintaining a binary search tree that can be searched for intersections very quickly. – isnot2bad Oct 23 '20 at 08:48