001/*
002MIT License
003
004Copyright (c) 2020 earlygrey
005
006Permission is hereby granted, free of charge, to any person obtaining a copy
007of this software and associated documentation files (the "Software"), to deal
008in the Software without restriction, including without limitation the rights
009to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
010copies of the Software, and to permit persons to whom the Software is
011furnished to do so, subject to the following conditions:
012
013The above copyright notice and this permission notice shall be included in all
014copies or substantial portions of the Software.
015
016THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
017IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
018FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
019AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
020LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
021OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
022SOFTWARE.
023 */
024package squidpony.squidai.graph;
025
026import squidpony.squidmath.OrderedMap;
027
028import java.util.*;
029
030/**
031 * Abstract superclass of actual Graph types, like {@link DirectedGraph} and {@link UndirectedGraph}.
032 * @param <V> the vertex type; often {@link squidpony.squidmath.Coord}
033 * @author earlygrey
034 */
035public abstract class Graph<V> {
036
037    //================================================================================
038    // Members
039    //================================================================================
040    
041    protected final OrderedMap<V, Node<V>> vertexMap;
042    protected final OrderedMap<Connection<V>, Connection<V>> edgeMap;
043    
044    //================================================================================
045    // Constructors
046    //================================================================================
047
048    protected Graph() {
049        vertexMap = new OrderedMap<>();
050        edgeMap = new OrderedMap<>();
051    }
052
053    protected Graph(Collection<V> vertices) {
054        this();
055        for (V v : vertices) {
056            addVertex(v);
057        }
058    }
059
060    //================================================================================
061    // Graph Builders
062    //================================================================================
063
064    //--------------------
065    //  Abstract Methods
066    //--------------------
067
068    protected abstract Connection<V> obtainEdge();
069    protected abstract Graph<V> createNew();
070    public abstract Algorithms<V> algorithms();
071
072    //--------------------
073    //  Public Methods
074    //--------------------
075
076    /**
077     * Adds a vertex to the graph.
078     * @param v the vertex to be added
079     * @return true if the vertex was not already in the graph, false otherwise
080     */
081
082    public boolean addVertex(V v) {
083        Node<V> node = getNode(v);
084        if (node!=null) return false;
085        node = new Node<>(v, this);
086        vertexMap.put(v, node);
087        return true;
088    }
089
090    /**
091     * Adds all the vertices in the collection to the graph.
092     * @param vertices a collection of vertices to be added
093     */
094    public void addVertices(Collection<V> vertices) {
095        for (V v : vertices) {
096            addVertex(v);
097        }
098    }
099
100    /**
101     * Removes a vertex from the graph, and any adjacent edges.
102     * @param v the vertex to be removed
103     * @return true if the vertex was in the graph, false otherwise
104     */
105    public boolean removeVertex(V v) {
106        Node<V> existing = getNode(v);
107        if (existing==null) return false;
108        removeNode(existing);
109        return true;
110    }
111
112    /**
113     * Removes all the vertices in the collection from the graph, and any adjacent edges.
114     * @param vertices vertices a collection of vertices to be removed
115     */
116    public void removeVertices(Collection<V> vertices) {
117        for (V v : vertices) {
118            removeVertex(v);
119        }
120    }
121
122    /**
123     * Add an edge to the graph, from v to w. The edge will have a default weight of 1.
124     * If there is already an edge between v and w, its weight will be set to 1.
125     * @param v the source vertex of the edge
126     * @param w the destination vertex of the edge
127     * @return the edge
128     */
129    public Connection<V> addEdge(V v, V w) {
130        return addEdge(v, w, Connection.DEFAULT_WEIGHT);
131    }
132
133    /**
134     * Add an edge to the graph, from v to w and with the specified weight.
135     * If there is already an edge between v and w, its weight will be set to the specified weight.
136     * @param v the source vertex of the edge
137     * @param w the destination vertex of the edge
138     * @param weight the weight of the edge
139     * @return the edge
140     */
141    public Connection<V> addEdge(V v, V w, float weight) {
142        if (v == null || w == null) throw new IllegalArgumentException("Vertices cannot be null");
143        if (v.equals(w)) throw new IllegalArgumentException("Self loops are not allowed");
144        Node<V> a = getNode(v);
145        Node<V> b = getNode(w);
146        if (a == null  || b == null) throw new IllegalArgumentException("At least one vertex is not in the graph");
147        return addConnection(a, b, weight);
148    }
149
150    /**
151     * Removes the edge from v to w from the graph.
152     * @param v the source vertex of the edge
153     * @param w the destination vertex of the edge
154     * @return the edge if there exists an edge from v to w, or null if there is no edge
155     */
156    public boolean removeEdge(V v, V w) {
157        Node<V> a = getNode(v), b = getNode(w);
158        if (a == null  || b == null) throw new IllegalArgumentException("At least one vertex is not in the graph");
159        return removeConnection(a, b);
160    }
161
162    public boolean removeEdge(Edge<V> edge) {
163        return removeConnection(edge.getInternalNodeA(), edge.getInternalNodeB());
164    }
165
166    /**
167     * Removes all edges from the graph.
168     */
169    public void removeAllEdges() {
170        for (Node<V> v : getNodes()) {
171            v.disconnect();
172        }
173        edgeMap.clear();
174    }
175
176    /**
177     * Removes all vertices and edges from the graph.
178     */
179    public void removeAllVertices() {
180        edgeMap.clear();
181        vertexMap.clear();
182    }
183
184    /**
185     * Sort the vertices using the provided comparator. This is reflected in the iteration order of the collection returned
186     * by {@link #getVertices()}, as well as algorithms which involve iterating over all vertices.
187     * @param comparator a comparator for comparing vertices
188     */
189    public void sortVertices(Comparator<V> comparator) {
190        vertexMap.sort(comparator);
191    }
192
193    /**
194     * Sort the edges using the provided comparator. This is reflected in the iteration order of the collection returned
195     * by {@link #getEdges()}, as well as algorithms which involve iterating over all edges.
196     * @param comparator a comparator for comparing edges
197     */
198    public void sortEdges(Comparator<Connection<V>> comparator) {
199        edgeMap.sort(comparator);
200    }
201
202    //--------------------
203    //  Internal Methods
204    //--------------------
205
206    protected void removeNode(Node<V> node) {
207        for (int i = node.outEdges.size()-1; i >= 0; i--) {
208            removeConnection(node.outEdges.get(i).b, node);
209        }
210        node.disconnect();
211        vertexMap.remove(node.object);
212    }
213
214    protected Connection<V> addConnection(Node<V> a, Node<V> b) {
215        Connection<V> e = a.addEdge(b, Connection.DEFAULT_WEIGHT);
216        edgeMap.put(e, e);
217        return e;
218    }
219
220    protected Connection<V> addConnection(Node<V> a, Node<V> b, float weight) {
221        Connection<V> e = a.addEdge(b, weight);
222        edgeMap.put(e, e);
223        return e;
224    }
225
226    protected boolean removeConnection(Node<V> a, Node<V> b) {
227        Connection<V> e = a.removeEdge(b);
228        if (e == null) return false;
229        edgeMap.remove(e);
230        return true;
231    }
232
233    //================================================================================
234    // Getters
235    //================================================================================
236
237    //--------------------
238    //  Public Getters
239    //--------------------
240
241    /**
242     * Check if the graph contains a vertex.
243     * @param v the vertex with which to check
244     * @return true if the graph contains the vertex, false otherwise
245     */
246    public boolean contains(V v) {
247        return vertexMap.containsKey(v);
248    }
249
250    /**
251     * Retrieve the edge which is from v to w.
252     * @param v the source vertex of the edge
253     * @param w the destination vertex of the edge
254     * @return the edge if it is in the graph, otherwise null
255     */
256    public Edge<V> getEdge(V v, V w) {
257        Node<V> a = getNode(v), b = getNode(w);
258        if (a == null  || b == null) throw new IllegalArgumentException("At least one vertex is not in the graph");
259        return getEdge(a, b);
260    }
261
262    /**
263     * Check if the graph contains an edge from v to w.
264     * @param v the source vertex of the edge
265     * @param w the destination vertex of the edge
266     * @return true if the edge is in the graph, false otherwise
267     */
268    public boolean edgeExists(V v, V w) {
269        Node<V> a = getNode(v), b = getNode(w);
270        if (a == null  || b == null) throw new IllegalArgumentException("At least one vertex is not in the graph");
271        return connectionExists(a, b);
272    }
273
274    /**
275     * Get a collection containing all the edges which have v as a source.
276     * @param v the source vertex of all the edges
277     * @return an unmodifiable collection of edges
278     */
279    public List<? extends Edge<V>> getEdges(V v) {
280        Node<V> node = getNode(v);
281        if (node==null) return null;
282        return Collections.unmodifiableList(node.outEdges);
283    }
284
285    /**
286     * Get a collection containing all the edges in the graph.
287     * @return an unmodifiable collection of all the edges in the graph
288     */
289    public SortedSet<? extends Edge<V>> getEdges() {
290        return Collections.unmodifiableSortedSet(edgeMap.keySet());
291    }
292
293    /**
294     * Get a collection containing all the vertices in the graph.
295     * @return an unmodifiable collection of all the vertices in the graph
296     */
297    public SortedSet<V> getVertices() {
298        return Collections.unmodifiableSortedSet(vertexMap.keySet());
299    }
300
301
302    /**
303     * Check if the graph is directed, that is whether the edges form an ordered pair or a set.
304     * @return whether the graph is directed
305     */
306    public boolean isDirected() {
307        return true;
308    }
309
310    /**
311     * Get the number of vertices in the graph.
312     * @return the number of vertices
313     */
314    public int size() {
315        return vertexMap.size();
316    }
317
318    /**
319     * Get the number of edges in the graph.
320     * @return the number of edges
321     */
322    public int getEdgeCount() {
323        return edgeMap.size();
324    }
325
326
327    //--------------------
328    //  Internal Getters
329    //--------------------
330
331    protected Node<V> getNode(V v) {
332        return vertexMap.get(v);
333    }
334
335    protected Collection<Node<V>> getNodes() {
336        return vertexMap.values();
337    }
338
339    protected boolean connectionExists(Node<V> u, Node<V> v) {
340        return u.getEdge(v) != null;
341    }
342
343    protected Connection<V> getEdge(Node<V> a, Node<V> b) {
344        return a.getEdge(b);
345    }
346
347
348
349}