Mega Code Archive

 
Categories / Java / 2D Graphics GUI
 

An undirected graph that keeps track of connected components (groups)

/**  * Copyright (c) 2008-2010  Morten Silcowitz.  *  * This file is part of the Jinngine physics library  *  * Jinngine is published under the GPL license, available   * at http://www.gnu.org/copyleft/gpl.html.   */ //package jinngine.util; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Queue; import java.util.Set; /**  * An undirected graph that keeps track of connected components (groups). Each  * time an edge is added or removed from the graph, data structures are  * maintained, reflecting connected components in the graph. This means, that  * adding edges are roughly an O(k) operation, while removing an edge could i  * result in a total traversal of the graph, visiting all present edges, worst  * case O((n-1)^2) where n is the number of nodes. Usually this will be much  * cheaper, given that the graph has a low density, and is fragmented into  * separated components.  *   * @param <T>  *            Type that stores in nodes  * @param <U>  *            Type that stores in edges  */ public class HashMapComponentGraph<T, U, V> implements ComponentGraph<T, U, V> {   // wrapping classes   private final class Node {     public Node(T element) {       this.element = element;     }     public final T element;     public int color;     public final int hashCode() {       return element.hashCode();     }     public final boolean equals(Object other) {       return element.equals(((Node) other).element);     }   }   // component wrapper class for the type V.   private final class Component {     private final V element;     public Component(V element) {       this.element = element;     }     public final int hashCode() {       return element.hashCode();     }     public final boolean equals(Object other) {       return element.equals(((Component) other).element);     }   }   // /**   // * Node classifier for the ContactGraph   // *   // * @param <T> Type that stores in nodes   // */   // public interface NodeClassifier<T> {   // /**   // * @param node Node to classify   // * @return true if the node is to be considered as a delimiting node, such   // that two   // * components in some graph, would not be merged if connected through such   // a node. Returns false otherwise.   // */   // public boolean isDelimitor(final T node);   // }   // this would ideally be a Set, but the HashSet implementation doesn't allow   // one to get the   // actual reference to a specific object in the set. This means that we   // can't keep our Node objects   // unique, which we would like to do   private final LinkedHashMap<Node, Node> allnodes = new LinkedHashMap<Node, Node>();   private final LinkedHashSet<Node> freenodes = new LinkedHashSet<Node>();//   private final Map<Node, Set<Node>> edges = new LinkedHashMap<Node, Set<Node>>();   private final Map<Node, Component> component = new LinkedHashMap<Node, Component>();   private final Map<Pair<T>, U> edgeData = new LinkedHashMap<Pair<T>, U>();//   private final Map<Component, Set<Node>> componentNodes = new LinkedHashMap<Component, Set<Node>>();//   private final Map<Component, Set<Pair<T>>> componentEdges = new LinkedHashMap<Component, Set<Pair<T>>>();//   private final NodeClassifier<T> nodeClassifier;   // TODO the nodes map is not cleaned up, nodes that are removed still   // remains in here   // default component creator   private final ComponentHandler<T, V> componenthandler;   // = new ComponentHandler<V>() {   // public V newComponent() {   // return null;   // };   // };   // /**   // * Create a new component graph   // * @param nodeClassifier a classifier for the type T, used for the   // connected components analysis   // */   // public HashMapComponentGraph( NodeClassifier<T> nodeClassifier ) {   // this.nodeClassifier = nodeClassifier;   // }   /**    * Create a new component graph    *     * @param nodeClassifier    *            a classifier for the type T, used for the connected components    *            analysis    * @param componetcreator    *            a creator for new components that arrise inside the component    *            graph    */   public HashMapComponentGraph(NodeClassifier<T> nodeClassifier,       ComponentHandler<T, V> componentcreator) {     this.componenthandler = componentcreator;     this.nodeClassifier = nodeClassifier;   }   /**    * Add an edge to the graph, and implicitly add included end-nodes if not    * already present in the graph. This is roughly an O(k) and sometimes    * O(nodes) operation, depending on whether components are to be merged or    * not.    *     * @param pair    *            A pair of nodes, where an edge is to be added between them.    * @param edgeelement    *            An element of type U to store in the new edge    */   @Override   public final void addEdge(Pair<T> pair, U edgeelement) {     // do not act if edge is already present     if (edgeData.containsKey(pair)) {       // update the edge data user reference       edgeData.put(pair, edgeelement);       // System.out.println("Edge already present");       return;     }     // add the new edge data to the edge     edgeData.put(pair, edgeelement);     // get nodes from the node tables ( in this way we can keep data other     // than T in the Node objects)     // if the nodes are not present, we add them to the allnodes and to     // freenodes     Node a = new Node(pair.getFirst());     if (allnodes.containsKey(a)) {       a = allnodes.get(a);     } else {       allnodes.put(a, a);       freenodes.add(a);     }     Node b = new Node(pair.getSecond());     if (allnodes.containsKey(b)) {       b = allnodes.get(b);     } else {       allnodes.put(b, b);       freenodes.add(b);     }     // if b is fixed, interchange a and b ( now, if b is fixed, both a and b     // are fixed)     if (nodeClassifier.isDelimitor(b.element)) {       Node t = a;       a = b;       b = t;     }     // add edge to nodes. First create hash sets, and then add the nodes to     // them     if (!edges.containsKey(a))       edges.put(a, new LinkedHashSet<Node>());     if (!edges.containsKey(b))       edges.put(b, new LinkedHashSet<Node>());     edges.get(b).add(a);     edges.get(a).add(b);     // Cases     // i. Both nodes are delimiters     // a) do nothing     // ii. One node is delimiter:     // a). non-delimiter is in a component     // do nothing     // b). non-delimiter is not in a component     // create a new component for the non-delimiter node     // iii. No node is delimiter:     // a). no node is in a component     // create a new component for both nodes     // b). one node is in a component     // add the new node to this component     // c). both nodes are in a component     // 1. the same component     // do nothing     // 2. different components     // merge the one component into the other     // case i a)     // both a and b are delimitors     if (nodeClassifier.isDelimitor(b.element)) {       // do nothing       // ii)       // one is delimiter     } else if (nodeClassifier.isDelimitor(a.element)) {       // if b is not in a group, create a new one for b       if (!component.containsKey(b)) {         // case ii b)         Component g = new Component(componenthandler.newComponent());         // add b to the new group         component.put(b, g);         componentNodes.put(g, new LinkedHashSet<Node>());         componentNodes.get(g).add(b);         // notify handler         componenthandler.nodeAddedToComponent(g.element, b.element);         // b is not a free node anymore         freenodes.remove(b);         // add to pairs         componentEdges.put(g, new LinkedHashSet<Pair<T>>());         componentEdges.get(g).add(pair);         // return;       } else {         // case ii a)         // add to pairs         Component g = component.get(b);         componentEdges.get(g).add(pair);       }       // non of the bodies are delimiters     } else {       // if b is in a group, interchange a and b       // ( now, if b is in a group, both a and b are grouped)       if (component.containsKey(b)) {         Node t = a;         a = b;         b = t;       }       // both in components       if (component.containsKey(b)) {         // same component         if (component.get(a) == component.get(b)) {           // do nothing           // add edge to this component           componentEdges.get(component.get(a)).add(pair);           // different components         } else {           // two nodes from two different components was connected.           // we then merge the two components into one           // merge groups (remove the gb group)           Component ga = component.get(a);           Component gb = component.get(b);           // call the user handler to say we are merging gb into ga           componenthandler.mergeComponent(ga.element, gb.element);           // update the component table, i.e. update bodies that was           // tied to component gb, to ga           Iterator<Node> i = componentNodes.get(gb).iterator();           while (i.hasNext()) {             Node body = i.next();             component.put(body, ga);           }           // put nodes in group b into group a           componentNodes.get(ga).addAll(componentNodes.get(gb));           componentEdges.get(ga).addAll(componentEdges.get(gb));           // also, add the new edge (pair)           componentEdges.get(ga).add(pair);           // remove the gb component from the component table           componentNodes.remove(gb);           componentEdges.remove(gb);           // return;         }         // one group       } else if (component.containsKey(a)) {         // assign b to the group of a         Component g = component.get(a);         component.put(b, g);         componentNodes.get(g).add(b);         componentEdges.get(g).add(pair);         // b is not a free node anymore         freenodes.remove(b);         // notify handler that b is added to the group of a         componenthandler.nodeAddedToComponent(g.element, b.element);         // return;         // no groups       } else {         // create a new component for both bodies         Component newGroup = new Component(             componenthandler.newComponent());         component.put(a, newGroup);         component.put(b, newGroup);         componentNodes.put(newGroup, new LinkedHashSet<Node>());         componentNodes.get(newGroup).add(a);         componentNodes.get(newGroup).add(b);         // notify handler that a and b is added to the new component         componenthandler.nodeAddedToComponent(newGroup.element,             a.element);         componenthandler.nodeAddedToComponent(newGroup.element,             b.element);         componentEdges.put(newGroup, new LinkedHashSet<Pair<T>>());         componentEdges.get(newGroup).add(pair);         // both a and b are not free now         freenodes.remove(a);         freenodes.remove(b);         // return;       }     }     // // System.out.println("After add: " + groups.keySet().size() +     // " groups with " + group.size() + " bodies" );     // Iterator<Component> groupiter = componentNodes.keySet().iterator();     //     // Set<Pair<T>> allpairs = new HashSet<Pair<T>>();     // Set<Node> allnodes = new HashSet<Node>();     // while(groupiter.hasNext()){     // Component g = groupiter.next();     // //System.out.println( "Group " + g + " : " + groupPairs.get(g).size()     // + " pairs " );     //     // Iterator<Pair<T>> pairiter = componentEdges.get(g).iterator();     // while (pairiter.hasNext()) {     // Pair<T> thispair = pairiter.next();     // //System.out.println( "    pair:"+thispair.hashCode());     // if (allpairs.contains(thispair)) {     // System.out.println("Duplicates!!!!");     // System.exit(0);     // }     // allpairs.add(thispair);     //     // }     //     //     // Iterator<Node> nodeiter = componentNodes.get(g).iterator();     // while (nodeiter.hasNext()) {     // Node node = nodeiter.next();     // //System.out.println( "     Node:"+node);     // if (allnodes.contains(node)) {     // System.out.println("Duplicates!!!!");     // System.exit(0);     // }     // allnodes.add(node);     //     // }     //     //     //     // }   }   /**    * Remove an edge. If the removal results in one or more isolated nodes,    * these will be removed from the graph implicitly.    *     * For non-dense and relatively fragmented graphs, this operation will be    * cheap. Otherwise, for dense and strongly connected graphs, the operation    * could include a full traversal of the graph visiting all present edges,    * resulting in an O((n-1)^2) operation, where n is the number of nodes in    * the graph.    *     * @param pair    *            edge to be removed    * @return true if the edge was actually removed, false if the edge did not    *         exists before call.    */   @Override   public final boolean removeEdge(Pair<T> pair) {     // don't act if edge is not present     if (!edgeData.containsKey(pair)) {       // System.out.println("Edge NOT present");       return false;     } else {       edgeData.remove(pair);     }     // get the node out of the node adjacency hash map ( at this point we     // know that the nodes must     // exist, because the edge exists     Node a = new Node(pair.getFirst());     if (allnodes.containsKey(a)) {       a = allnodes.get(a);     } else {       // not possible       throw new IllegalStateException(           "ComponentGraph.removeEdge(): Node did not have an adjacency entry. ComponentGraph corrupted.");     }     Node b = new Node(pair.getSecond());     if (allnodes.containsKey(b)) {       b = allnodes.get(b);     } else {       // this is not possible       throw new IllegalStateException(           "ComponentGraph.removeEdge(): Node did not have an adjacency entry. ComponentGraph corrupted.");     }     // if b is fixed, interchange a and b ( now, if b is fixed, both a and b     // are fixed)     if (nodeClassifier.isDelimitor(b.element)) {       Node t = a;       a = b;       b = t;     }     // remove references to each node, in each nodes     // connected node sets     edges.get(a).remove(b);     edges.get(b).remove(a);     // if no edges left in set, remove the set     if (edges.get(a).isEmpty())       edges.remove(a);     // if no edges left in set, remove it     if (edges.get(b).isEmpty())       edges.remove(b);     // Cases     // i. Both node are delimiters     // do nothing     // ii. One node is delimiter:     // a). non-delimiter is in a component     // do nothing (node could now be alone in its component)     // if node contains no other edges, delete it from its component     // b). non-delimiter is not in a component (not possible)     // do nothing/ report fatal error     // iii. No node is delimiter:     // a). no node is in a component (not possible)     // do nothing/ error     // b). one node is in a component (not possible)     // do nothing     // c). both nodes are in a component     // 1. the same component     // remove edge, traverse breadth-first from each node to determine     // if component should be split.     // 2. different components (not possible)     // do nothing/ error     // both nodes are fixed     if (nodeClassifier.isDelimitor(b.element)) {       // do nothing       // return;       // one is fixed     } else if (nodeClassifier.isDelimitor(a.element)) {       if (component.containsKey(b)) { // only possible option         // System.out.println("One fixed node");         Component g = component.get(b);         // check for another edge on this node         if (!edges.containsKey(b)) {           // System.out.println("b did not have any edges");           // remove the node from component           component.remove(b);           // notify handler           componenthandler.nodeRemovedFromComponent(g.element,               b.element);           // b is now free           freenodes.add(b);           Set<Node> s = componentNodes.get(g);           if (!s.remove(b)) {             System.out.println("ALARM");             System.exit(0);           }           // remove group if empty           if (s.isEmpty()) {             // System.out.println("groups entry removed");             componentNodes.remove(g);             // TODO notify handler           } else {             System.out.println("Group isn't empty, why??");             // System.exit(0);           }         } else {           // b has edges left, and is part of a group. Were done         }         // remove edge from component (even if b was not removed from         // the group)         Set<Pair<T>> sp = componentEdges.get(g);         sp.remove(pair);         // remove group if empty         if (sp.isEmpty()) {           // System.out.println("grouppair entry removed " + g );           componentEdges.remove(g);         }       } else {         throw new IllegalStateException(             "HashMapComponentGraph.removeEdge(): A connected non-delimiter node was not in a component. ComponentGraph corrupted.");       }       // return;       // none is fixed     } else {       // if b has edges, interchange a and b       // ( now, if b has edges, both a and b have edges)       if (edges.containsKey(b)) {         Node t = a;         a = b;         b = t;       }       // both are in the same group (only possible option)       Component oldgroup = component.get(a);       if (oldgroup != component.get(b)) {         System.out.println("Different groups??!");         System.exit(0);       }       // both have edges       if (edges.containsKey(b)) {         final int NONE = 0;         final int RED = 1;         final int BLUE = 2;         // clear node colors in entire group         Iterator<Node> i = componentNodes.get(oldgroup).iterator();         while (i.hasNext()) {           i.next().color = NONE;         }         // perform breadth-first traversal,         // to determine if group has become disjoint         boolean disjoint = true;         Queue<Node> queue = new LinkedList<Node>();         Set<Pair<T>> blueEdges = new LinkedHashSet<Pair<T>>();         a.color = RED;         b.color = BLUE;         queue.add(a);         queue.add(b);         // traverse         while (!queue.isEmpty()) {           Node node = queue.poll();           // add nodes neighbors to queue           Iterator<Node> neighbors = edges.get(node).iterator();           while (neighbors.hasNext()) {             Node neighbor = neighbors.next();             // remember visited edges             if (node.color == BLUE)               blueEdges.add(new Pair<T>(node.element,                   neighbor.element));             if (nodeClassifier.isDelimitor(neighbor.element)) {               // ignore fixed nodes               continue;             } else if (neighbor.color == NONE) {               neighbor.color = node.color;               queue.add(neighbor);               continue;             } else if (neighbor.color != node.color) {               // group is connected               disjoint = false;               break;             } else {               // already visited               continue;             }           } // while neighbors         } // while queue         // handle result of traversal         if (disjoint) {           // System.out.println("Splitting group");           // new group           Component newgroup = new Component(               componenthandler.newComponent());           Set<Node> blues = new LinkedHashSet<Node>();           // find all blue nodes           Iterator<Node> iter = componentNodes.get(oldgroup)               .iterator();           while (iter.hasNext()) {             Node node = iter.next();             if (node.color == BLUE) {               blues.add(node);               component.put(node, newgroup);             }           }           // impossible           if (blues.isEmpty()) {             System.out.println("Why was no blue nodes found?");             System.exit(0);           }           // remove bodies from old components and add the new           // component           componentNodes.get(oldgroup).removeAll(blues);           componentNodes.put(newgroup, blues);           // remove blue edges from the red group and create a new           // group with pairs (ng)           componentEdges.get(oldgroup).removeAll(blueEdges);           componentEdges.get(oldgroup).remove(pair); // the edge that                                 // was to be                                 // removed           componentEdges.put(newgroup, blueEdges);           // return;         } else {           // System.out.println("Group still connected");           // we keep group as it is, but remove the pair (edge)           Set<Pair<T>> sp = componentEdges.get(oldgroup);           sp.remove(pair);           // remove group if empty           if (sp.isEmpty()) {             // System.out.println("grouppair entry removed " +             // oldgroup );             componentEdges.remove(oldgroup);           }           // return;         }         // a has an edge and b do not       } else if (edges.containsKey(a)) {         // keep group as it is, but wipe out b         component.remove(b);         componentNodes.get(oldgroup).remove(b);         // b is now a free node         freenodes.add(b);         // notify handler that b is removed from oldgroup         componenthandler.nodeRemovedFromComponent(oldgroup.element,             b.element);         if (componentNodes.get(oldgroup).isEmpty()) { // never happens           System.out.println("How can group be empty?");           componentNodes.remove(oldgroup);         }         // remove from pairs         // System.out.println("removing " + pair +" from group pairs " +         // oldgroup);         Set<Pair<T>> sp = componentEdges.get(oldgroup);         sp.remove(pair);         // remove group if empty         if (sp.isEmpty()) {           // System.out.println("grouppair entry removed " + oldgroup           // );           componentEdges.remove(oldgroup);         }         // non have edges       } else {         // clear out group entirely         component.remove(a);         component.remove(b);         // both a and b are free nodes now         freenodes.add(a);         freenodes.add(b);         // notify handler that a and b is removed         componenthandler.nodeRemovedFromComponent(oldgroup.element,             a.element);         componenthandler.nodeRemovedFromComponent(oldgroup.element,             b.element);         // assume that the group is only containing a and b?         componentNodes.get(oldgroup).remove(b);         componentNodes.get(oldgroup).remove(a);         if (componentNodes.get(oldgroup).isEmpty()) {           componentNodes.remove(oldgroup);         } else { // impossible           System.out               .println("Hmm still stuff in group but no outgoing edges?"                   + componentNodes.get(oldgroup)                   + " a and b is " + a + ",    " + b);           System.exit(0);         }         // remove from pairs         Set<Pair<T>> sp = componentEdges.get(oldgroup);         sp.remove(pair);         // remove group if empty         if (sp.isEmpty()) {           // System.out.println("grouppair entry removed " + oldgroup           // );           componentEdges.remove(oldgroup);         }       }// non have edges     } // none is fixed     // System.out.println("After remove: " + groups.keySet().size() +     // " groups with " + group.size() + " bodies" );     // Iterator<Component<V>> groupiter =     // componentNodes.keySet().iterator();     //     // Set<Pair<T>> allpairs = new HashSet<Pair<T>>();     // Set<Node> allnodes = new HashSet<Node>();     // while(groupiter.hasNext()){     // Component<V> g = groupiter.next();     // //System.out.println( "Group " + g + " : " + groupPairs.get(g).size()     // + " pairs " );     //     // Iterator<Pair<T>> pairiter = componentEdges.get(g).iterator();     // while (pairiter.hasNext()) {     // Pair<T> thispair = pairiter.next();     // //System.out.println( "    pair:"+thispair.hashCode());     // if (allpairs.contains(thispair)) {     // System.out.println("Duplicates!!!!");     // System.exit(0);     // }     // allpairs.add(thispair);     //     // }     //     //     // Iterator<Node> nodeiter = componentNodes.get(g).iterator();     // while (nodeiter.hasNext()) {     // Node node = nodeiter.next();     // //System.out.println( "    Node:"+node);     // if (allnodes.contains(node)) {     // System.out.println("Duplicates!!!!");     // System.exit(0);     // }     // allnodes.add(node);     //     // }     //     // }     return true;   }   @Override   public final U getEdge(Pair<T> pair) {     if (edgeData.containsKey(pair)) {       return edgeData.get(pair);     } else {       return null;     }   }   @Override   public final Iterator<V> getComponents() {     // wrapping iterator     return new Iterator<V>() {       private final Iterator<Component> iter = componentEdges.keySet()           .iterator();       public boolean hasNext() {         return iter.hasNext();       }       @Override       public V next() {         return iter.next().element;       }       @Override       public void remove() {         throw new UnsupportedOperationException();       }     };   }   @Override   public final Iterator<U> getEdgesInComponent(V c) {     // get edges from component     final Set<Pair<T>> edges = componentEdges.get(new Component(c));     // abort if the component doesn't exist     if (edges == null)       return null;     // get the edges     final Iterator<Pair<T>> i = edges.iterator();     // create an iterator that wraps the process of picking out the     // edge data types from edgeData     return new Iterator<U>() {       @Override       public boolean hasNext() {         return i.hasNext();       }       @Override       public U next() {         if (i.hasNext()) {           Pair<T> p = i.next();           // return the edge data           return edgeData.get(p);         }         // no element available         return null;       }       @Override       public void remove() {         throw new UnsupportedOperationException();       }     };   }   @Override   public Iterator<T> getNodesInComponent(V c1) {     // get edges from component     final Set<Node> nodes = componentNodes.get(new Component(c1));     // abort if the component doesn't exist     if (nodes == null)       return null;     // get the edges     final Iterator<Node> i = nodes.iterator();     // create an iterator iterates the nodes, but return the T element value     return new Iterator<T>() {       @Override       public boolean hasNext() {         return i.hasNext();       }       @Override       public T next() {         if (i.hasNext()) {           Node p = i.next();           // return the node data           return p.element;         }         // no element available         return null;       }       @Override       public void remove() {         throw new UnsupportedOperationException();       }     };   }   /**    * Auxiliary method to print the graph    */   public final void print() {     System.out.println("Status: " + componentNodes.keySet().size()         + " components with " + component.size() + " bodies, "         + getNumberOfFreeNodes() + " free ");     Iterator<Component> groupiter = componentNodes.keySet().iterator();     Set<Pair<T>> allpairs = new LinkedHashSet<Pair<T>>();     Set<Node> allnodes = new LinkedHashSet<Node>();     while (groupiter.hasNext()) {       Component g = groupiter.next();       System.out.println("Group " + g.element + " : "           + componentEdges.get(g).size() + " pairs, "           + componentNodes.get(g).size() + " nodes ");       Iterator<Pair<T>> pairiter = componentEdges.get(g).iterator();       while (pairiter.hasNext()) {         Pair<T> thispair = pairiter.next();         // System.out.println( "    pair:"+thispair.hashCode());         if (allpairs.contains(thispair)) {           System.out.println("Duplicates!!!!");           System.exit(0);         }         allpairs.add(thispair);       }       Iterator<Node> nodeiter = componentNodes.get(g).iterator();       while (nodeiter.hasNext()) {         Node node = nodeiter.next();         // System.out.println( "    Node:"+node);         if (allnodes.contains(node)) {           System.out.println("Duplicates!!!!");           System.exit(0);         }         allnodes.add(node);       }     }   }   @Override   public int getNumberOfComponents() {     // return the number of keys in the component-Nodes map     return componentNodes.keySet().size();   }   @Override   public Iterator<T> getConnectedNodes(final T node) {     // create a wrap iterator     return new Iterator<T>() {       Iterator<Node> i = edges.get(new Node(node)).iterator();       @Override       public boolean hasNext() {         return i.hasNext();       }       @Override       public T next() {         return i.next().element;       }       @Override       public void remove() {       }     };   }   public void addNode(T nodeelement) {     // check if we know about this node     Node node = new Node(nodeelement);     if (allnodes.containsKey(node)) {       // ignore. Maybe give warning?       System.out           .println("HashMapComponentGraph.addNode(): Node is already in graph");     } else {       // add to both allnodes and freenodes       allnodes.put(node, node);       freenodes.add(node);     }   }   public void removeNode(T nodeelement) {     Node node = new Node(nodeelement);     // check if node is in freenodes. If so, we don't have to do anything     // but removing the node     // from both freenodes and allnodes     if (freenodes.contains(node)) {       freenodes.remove(node);       allnodes.remove(node);       return;     }     // we now expect node to be part of a component, but we can now simply     // remove all incident     // edges to the node. After that, the node will be placed into     // freenodes, and we can trivially     // remove it     // remove each incident edges. store edges in intermediate list to avoid     // concurrent modification errors     List<Pair<T>> edgesToRemove = new ArrayList<Pair<T>>();     Iterator<T> neighbors = getConnectedNodes(node.element);     while (neighbors.hasNext()) {       Pair<T> nodepair = new Pair<T>(node.element, neighbors.next());       edgesToRemove.add(nodepair);     }     for (Pair<T> edge : edgesToRemove)       removeEdge(edge);     // we can now remove the node     if (freenodes.contains(node)) {       freenodes.remove(node);       allnodes.remove(node);       return;     } else {       System.out           .println("HashMapComponentGraph.removeNode(): Node was not free after removing its edges");     }   }   @Override   public int getNumberOfNodes() {     return allnodes.size();   }   @Override   public int getNumberOfFreeNodes() {     return freenodes.size();   }   @Override   public Iterator<T> getFreeNodes() {     // wrapping iterator     return new Iterator<T>() {       Iterator<Node> i = freenodes.iterator();       @Override       public boolean hasNext() {         return i.hasNext();       }       @Override       public T next() {         return i.next().element;       }       @Override       public void remove() {         throw new UnsupportedOperationException();       }     };   }   @Override   public Iterator<U> getConnectedEdges(final T node) {     if (edges.containsKey(new Node(node))) {       // create a wrap iterator       return new Iterator<U>() {         Set<Node> outEdges = edges.get(new Node(node));         Iterator<Node> i = outEdges.iterator();         @Override         public boolean hasNext() {           return i.hasNext();         }         @Override         public U next() {           // create a edge pair from the node types, and return the           // edge data           return edgeData.get(new Pair<T>(node, i.next().element));         }         @Override         public void remove() {           throw new UnsupportedOperationException();         }       };     } else {       // create a dummy empty iterator       return new Iterator<U>() {         @Override         public boolean hasNext() {           return false;         }         @Override         public U next() {           return null;         }         @Override         public void remove() {           throw new UnsupportedOperationException();         }       };     }   } } /**  * Copyright (c) 2008-2010 Morten Silcowitz.  *   * This file is part of the Jinngine physics library  *   * Jinngine is published under the GPL license, available at  * http://www.gnu.org/copyleft/gpl.html.  */ // package jinngine.util; // import java.util.Iterator; /**  * An undirected graph that keeps track of connected components (groups). Each  * time an edge is added or removed from the graph, data structures are  * maintained, reflecting connected components in the graph. This means, that  * adding edges are roughly an O(k) operation, while removing an edge could i  * result in a total traversal of the graph, visiting all present edges, worst  * case O((n-1)^2) where n is the number of nodes. Usually this will be much  * cheaper, given that the graph has a low density, and is fragmented into  * separated components.  *   * @param <T>  *            Type that stores in nodes  * @param <U>  *            Type that stores in edges  * @param <V>  *            Type that stores in components  */ interface ComponentGraph<T, U, V> {   /**    * Interface for supplying custom component objects. Components are used to    * reference the independently connected components in the graph. It is    * therefore useful to be able to store user information within the    * component references.    */   public interface ComponentHandler<T, V> {     /**      * Called when a new component is created. This call MUST return a      * unique object of type V, that has not been previously known to the      * ComponentGraph      *       * @return a new unique component of type V      */     public V newComponent();     /**      * Called prior to two components being merged. This gives the user a      * way to manipulate data in the component type V. During this call, it      * is possible to access the data of the ComponentGraph in a read-only      * fashion.      *       * @param remaining      *            The component that will be the union of both components      *            after merge      * @param disappearing      *            The component that will be removed from the graph      */     public void mergeComponent(V remaining, V leaving);     /**      * Called when a node is added to some component      */     public void nodeAddedToComponent(V component, T node);     /**      * Called when a node is removed from some component      */     public void nodeRemovedFromComponent(V component, T node);   }   /**    * Node classifier for the ContactGraph    *     * @param <T>    *            Type that stores in nodes    */   public interface NodeClassifier<T> {     /**      * @param node      *            Node to classify      * @return true if the node is to be considered as a delimiting node,      *         such that two components in some graph, would not be merged      *         if connected through such a node. Returns false otherwise.      */     public boolean isDelimitor(final T node);   }   /**    * Add a node to the graph. If the node already exists in the graph, the    * call will have no effect.    *     * @param node    */   public void addNode(T node);   /**    * Remove a node from the graph. All edges incident to this node will be    * removed as well.    *     * @param node    */   public void removeNode(T node);   /**    * Add an edge to the graph, and implicitly add included end-nodes if not    * already present in the graph. This is roughly an O(k) and sometimes    * O(nodes) operation, depending on whether components are to be merged or    * not.    *     * @param pair    *            A pair of nodes, where an edge is to be added between them.    * @param edgeelement    *            An element of type U to store in the new edge    */   public void addEdge(Pair<T> pair, U edgeelement);   /**    * Remove an edge. If the removal results in one or more isolated nodes,    * these will be removed from the graph implicitly.    *     * For non-dense and relatively fragmented graphs, this operation will be    * cheap. Otherwise, for dense and strongly connected graphs, the operation    * could include a full traversal of the graph visiting all present edges,    * resulting in an O((n-1)^2) operation, where n is the number of nodes in    * the graph.    *     * @param pair    *            edge to be removed    * @return true if the edge was actually removed, false if the edge did not    *         exists before call.    */   public boolean removeEdge(Pair<T> pair);   /**    * Get the edge element of type U that is stored in the edge defined by a    * pair of node types T. If no such edge exist, the return value is null.    *     * @param pair    *            A pair of T type objects defining an edge in the graph    * @return The U type object stored in the edge. Return value is null if no    *         such edge is present in the graph    */   public U getEdge(Pair<T> pair);   /**    * Return an iterator yielding the edges in the specified component.    *     * @param c    *            Component to iterate    * @return Iterator giving the edge elements in the component    */   public Iterator<U> getEdgesInComponent(V c);   /**    * Returns an iterator yielding the nodes present in the given component    *     * @param c    *            Any component of this graph    * @return An iterator yielding the nodes present in the component c    */   public Iterator<T> getNodesInComponent(V c);   /**    * Return an iterator that yields the components in the graph    *     * @return    */   public Iterator<V> getComponents();   /**    * Return the number of components in this graph    */   public int getNumberOfComponents();   /**    * Return the total number of nodes in this graph    */   public int getNumberOfNodes();   /**    * Return the number of free nodes, which are nodes that are not a part of a    * graph component    */   public int getNumberOfFreeNodes();   /**    * Get all free nodes. A free node is not in any component.    */   public Iterator<T> getFreeNodes();   /**    * Get all nodes that is connected to the given node. The constructible    * pairs Pair<T> can then be used to obtain the edge type U using    * getEdge(Pair<T>)    */   public Iterator<T> getConnectedNodes(T node);   /**    * Get all edges connected to the given node    *     * @param node    * @return An iterator over all edges connected to the given node    */   public Iterator<U> getConnectedEdges(T node); } /**  * Copyright (c) 2008-2010 Morten Silcowitz.  *   * This file is part of the Jinngine physics library  *   * Jinngine is published under the GPL license, available at  * http://www.gnu.org/copyleft/gpl.html.  */ // package jinngine.util; /**  * Small pair class, for the purpose of indexing unordered pairs in a hash table  */ final class Pair<T> {   private final T o1;   private final T o2;   public Pair(T o1, T o2) {     this.o1 = o1;     this.o2 = o2;   }   // since this is an unordered pair, we use   // the same hash code for interchanced objects   @Override   public final int hashCode() {     return o1.hashCode() * o2.hashCode();   }   @SuppressWarnings("unchecked")   @Override   public final boolean equals(Object other) {     if (this == other)       return true;     if (other == null)       return false;     if (other instanceof Pair) {       final Pair<T> otherpair = (Pair<T>) other;       return ((o1.equals(otherpair.o1) && o2.equals(otherpair.o2)) || (o1           .equals(otherpair.o2) && o2.equals(otherpair.o1)));     } else {       return false;     }   }   public final T getFirst() {     return o1;   }   public final T getSecond() {     return o2;   }   public final boolean contains(T o) {     return (o == o1 || o == o2);   } }