HashMapComponentGraph.java Source code

Java tutorial

Introduction

Here is the source code for HashMapComponentGraph.java

Source

/**
 * 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);
    }

}