This question already has answers here:
Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop
(31 answers)
Closed 5 years ago.
I have a quick question that involves one ArrayList, 2 Iterators, and some nested for loops. Im trying to make a bit of a gravity engine using multiple gravity wells pulling on each other and moving around. To do this, Iv made an ArrayList of these gravity wells, all randomly places on the screen with a random size. Here it is for reference.
for(int i = 0; i < amount; i++){ // makes all
int mass = rand.nextInt(45,65);
int locX = rand.nextInt(50, getWidth()-100);
int locY = rand.nextInt(50, getHeight()-100);
Color cColor = rand.nextColor();
if(mass%8==0){
mass = rand.nextInt(25,35);
}
else if(mass%7==0){
mass = rand.nextInt(75,85);
}
Body body = new Body((double)locX,(double)locY,mass);
body.setFilled(true);
body.setColor(Color.WHITE);
body.setFillColor(cColor);
add(body);
bodys.add(body);
}
bodys is the name of the ArrayList containing everything. So my real problem comes to the Iterators. Heres the code thats giving me trouble:
public void move(){
Iterator<Body> eIter = bodys.iterator();
while(eIter.hasNext()){ // finding the thing we edit
Body edit = eIter.next();
int addX = 0, addY = 0;
int totalX = 0, totalY = 0;
double ex = edit.getX(), ey = edit.getY();
double eMass = edit.getMass(), eSize = edit.getHeight();
double eMoveX = edit.getMoveX(), eMoveY = edit.getMoveY();
int placeInArrayEdit = bodys.indexOf(edit);
Iterator<Body> fIter = bodys.iterator();
while(fIter.hasNext()){ // iterating through the force pulling the edit body
Body force = fIter.next(); /// ConcurrentModificationException is thrown
int placeInArrayForce = bodys.indexOf(force);
if(placeInArrayForce != placeInArrayEdit){ // making sure the 2 bodys arent the same
double fx = force.getX(), fy = force.getY();
double fMass = force.getMass();
double fMoveX = force.getMoveX(), fMoveY = force.getMoveY();
double difX = (ex-fx);
double difY = (ey-fy);
double distX = distanceP(ex, fx);
double distY = distanceP(ey, fy);
double vecX = (difX/distX);
double vecY = (difY/distY);
if(distance(fx,ex,fy,ey) <= eSize/3){ // if they are colliding
if(eMass >= fMass){
remove(edit);
edit.addMass((int)(fMass));
eIter.remove(); // problem
}
if(eMass < fMass){
remove(force);
force.addMass((int)(eMass));
fIter.remove();
}
}
double grav = (eMass/fMass);
grav -= (grav*.50);
addX -= (vecX/grav)/2; // this determines movement which means i
addY -= (vecY/grav)/2; // need to edit this with fMass
}
edit.setVelX(addX/(eMass + (eMass*.75)));
edit.setVelY(addY/(eMass + (eMass*.75)));
edit.addMoveX(edit.getVelX());
edit.addMoveY(edit.getVelY());
edit.move(edit.getMoveX(),edit.getMoveY());
}
}
}
The code above is moving the gravity wells and testing for collision. The problem is that ConcurrentModificationException is thrown where iv commented it to be thrown.
Iv spent about an hour or so looking around for a solution and nothing iv tried has worked. The code works up until the wells actually hit each other, then the error is thrown. Is there a way to avoid this error while still testing for collision like this, or is my code just too broken?
Thanks for all the help! Please let me know if you need anything clarified as this is my first question on StackOverflow
See javadoc of ArrayList:
The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.
So, you have 2 iterators: eIter for the outer loop, and fIter for the inner loop.
When you call eIter.remove(), fIter will go bad.
When you call fIter.remove(), eIter will go bad.
(If you had called bodys.remove(index), both would go bad.)
Either way, one of the iterators will be stale, and will throw ConcurrentModificationException when you call next().
Also, when you call eIter.remove(), you don't break out of the inner loop, so you run the risk of trying to do it again in another iteration of the inner loop.
In short, you need to find another way, e.g. using indexes and get(index) calls, or something like that.
Related
I have a set of points on the map. I'm trying to create clusters. Along with the distance, I'm considering the maximum cost (as another parameter) of the each cluster.
Please find the below code snippet.
private void assignCluster(List<Cluster> finalClusters, List<Node> clusterNodes, int maxCostLimit) {
double max = Double.MAX_VALUE;
double min = max;
int clusterIndex = 0;
double distance = 0.0;
for (Node node : clusterNodes) {
min = max;
for (int i = 0; i < finalClusters.size(); i++) {
Cluster cluster = finalClusters.get(i);
distance = Point.getDistanceBetweenPoints(node.getPoint(), cluster.getPoint());
if (distance < min && (cluster.getTotalCost() + node.getCost()) <= maxCostLimit) {
min = distance;
clusterIndex = i;
}
}
if (min != max) {
Cluster cluster = finalClusters.get(clusterIndex);
cluster.setTotalCost(cluster.getTotalCost() + node.getCost());
cluster.addClusterNode(node);
}
}
}
If I try to create clusters, it is going to infinite loop. Alternatively, two points on the map are getting assigned to the two different clusters. In each iteration, the centroids of these two clusters are changing.
Please suggest me, How can I achieve this?
EDITS
Cluster.java
public class Cluster{
private List<Node> clusterNodes = new ArrayList<Node>();
private Integer totalCost = 0;
private Point2D point;
//getters and setters
}
Point.java
public class Point{
private double x = 0;
private double y = 0;
// getters and setters
//method to find the distance between 2 points
}
I'm referring this link for basic Kmeans Algorithm : http://www.dataonfocus.com/k-means-clustering-java-code/
Normally, the K-means algorithm can be shown to never repeat an assignment of nodes to clusters from a previous iteration.
Maybe this is possible in your case, due to the extra constraint of costs that you have introduced that is traditionally not present when using K-means, but maybe it still isn't, I'm not sure.
I am wondering about how you are using this assignCluster() method for which you have provided the code. Do you have another loop around it which keeps calling assignCluster() with finalClusters = a list of the latest assignments of clusters, and clusterNodes = a list of all nodes, and keeps looping until it ends up with an assignment that is equal to the previous one?
If so, are you sure that cluster.addClusterNode() correctly removes the node from its' previous cluster (as I assume it should if you implemented it as described above?). Another thing to look at may be the (cluster.getTotalDemand() + node.getCost()) calculation. I suspect that, if you happen to be looking at the cluster that this node is already in, you may not want to include node.getCost() in that calculation, since it'll be counted double if it's also included in cluster.getTotalDemand().
I had to make some assumptions about what exactly you want the code to do, or how you implemented other methods for which the code is not shown... so you'll have to point out if there are any errors in my assumptions.
Looking at the the code you provided with your question and through the link, I cannot see any reason for an infinite loop (assuming that you adapted the code correctly) except of the possibility, that the total number of clusters multiplied with the maximum cost per cluster is smaller than the total cost of all nodes together. You could check that by iterating over all nodes before entering the loop.
Another problem could be, that you forgot to reset the totalCost per cluster in your clearClusters() method, but I think that would not lead to an infinite loop.
Why is your centroid of class-type Point2D and not an object of your own Point class?
I'm working on a 2D game for android so performance is a real issue and a must. In this game there might occur a lot of collisions between any objects and I don't want to check in bruteforce o(n^2) whether any gameobject collides with another one. In order to reduce the possible amount of collision checks I decided to use spatial hashing as broadphase algorithm becouse it seems quite simple and efficient - dividing the scene on rows and columns and checking collisions between objects residing only in the same grid element.
Here's the basic concept I quickly scratched:
public class SpatialHashGridElement
{
HashSet<GameObject> gameObjects = new HashSet<GameObject>();
}
static final int SPATIAL_HASH_GRID_ROWS = 4;
static final int SPATIAL_HASH_GRID_COLUMNS = 5;
static SpatialHashGridElement[] spatialHashGrid = new SpatialHashGridElement[SPATIAL_HASH_GRID_ROWS * SPATIAL_HASH_GRID_COLUMNS];
void updateGrid()
{
float spatialHashGridElementWidth = screenWidth / SPATIAL_HASH_GRID_COLUMNS;
float spatialHashGridElementHeight = screenHeight / SPATIAL_HASH_GRID_ROWS;
for(SpatialHashGridElement e : spatialHashGrid)
e.gameObjects.clear();
for(GameObject go : displayList)
{
for(int i = 0; i < go.vertices.length/3; i++)
{
int row = (int) Math.abs(((go.vertices[i*3 + 1] / spatialHashGridElementHeight) % SPATIAL_HASH_GRID_ROWS));
int col = (int) Math.abs(((go.vertices[i*3 + 0] / spatialHashGridElementWidth) % SPATIAL_HASH_GRID_COLUMNS));
if(!spatialHashGrid[row * SPATIAL_HASH_GRID_COLUMNS + col].gameObjects.contains(go))
spatialHashGrid[row * SPATIAL_HASH_GRID_COLUMNS + col].gameObjects.add(go);
}
}
}
The code isn't probably of the highest quality so if you spot anything to improve please don't hesitate to tell me but the most worrying problem that arises currently is that in 2 grid cells there might be same collision pairs checked. Worst case example (assuming none of the objects spans more than 2 cells):
Here we have 2 gameObjects colliding(red and blue). Each of them resides in 4 cells => therefore in each cell there will be the same pair to check.
I can't come up with some efficient approach to remove the possibility of duplicate pairs without a need to filter the grid after creating it in updateGrid(). Is there some brilliant way to detect that some collision pair has been already inserted even during the updateGrid function? I will be very grateful for any tips!
I'm trying to explain my idea using some pseudo-code (C# language elements):
public partial class GameObject {
// ...
Set<GameObject> collidedSinceLastTick = new HashSet<GameObject>();
public boolean collidesWith(GameObject other) {
if (collidedSinceLastTick.contains(other)) {
return true; // or even false, see below
}
boolean collided = false;
// TODO: your costly logic here
if (collided) {
collidedSinceLastTick.add(other);
// maybe return false if other actions depend on a GameObject just colliding once per tick
}
return collided;
}
// ...
}
HashSet and .hashCode() both can be tuned in some cases. Maybe you could even remove displayList and "hold" everything in spatialHashGrid to reduce the memory foot-print a little bit. Of course do that only if you don't need special access to displayList - in XML's DocumentObjectModel objects can be accessed by a path throught the tree, and "hot spots" can be accessed by ID where the ID has to be assigned explicitely. For serializing (saving game state or whatever) it should not be an issue to iterate through spatialHashGrid performance-wise (it's a bit slower than serializing the gameObject set because you may have to suppress duplicates - using Java serialization it even does not save the same object twice using the default settings, saving just a reference after the first occurence of an object).
for some reason in my ray tracer if I try to limit the number of recursive calls in my ray tracer my reflectance doesn't work.
Here is my reflectance code:
public static int recursionLevel;
public int maxRecursionLevel;
public Colour shade(Intersection intersection, ArrayList<Light> lights, Ray incidenceRay) {
recursionLevel++;
if(recursionLevel<maxRecursionLevel){
Vector3D reflectedDirection = incidenceRay.direction.subtractNormal(intersection.normal.multiply(2).multiply(incidenceRay.direction.dot(intersection.normal)));
Ray reflectiveRay = new Ray(intersection.point, reflectedDirection);
double min = Double.MAX_VALUE;
Colour tempColour = new Colour();
for(int i = 0; i<RayTracer.world.worldObjects.size(); i++){
Intersection reflectiveRayIntersection = RayTracer.world.worldObjects.get(i).intersect(reflectiveRay);
if (reflectiveRayIntersection != null && reflectiveRayIntersection.distance<min){
min = reflectiveRayIntersection.distance;
recursionLevel++;
tempColour = RayTracer.world.worldObjects.get(i).material.shade(reflectiveRayIntersection, lights, reflectiveRay);
recursionLevel--;
}
}
return tempColour;
}else{
return new Colour(1.0f,1.0f,1.0f);
}
}
If I get rid of the if statement it works, though I run out of memory if I place too many reflective objects. I'm not sure what could be causing this.
The problem is that you're using recursionLevel as global state, but it really should be local state. Also, with every recursive call to shade(), you're incrementing it twice and only decrementing it once. I would refactor your code as follows:
Delete the recursionLevel global
Add a recursionLevel parameter to your shade() method
Keep your if(recursionLevel < maxRecursionLevel) check
Remove the recursionLevel increments and decrements around the recursive call to shade()
Modify the recursive call to shade() such that it calls shade(..., recursionLevel + 1)
Im having problems with removing items from an arraylist using an iterator. My aim is to retrieve points within a certain radius and cluster them into a set of groups. I am using the initial points as a reference. The code has an initial for loop that will run through each place, then for each place an inner for loop is created to check the radius between the reference place and the rest of places. If the radius between both reference place and other place is less than a threshold i set, it will be added to the arraylist grouped with other similar points. As they are added to groups they will be removed from the original arraylist.
However i am getting problems such as it either only performs the outer for loop once or i get an IllegalStateException.
Here is the code:
HashMap<Place, ArrayList<Place>> sets = new HashMap<Place, ArrayList<Place>>();
private void cluster(ArrayList<Place> places) {
for (Iterator<Place> iterator = places.iterator(); iterator.hasNext();) {
Place pl = iterator.next();
ArrayList<Place> subset = new ArrayList<Place>(); // Group
GeoPoint g = new GeoPoint((int) (pl.getGeometry().getLocation()
.getLat() * 1e6), (int) (pl.getGeometry().getLocation()
.getLng() * 1e6));
Point point = new Point();
mapView.getProjection().toPixels(g, point);
sets.put(pl, subset);
subset.add(pl);
iterator.remove();
for (Iterator<Place> iterator2 = places.iterator(); iterator2
.hasNext();) {
Place pl2 = iterator2.next();
int threshold = 100;
GeoPoint g2 = new GeoPoint((int) (pl2.getGeometry()
.getLocation().getLat() * 1e6), (int) (pl2
.getGeometry().getLocation().getLng() * 1e6));
Point point2 = new Point();
mapView.getProjection().toPixels(g2, point);
int dx = Math.abs(point2.x - point.x);
int dy = Math.abs(point2.y - point.y);
if (dx < threshold && dy < threshold) {
subset.add(pl2);
iterator2.remove();
}
}
}
}
Sorry for the info overload, would really appreciate the help.
Thanks in advance peeps
Rehan
You are stepping the outer iterator inside the inner loop. It looks like these lines might be in error:
for (Iterator<Place> iterator2 = places.iterator(); iterator.hasNext();) {
Place pl2 = iterator.next();
Looks like maybe you copied and pasted without changing the terminating condition in the loop and the following line:
for (Iterator<Place> iterator2 = places.iterator(); iterator2.hasNext();) {
Place pl2 = iterator2.next();
running multiple iterators over the same list isnt allowed. So you will get a concurrentmodification exception. Better make a copy of the array list, in the inner loop update the data in the position of copy where you want to update. In short,change your logic
I guess you gets exception because you change list while iterating it.
At first, I would use for (... in ...) construction.
Second, I think you have to copy places an iterating it, but deleting from places.
Hey guys, recently posted up about a problem with my algorithm.
Finding the numbers from a set which give the minimum amount of waste
Ive amended the code slightly, so it now backtracks to an extent, however the output is still flawed. Ive debugged this considerablychecking all the variable values and cant seem to find out the issue.
Again advice as opposed to an outright solution would be of great help. I think there is only a couple of problems with my code, but i cant work out where.
//from previous post:
Basically a set is passed to this method below, and a length of a bar is also passed in. The solution should output the numbers from the set which give the minimum amount of waste if certain numbers from the set were removed from the bar length. So, bar length 10, set includes 6,1,4, so the solution is 6 and 4, and the wastage is 0. Im having some trouble with the conditions to backtrack though the set. Ive also tried to use a wastage "global" variable to help with the backtracking aspect but to no avail.
SetInt is a manually made set implementation, which can add, remove, check if the set is empty and return the minimum value from the set.
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package recursivebacktracking;
/**
*
* #author User
*/
public class RecBack {
int WASTAGE = 10;
int BESTWASTAGE;
int BARLENGTH = 10;
public void work()
{
int[] nums = {6,1,2,5};
//Order Numbers
SetInt ORDERS = new SetInt(nums.length);
SetInt BESTSET = new SetInt(nums.length);
SetInt SOLUTION = new SetInt(nums.length);
//Set Declarration
for (int item : nums)ORDERS.add(item);
//Populate Set
SetInt result = tryCutting(ORDERS, SOLUTION, BARLENGTH, WASTAGE);
result.printNumbers();
}
public SetInt tryCutting(SetInt possibleOrders, SetInt solution, int lengthleft, int waste)
{
for (int i = 0; i < possibleOrders.numberInSet(); i++) // the repeat
{
int a = possibleOrders.min(); //select next candidate
System.out.println(a);
if (a <= lengthleft) //if accecptable
{
solution.add(a); //record candidate
lengthleft -= a;
WASTAGE = lengthleft;
possibleOrders.remove(a); //remove from original set
if (!possibleOrders.isEmpty()) //solution not complete
{
System.out.println("this time");
tryCutting(possibleOrders, solution, lengthleft, waste);//try recursive call
BESTWASTAGE = WASTAGE;
if ( BESTWASTAGE <= WASTAGE )//if not successfull
{
lengthleft += a;
solution.remove(a);
System.out.println("never happens");
}
} //solution not complete
}
} //for loop
return solution;
}
}
Instead of using backtracking, have you considered using a bitmask algorithm instead? I think it would make your algorithm much simpler.
Here's an outline of how you would do this:
Let N be number of elements in your set. So if the set is {6,1,2,5} then N would be 4. Let max_waste be the maximum waste we can eliminate (10 in your example).
int best = 0; // the best result so far
for (int mask = 1; mask <= (1<<N)-1; ++mask) {
// loop over each bit in the mask to see if it's set and add to the sum
int sm = 0;
for (int j = 0; j < N; ++j) {
if ( ((1<<j)&mask) != 0) {
// the bit is set, add this amount to the total
sm += your_set[j];
// possible optimization: if sm is greater than max waste, then break
// out of loop since there's no need to continue
}
}
// if sm <= max_waste, then see if this result produces a better one
// that our current best, and store accordingly
if (sm <= max_waste) {
best = max(max_waste - sm);
}
}
This algorithm is very similar to backtracking and has similar complexity, it just doesn't use recursion.
The bitmask basically is a binary representation where 1 indicates that we use the item in the set, and 0 means we don't. Since we are looping from 1 to (1<<N)-1, we are considering all possible subsets of the given items.
Note that running time of this algorithm increases very quickly as N gets larger, but with N <= around 20 it should be ok. The same limitation applies with backtracking, by the way. If you need faster performance, you'd need to consider another technique like dynamic programming.
For the backtracking, you just need to keep track of which element in the set you are on, and you either try to use the element or not use it. If you use it, you add it to your total, and if not, you proceeed to the next recursive call without increasing your total. Then, you decrement the total (if you incremented it), which is where the backtracking comes in.
It's very similar to the bitmask approach above, and I provided the bitmask solution to help give you a better understanding of how the backtracking algorithm would work.
EDIT
OK, I didn't realize you were required to use recursion.
Hint1
First, I think you can simplify your code considerably by just using a single recursive function and putting the logic in that function. There's no need to build all the sets ahead of time then process them (I'm not totally sure that's what you're doing but it seems that way from your code). You can just build the sets and then keep track of where you are in the set. When you get to the end of the set, see if your result is better.
Hint2
If you still need more hints, try to think of what your backtracking function should be doing. What are the terminating conditions? When we reach the terminating condition, what do we need to record (e.g. did we get a new best result, etc.)?
Hint3
Spoiler Alert
Below is a C++ implementation to give you some ideas, so stop reading here if you want to work on it some more by yourself.
int bestDiff = 999999999;
int N;
vector< int > cur_items;
int cur_tot = 0;
int items[] = {6,1,2,5};
vector< int > best_items;
int max_waste;
void go(int at) {
if (cur_tot > max_waste)
// we've exceeded max_waste, so no need to continue
return;
if (at == N) {
// we're at the end of the input, see if we got a better result and
// if so, record it
if (max_waste - cur_tot < bestDiff) {
bestDiff = max_waste - cur_tot;
best_items = cur_items;
}
return;
}
// use this item
cur_items.push_back(items[at]);
cur_tot += items[at];
go(at+1);
// here's the backtracking part
cur_tot -= items[at];
cur_items.pop_back();
// don't use this item
go(at+1);
}
int main() {
// 4 items in the set, so N is 4
N=4;
// maximum waste we can eliminiate is 10
max_waste = 10;
// call the backtracking algo
go(0);
// output the results
cout<<"bestDiff = "<<bestDiff<<endl;
cout<<"The items are:"<<endl;
for (int i = 0; i < best_items.size(); ++i) {
cout<<best_items[i]<<" ";
}
return 0;
}