0

I have different scenarios in my model, and in each scenario some road segments (edges) of the road network (Graph) is degraded (loses capacity) or disrupted (removed because of total damage). For that reason, I am trying to iterate over a set of edges for each scenario, starting with the original network, and update the network by changing capacity of some of the edges and removing some others. In the beginning I did not use an iterator to iterate over the edges which resulted in "ConcurrentModificationException". Then I changed the code so as to use Iterator, but this time it does not allow me to use remove method with my iterator (edgeIt.remove()). How can I solve this issue? Thanks for your help in advance.

.....

ArrayList<FloydWarshallShortestPaths<Integer, DefaultWeightedEdge>> FWS = new ArrayList<FloydWarshallShortestPaths<Integer, DefaultWeightedEdge>>();
        for(int w=0; w<numOfScenarios; w++){
            FWS.add(w, fr.readData(fileName));
        }

....

//Road Network and Shelters after disruption in Scenarios
        for(int i=1; i<6; i++){
            Iterator<FloydWarshallShortestPaths<Integer, DefaultWeightedEdge>> it = FWS.iterator();
            while(it.hasNext()){
                FloydWarshallShortestPaths<Integer, DefaultWeightedEdge> FWIt = it.next();
                Iterator<DefaultWeightedEdge> edgeIt = FWIt.getGraph().edgeSet().iterator();
                while(edgeIt.hasNext()){
                DefaultWeightedEdge e = edgeIt.next();
                    if(arcRiskZoneIndex[FWIt.getGraph().getEdgeSource(e)][FWIt.getGraph().getEdgeTarget(e)][FWS.indexOf(FWIt)]==i){
                        if(rng.nextDouble()<=arcDisruptProb[FWS.indexOf(FWIt)][i-1]){
                            roadCapS[FWS.get(FWS.indexOf(FWIt)).getGraph().getEdgeSource(e)][FWS.get(FWS.indexOf(FWIt)).getGraph().getEdgeTarget(e)][FWS.indexOf(FWIt)]=(roadCap[FWIt.getGraph().getEdgeSource(e)][FWIt.getGraph().getEdgeTarget(e)]*10000-rng.nextInt(((int) (10000*roadCap[FWIt.getGraph().getEdgeSource(e)][FWIt.getGraph().getEdgeTarget(e)]/2000))+1)*2000)/10000;
                            if(roadCapS[FWIt.getGraph().getEdgeSource(e)][FWIt.getGraph().getEdgeTarget(e)][FWS.indexOf(FWIt)]==0.0){
                                **edgeIt.remove()**;
                            }
                        }
                    }
                }
                for(int s:setOfFacilityNodesDummy){
                    if(shelterRiskZoneIndex[s][FWS.indexOf(FWIt)]==i){
                        if(rng.nextDouble()<=shelterDisruptProb[FWS.indexOf(FWIt)][i-1]){
                            setOfFacilityNodesS.get(FWS.indexOf(FWIt)).remove(s);
                        }
                    }
                }
            }
        }
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 2
    What's an `edgeSet()`? – Dave Newton Aug 15 '14 at 12:18
  • The set of edges in the graph. – Vedat BAYRAM Aug 15 '14 at 12:19
  • 1
    possible duplicate of [How to avoid "ConcurrentModificationException" while removing elements from \`ArrayList\` while iterating it?](http://stackoverflow.com/questions/18448671/how-to-avoid-concurrentmodificationexception-while-removing-elements-from-arr) – DavidPostill Aug 15 '14 at 12:20
  • The Iterator does not support removal, hence the UnsupportedOperationException. Can you post the original code as well, so we can debug that? THe issue MIGHT be that you used the List.remove(Object) which runs through the list behind the scenes, thus throwing ConcurrentModificationException. Removing by index would solve that issue. – Martin Nielsen Aug 15 '14 at 12:21
  • @VedatBAYRAM ... What *type* is it? Obviously it's a set of edges. That provides no information with which anyone can diagnose the problem. In order to diagnose why the iterator won't let you remove an object from the set we need to know more about the set and its iterator. – Dave Newton Aug 15 '14 at 12:21
  • To be more specific, what does `edgeSet()` return? Does it say anything about the result being an unmodifiable or immutable set? Because in that case, `remove` should indeed throw `UnsupportedOperationException` and you won't be able to remove edges during iteration like this. – Mattias Buelens Aug 15 '14 at 12:22
  • It is actually a Set – Vedat BAYRAM Aug 15 '14 at 12:22
  • @DavidPostill Except that's not the exception that's happening. – Dave Newton Aug 15 '14 at 12:22
  • @VedatBAYRAM Not enough information: a `Set` is an interface, it says nothing about the implementation. – Dave Newton Aug 15 '14 at 12:22
  • From: http://docs.oracle.com/javase/7/docs/api/java/util/Iterator.html#remove() UnsupportedOperationException - if the remove operation is not supported by this iterator – trappski Aug 15 '14 at 12:23
  • slightly off-topic, but I think SO should also offer help for general guidance: Your code severely looks maintainability, it is very hard to read. This one lines is just ridiculously long and should be split up. I am sure it is not that complex, but it is nearly impossible to process where one parenthesis is closed and another is opened. – dirkk Aug 15 '14 at 12:48

2 Answers2

2

Most likely the Collection returned by edgeSet() simply doesn't support the remove() operation, or it does support remove(), yet its Iterator does not.

To get around this (and the ConcurrentModificationException), you'll have to collect the edges you want removed in a seperate Set, and after you're done iterating, remove them through the proper API of the graph.

bowmore
  • 10,842
  • 1
  • 35
  • 43
1

Okay, I did some googling and apparently you're using the JGraphT library. (Protip: it helps to specify this in your question!) The JavaDoc for Graph.edgeSet() says:

Returns a set of the edges contained in this graph. The set is backed by the graph, so changes to the graph are reflected in the set. If the graph is modified while an iteration over the set is in progress, the results of the iteration are undefined.

Now, this just means that if the edges of the Graph change, then those changes can be seen in the returned Set. Unfortunately, it doesn't say anything about changes in the returned Set causing changes to the edges of the Graph. Seeing that you're getting an UnsupportedOperationException, I would assume Graph does not allow you change the returned Set. The source code of AbstractBaseGraph confirms this assumption:

/**
 * @see Graph#edgeSet()
 */
public Set<E> edgeSet()
{
    if (unmodifiableEdgeSet == null) {
        unmodifiableEdgeSet = Collections.unmodifiableSet(edgeMap.keySet());
    }

    return unmodifiableEdgeSet;
}

edgeSet() returns an unmodifiable view of a Graph's edges. You cannot change the edgeSet directly, you have to use the Graph interface to add/change/remove edges. Additionally, if you are iterating over the edgeSet while you're making these changes, you may run into undefined behavior.

To solve this, I recommend first collecting the edges to be removed while iterating, and then removing them afterwards:

// Collection holding the 'marked' edges
Set<DefaultWeightedEdge> toRemove = new HashSet<>();
Iterator<DefaultWeightedEdge> edgeIt = FWIt.getGraph().edgeSet().iterator();
while (edgeIt.hasNext()){
    DefaultWeightedEdge e = edgeIt.next();
    /* ... */
    if (/* something */) {
         // Mark the edge to be removed
         toRemove.add(e);
    }
}
// Remove the marked edges using the Graph's interface
FWIt.getGraph().removeAllEdges(toRemove);
Mattias Buelens
  • 19,609
  • 4
  • 45
  • 51