001/* 002 * Copyright 2006 - 2013 003 * Stefan Balev <stefan.balev@graphstream-project.org> 004 * Julien Baudry <julien.baudry@graphstream-project.org> 005 * Antoine Dutot <antoine.dutot@graphstream-project.org> 006 * Yoann Pigné <yoann.pigne@graphstream-project.org> 007 * Guilhelm Savin <guilhelm.savin@graphstream-project.org> 008 * 009 * This file is part of GraphStream <http://graphstream-project.org>. 010 * 011 * GraphStream is a library whose purpose is to handle static or dynamic 012 * graph, create them from scratch, file or any source and display them. 013 * 014 * This program is free software distributed under the terms of two licenses, the 015 * CeCILL-C license that fits European law, and the GNU Lesser General Public 016 * License. You can use, modify and/ or redistribute the software under the terms 017 * of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following 018 * URL <http://www.cecill.info> or under the terms of the GNU LGPL as published by 019 * the Free Software Foundation, either version 3 of the License, or (at your 020 * option) any later version. 021 * 022 * This program is distributed in the hope that it will be useful, but WITHOUT ANY 023 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 024 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 025 * 026 * You should have received a copy of the GNU Lesser General Public License 027 * along with this program. If not, see <http://www.gnu.org/licenses/>. 028 * 029 * The fact that you are presently reading this means that you have had 030 * knowledge of the CeCILL-C and LGPL licenses and that you accept their terms. 031 */ 032package org.graphstream.graph; 033 034import java.util.Collection; 035import java.util.Iterator; 036import java.util.List; 037import java.util.Stack; 038 039/** 040 * Path description. 041 * 042 * <p> 043 * A path is a class that stores ordered lists of nodes and links that are 044 * adjacent. Such a path may be manipulated with nodes and/or edges added or 045 * removed. This class is designed as a dynamic structure that is, to add edges 046 * during the construction of the path. Only edges need to be added, the nodes 047 * list is maintained automatically. 048 * </p> 049 * 050 * <p> 051 * The two lists (one for nodes, one for edges) may be acceded at any moment in 052 * constant time. 053 * </p> 054 * 055 * <p> 056 * The constraint of this class is that it needs to know the first node of the 057 * path (the root). This root can be set with the {@link #setRoot(Node)} method 058 * or by using the {@link #add(Node, Edge)} method. 059 * </p> 060 * 061 * <p> 062 * The normal use with this class is to first use the {@link #setRoot(Node)} 063 * method to initialize the path; then to use the {@link #add(Edge)} method to 064 * grow it and the {@link #popEdge()} or {@link #popNode()}. 065 * 066 */ 067public class Path implements Structure { 068 // ------------- ATTRIBUTES ------------ 069 070 /** 071 * The root of the path; 072 */ 073 private Node root = null; 074 075 /** 076 * The list of edges that represents the path. 077 */ 078 Stack<Edge> edgePath; 079 080 /** 081 * The list of nodes representing the path. 082 */ 083 Stack<Node> nodePath; 084 085 // ------------- CONSTRUCTORS ------------ 086 087 /** 088 * New empty path. 089 */ 090 public Path() { 091 edgePath = new Stack<Edge>(); 092 nodePath = new Stack<Node>(); 093 } 094 095 // -------------- ACCESSORS -------------- 096 097 /** 098 * Get the root (the first node) of the path. 099 * 100 * @return the root of the path. 101 */ 102 public Node getRoot() { 103 return this.root; 104 } 105 106 /** 107 * Set the root (first node) of the path. 108 * 109 * @param root 110 * The root of the path. 111 */ 112 public void setRoot(Node root) { 113 if (this.root == null) { 114 this.root = root; 115 nodePath.push(root); 116 } else { 117 System.err 118 .printf("Error in org.miv.graphstream.graph.Path: root is not null. First use the clear method.%n"); 119 } 120 121 } 122 123 /** 124 * Says whether the path contains this node or not. 125 * 126 * @param node 127 * The node tested for existence in the path. 128 * @return <code>true</code> if the path contains the node. 129 */ 130 public boolean contains(Node node) { 131 return nodePath.contains(node); 132 } 133 134 /** 135 * Says whether the path contains this edge or not. 136 * 137 * @param edge 138 * The edge tested for existence in the path. 139 * @return <code>true</code> if the path contains the edge. 140 */ 141 public boolean contains(Edge edge) { 142 return edgePath.contains(edge); 143 } 144 145 /** 146 * Returns true if the path is empty. 147 * 148 * @return <code>true</code> if the path is empty. 149 */ 150 public boolean empty() { 151 return nodePath.empty(); 152 } 153 154 /** 155 * Returns the size of the path 156 */ 157 public int size() { 158 return nodePath.size(); 159 } 160 161 /** 162 * It returns the sum of the <code>characteristic</code> given value in the 163 * Edges of the path. 164 * 165 * @param characteristic 166 * The characteristic. 167 * @return Sum of the characteristics. 168 */ 169 public Double getPathWeight(String characteristic) { 170 double d = 0; 171 for (Edge l : edgePath) { 172 d += (Double) l.getAttribute(characteristic, Number.class); 173 } 174 return d; 175 } 176 177 /** 178 * Returns the list of edges representing the path. 179 * 180 * @return The list of edges representing the path. 181 */ 182 public List<Edge> getEdgePath() { 183 return edgePath; 184 } 185 186 /** 187 * Construct an return a list of nodes that represents the path. 188 * 189 * @return A list of nodes representing the path. 190 */ 191 public List<Node> getNodePath() { 192 return nodePath; 193 } 194 195 // -------------- MODIFIERS ------------- 196 197 /** 198 * Method that adds a node (and an edge) to the path. Parameters are the 199 * start node : the one who already belong to the path or the first one if 200 * the path is empty. The other parameter is the the new edge to add. 201 * 202 * @param from 203 * The start node. 204 * @param edge 205 * The edge used. 206 */ 207 public void add(Node from, Edge edge) { 208 if (root == null) { 209 if (from == null) { 210 System.err 211 .print("Error using org.miv.graphstream.graph.Path: Use setRoot( ) first. %n"); 212 System.exit(0); 213 } else { 214 setRoot(from); 215 } 216 } 217 218 if (from == null) { 219 from = nodePath.peek(); 220 } 221 222 if (nodePath.size() == 1 223 || ((nodePath.peek() == from) && (from == edgePath.peek() 224 .getSourceNode() || from == edgePath.peek() 225 .getTargetNode()))) { 226 227 nodePath.push(edge.getOpposite(from)); 228 edgePath.push(edge); 229 } else { 230 System.err 231 .printf("Path: Cannot add the specified edge, it cannot be part of the path! %n"); 232 } 233 } 234 235 /** 236 * Method that adds an edge an a node to the path. The new edge to add is 237 * given. 238 * 239 * @param edge 240 * The edge to add to the path. 241 */ 242 public void add(Edge edge) { 243 if (nodePath.isEmpty()) { 244 add(null, edge); 245 } else { 246 add(nodePath.peek(), edge); 247 } 248 } 249 250 /** 251 * A synonym for {@link #add(Edge)}. 252 */ 253 public void push(Node from, Edge edge) { 254 add(from, edge); 255 } 256 257 /** 258 * A synonym for {@link #add(Edge)}. 259 */ 260 public void push(Edge edge) { 261 add(edge); 262 } 263 264 /** 265 * This methods pops the 2 stacks (<code>edgePath</code> and 266 * <code>nodePath</code>) and returns the removed edge. 267 * 268 * @return The edge that have just been removed. 269 */ 270 public Edge popEdge() { 271 nodePath.pop(); 272 return edgePath.pop(); 273 } 274 275 /** 276 * This methods pops the 2 stacks (<code>edgePath</code> and 277 * <code>nodePath</code>) and returns the removed node. 278 * 279 * @return The node that have just been removed. 280 */ 281 public Node popNode() { 282 edgePath.pop(); 283 return nodePath.pop(); 284 } 285 286 /** 287 * Looks at the node at the top of the stack without removing it from the 288 * stack. 289 * 290 * @return The node at the top of the stack. 291 */ 292 public Node peekNode() { 293 return nodePath.peek(); 294 } 295 296 /** 297 * Looks at the edge at the top of the stack without removing it from the 298 * stack. 299 * 300 * @return The edge at the top of the stack. 301 */ 302 303 public Edge peekEdge() { 304 return edgePath.peek(); 305 } 306 307 /** 308 * Clears the path; 309 */ 310 public void clear() { 311 nodePath.clear(); 312 edgePath.clear(); 313 // Runtime.getRuntime().gc(); 314 root = null; 315 } 316 317 /** 318 * Get a copy of this path 319 * 320 * @return A copy of this path. 321 */ 322 @SuppressWarnings("unchecked") 323 public Path getACopy() { 324 Path newPath = new Path(); 325 newPath.root = this.root; 326 newPath.edgePath = (Stack<Edge>) edgePath.clone(); 327 newPath.nodePath = (Stack<Node>) nodePath.clone(); 328 329 return newPath; 330 } 331 332 /** 333 * Remove all parts of the path that start at a given node and pass a new at 334 * this node. 335 */ 336 public void removeLoops() { 337 int n = nodePath.size(); 338 /* 339 * System.err.printf( "removeLoop()%n" ); System.err.printf( 340 * " path size = %d==%d%n [ ", n, edgePath.size() ); 341 * 342 * for( int i=0; i<n; i++ ) { System.err.printf( "%d=%s ", i, 343 * nodePath.get(i).getId() ); } System.err.printf( "]%n" ); 344 */ 345 // For each node-edge pair 346 for (int i = 0; i < n; i++) { 347 // Lookup each other following node. We start 348 // at the end to find the largest loop possible. 349 for (int j = n - 1; j > i; j--) { 350 // If another node match, this is a loop. 351 if (nodePath.get(i) == nodePath.get(j)) { 352 // We found a loop between i and j. 353 // Remove ]i,j]. 354 // System.err.printf( "removed ]%d,%d]%n", i, j ); 355 for (int k = i + 1; k <= j; k++) { 356 nodePath.remove(i + 1); 357 edgePath.remove(i); 358 } 359 n -= (j - i); 360 j = i; // To stop the search. 361 } 362 } 363 } 364 /* 365 * System.err.printf( " NEW path size = %d==%d%n NEW [ ", n, 366 * edgePath.size() ); 367 * 368 * for( int i=0; i<n; i++ ) { System.err.printf( "%d=%s ", i, 369 * nodePath.get(i).getId() ); } System.err.printf( "]%n" ); 370 */} 371 372 /** 373 * Compare the content of the current path and the specified path to decide 374 * weather they are equal or not. 375 * 376 * @param p 377 * A path to compare to the curent one. 378 * @return True if both paths are equal. 379 */ 380 public boolean equals(Path p) { 381 if (nodePath.size() != p.nodePath.size()) { 382 return false; 383 } else { 384 for (int i = 0; i < nodePath.size(); i++) { 385 if (nodePath.get(i) != p.nodePath.get(i)) { 386 return false; 387 } 388 } 389 } 390 return true; 391 } 392 393 // ------------ UTILITY METHODS ------------ 394 395 /** 396 * Returns a String description of the path. 397 * 398 * @return A String representation of the path. 399 */ 400 @Override 401 public String toString() { 402 return nodePath.toString(); 403 } 404 405 /** 406 * Returns the size of the path. Identical to {@link #size()}. 407 * 408 * @return The size of the path. 409 */ 410 public int getNodeCount() { 411 return nodePath.size(); 412 } 413 414 /* 415 * (non-Javadoc) 416 * 417 * @see org.graphstream.graph.Structure#getEdgeCount() 418 */ 419 public int getEdgeCount() { 420 return edgePath.size(); 421 } 422 423 /* 424 * (non-Javadoc) 425 * 426 * @see org.graphstream.graph.Structure#getNodeIterator() 427 */ 428 @SuppressWarnings("unchecked") 429 public <T extends Node> Iterator<T> getNodeIterator() { 430 return (Iterator<T>) nodePath.iterator(); 431 } 432 433 /* 434 * (non-Javadoc) 435 * 436 * @see org.graphstream.graph.Structure#getEdgeIterator() 437 */ 438 @SuppressWarnings("unchecked") 439 public <T extends Edge> Iterator<T> getEdgeIterator() { 440 return (Iterator<T>) edgePath.iterator(); 441 } 442 443 /* 444 * (non-Javadoc) 445 * 446 * @see org.graphstream.graph.Structure#getEachNode() 447 */ 448 @SuppressWarnings("unchecked") 449 public <T extends Node> Iterable<? extends T> getEachNode() { 450 return (Iterable<? extends T>) nodePath; 451 } 452 453 /* 454 * (non-Javadoc) 455 * 456 * @see org.graphstream.graph.Structure#getEachEdge() 457 */ 458 @SuppressWarnings("unchecked") 459 public <T extends Edge> Iterable<? extends T> getEachEdge() { 460 return (Iterable<? extends T>) edgePath; 461 } 462 463 /* 464 * (non-Javadoc) 465 * 466 * @see org.graphstream.graph.Structure#getNodeSet() 467 */ 468 @SuppressWarnings("unchecked") 469 public <T extends Node> Collection<T> getNodeSet() { 470 return (Collection<T>) nodePath; 471 } 472 473 /* 474 * (non-Javadoc) 475 * 476 * @see org.graphstream.graph.Structure#getEdgeSet() 477 */ 478 @SuppressWarnings("unchecked") 479 public <T extends Edge> Collection<T> getEdgeSet() { 480 return (Collection<T>) edgePath; 481 } 482}