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}