001    package aima.util;
002    
003    import java.util.ArrayList;
004    import java.util.Hashtable;
005    import java.util.List;
006    
007    /**
008     * Represents a directed labeled graph. Vertices are represented by their unique
009     * labels and labeled edges by means of nested hashtables. Variant of class
010     * {@code aima.util.Table}. This version is more dynamic, it requires no
011     * initialization and can add new items whenever needed.
012     * 
013     * @author R. Lunde
014     */
015    public class LabeledGraph<VertexLabelType, EdgeLabelType> {
016    
017            /**
018             * Lookup for edge label information. Contains an entry for every vertex
019             * label.
020             */
021            private final Hashtable<VertexLabelType, Hashtable<VertexLabelType, EdgeLabelType>> globalEdgeLookup;
022            /** List of the labels of all vertices within the graph. */
023            private final List<VertexLabelType> vertexLabels;
024    
025            /** Creates a new empty graph. */
026            public LabeledGraph() {
027                    globalEdgeLookup = new Hashtable<VertexLabelType, Hashtable<VertexLabelType, EdgeLabelType>>();
028                    vertexLabels = new ArrayList<VertexLabelType>();
029            }
030    
031            /**
032             * Adds a new vertex to the graph if it is not already present.
033             */
034            public void addVertex(VertexLabelType v) {
035                    checkForNewVertex(v);
036            }
037    
038            /**
039             * Adds a directed labeled edge to the graph. The end points of the edge are
040             * specified by vertex labels. New vertices are automatically identified and
041             * added to the graph.
042             */
043            public void set(VertexLabelType from, VertexLabelType to, EdgeLabelType el) {
044                    Hashtable<VertexLabelType, EdgeLabelType> localEdgeLookup = checkForNewVertex(from);
045                    localEdgeLookup.put(to, el);
046                    checkForNewVertex(to);
047            }
048    
049            /** Handles new vertices. */
050            private Hashtable<VertexLabelType, EdgeLabelType> checkForNewVertex(
051                            VertexLabelType v) {
052                    Hashtable<VertexLabelType, EdgeLabelType> result = globalEdgeLookup
053                                    .get(v);
054                    if (result == null) {
055                            result = new Hashtable<VertexLabelType, EdgeLabelType>();
056                            globalEdgeLookup.put(v, result);
057                            vertexLabels.add(v);
058                    }
059                    return result;
060            }
061    
062            /** Removes an edge from the graph. */
063            public void remove(VertexLabelType from, VertexLabelType to) {
064                    Hashtable<VertexLabelType, EdgeLabelType> localEdgeLookup = globalEdgeLookup
065                                    .get(from);
066                    if (localEdgeLookup != null)
067                            localEdgeLookup.remove(to);
068            }
069    
070            /**
071             * Returns the label of the edge between the specified vertices and null if
072             * there is no edge between them.
073             */
074            public EdgeLabelType get(VertexLabelType from, VertexLabelType to) {
075                    Hashtable<VertexLabelType, EdgeLabelType> localEdgeLookup = globalEdgeLookup
076                                    .get(from);
077                    return localEdgeLookup == null ? null : localEdgeLookup.get(to);
078            }
079    
080            /**
081             * Returns the labels of those vertices which can be obtained by following
082             * the edges starting at the specified vertex.
083             */
084            public List<VertexLabelType> getSuccessors(VertexLabelType v) {
085                    List<VertexLabelType> result = new ArrayList<VertexLabelType>();
086                    Hashtable<VertexLabelType, EdgeLabelType> localEdgeLookup = globalEdgeLookup
087                                    .get(v);
088                    if (localEdgeLookup != null)
089                            result.addAll(localEdgeLookup.keySet());
090                    return result;
091            }
092    
093            /** Returns the labels of all vertices within the graph. */
094            public List<VertexLabelType> getVertexLabels() {
095                    return vertexLabels;
096            }
097    
098            /** Checks whether the given label is the label of one of the vertices. */
099            public boolean isVertexLabel(VertexLabelType v) {
100                    return globalEdgeLookup.get(v) != null;
101            }
102    
103            /** Removes all vertices and all edges from the graph. */
104            public void clear() {
105                    vertexLabels.clear();
106                    globalEdgeLookup.clear();
107            }
108    }