| Line | Hits | Source |
|---|---|---|
| 1 | /* | |
| 2 | * Created on May 3, 2004 | |
| 3 | * | |
| 4 | * Copyright (c) 2004, the JUNG Project and the Regents of the University | |
| 5 | * of California | |
| 6 | * All rights reserved. | |
| 7 | * | |
| 8 | * This software is open-source under the BSD license; see either | |
| 9 | * "license.txt" or | |
| 10 | * http://jung.sourceforge.net/license.txt for a description. | |
| 11 | */ | |
| 12 | package edu.uci.ics.jung.io; | |
| 13 | ||
| 14 | import java.awt.geom.Point2D; | |
| 15 | import java.io.BufferedReader; | |
| 16 | import java.io.FileReader; | |
| 17 | import java.io.IOException; | |
| 18 | import java.io.Reader; | |
| 19 | import java.util.StringTokenizer; | |
| 20 | ||
| 21 | import org.apache.commons.collections.Predicate; | |
| 22 | import org.apache.commons.collections.functors.OrPredicate; | |
| 23 | ||
| 24 | import edu.uci.ics.jung.exceptions.FatalException; | |
| 25 | import edu.uci.ics.jung.graph.Edge; | |
| 26 | import edu.uci.ics.jung.graph.Graph; | |
| 27 | import edu.uci.ics.jung.graph.Vertex; | |
| 28 | import edu.uci.ics.jung.graph.decorators.Indexer; | |
| 29 | import edu.uci.ics.jung.graph.decorators.NumberEdgeValue; | |
| 30 | import edu.uci.ics.jung.graph.decorators.StringLabeller; | |
| 31 | import edu.uci.ics.jung.graph.impl.DirectedSparseEdge; | |
| 32 | import edu.uci.ics.jung.graph.impl.SparseGraph; | |
| 33 | import edu.uci.ics.jung.graph.impl.UndirectedSparseEdge; | |
| 34 | import edu.uci.ics.jung.graph.predicates.ParallelEdgePredicate; | |
| 35 | import edu.uci.ics.jung.utils.PredicateUtils; | |
| 36 | import edu.uci.ics.jung.utils.TypedVertexGenerator; | |
| 37 | import edu.uci.ics.jung.utils.UserData; | |
| 38 | import edu.uci.ics.jung.utils.VertexGenerator; | |
| 39 | import edu.uci.ics.jung.visualization.DefaultSettableVertexLocationFunction; | |
| 40 | import edu.uci.ics.jung.visualization.SettableVertexLocationFunction; | |
| 41 | ||
| 42 | ||
| 43 | /** | |
| 44 | * Reads a <code>Graph</code> from a Pajek NET formatted source. | |
| 45 | * | |
| 46 | * <p>If the edge constraints specify that the graph is strictly undirected, | |
| 47 | * and an "*Arcs" section is encountered, or if the edge constraints specify that the | |
| 48 | * graph is strictly directed, and an "*Edges" section is encountered, | |
| 49 | * an <code>IllegalArgumentException</code> is thrown.</p> | |
| 50 | * | |
| 51 | * <p>If the edge constraints do not permit parallel edges, only the first encountered | |
| 52 | * of a set of parallel edges will be read; subsequent edges in that set will be ignored.</p> | |
| 53 | * | |
| 54 | * <p>More restrictive edge constraints will cause vertices to be generated | |
| 55 | * that are more time- and space-efficient.</p> | |
| 56 | * | |
| 57 | * At the moment, only supports the | |
| 58 | * part of the specification that defines: | |
| 59 | * <ul> | |
| 60 | * <li> vertex ids (each must have a value from 1 to n, where n is the number of vertices) | |
| 61 | * <li> vertex labels (must be in quotes if interrupted by whitespace) | |
| 62 | * <li> directed edge connections (single or list) | |
| 63 | * <li> undirected edge connections (single or list) | |
| 64 | * <li> edge weights (not compatible with edges specified in list form) | |
| 65 | * <br><b>note</b>: this version of PajekNetReader does not support multiple edge | |
| 66 | * weights, as PajekNetFile does; this behavior is consistent with the NET format. | |
| 67 | * <li/> vertex locations (x and y; z coordinate is ignored) | |
| 68 | * </ul> <p> | |
| 69 | * | |
| 70 | * Here is an example format for a directed graph without edge weights | |
| 71 | * and edges specified in list form: <br> | |
| 72 | * <pre> | |
| 73 | * *vertices <# of vertices> | |
| 74 | * 1 "a" | |
| 75 | * 2 "b" | |
| 76 | * 3 "c" | |
| 77 | * *arcslist | |
| 78 | * 1 2 3 | |
| 79 | * 2 3 | |
| 80 | * </pre> | |
| 81 | * | |
| 82 | * Here is an example format for an undirected graph with edge weights | |
| 83 | * and edges specified in non-list form: <br> | |
| 84 | * <pre> | |
| 85 | * *vertices <# of vertices> | |
| 86 | * 1 "a" | |
| 87 | * 2 "b" | |
| 88 | * 3 "c" | |
| 89 | * *edges | |
| 90 | * 1 2 0.1 | |
| 91 | * 1 3 0.9 | |
| 92 | * 2 3 1.0 | |
| 93 | * </pre> | |
| 94 | * | |
| 95 | * @author Joshua O'Madadhain | |
| 96 | * @see "'Pajek - Program for Analysis and Visualization of Large Networks', Vladimir Batagelj and Andrej Mrvar, http://vlado.fmf.uni-lj.si/pub/networks/pajek/doc/pajekman.pdf" | |
| 97 | */ | |
| 98 | public class PajekNetReader | |
| 99 | { | |
| 100 | protected boolean unique_labels; | |
| 101 | ||
| 102 | /** | |
| 103 | * The key used to identify the vertex labels (if any) created by this class. | |
| 104 | */ | |
| 105 | public static final String LABEL = "jung.io.PajekNetReader.LABEL"; | |
| 106 | ||
| 107 | /** | |
| 108 | * The user data key used to retrieve the vertex locations (if any) defined by this class. | |
| 109 | */ | |
| 110 | public static final String LOCATIONS = "jung.io.PajekNetReader.LOCATIONS"; | |
| 111 | ||
| 112 | protected SettableVertexLocationFunction v_locations; | |
| 113 | 5 | protected boolean get_locations = false; |
| 114 | ||
| 115 | /** | |
| 116 | * Used to specify whether the most recently read line is a | |
| 117 | * Pajek-specific tag. | |
| 118 | */ | |
| 119 | 1 | private static final Predicate v_pred = new TagPred("*vertices"); |
| 120 | 1 | private static final Predicate a_pred = new TagPred("*arcs"); |
| 121 | 1 | private static final Predicate e_pred = new TagPred("*edges"); |
| 122 | 1 | private static final Predicate t_pred = new TagPred("*"); |
| 123 | 1 | private static final Predicate c_pred = OrPredicate.getInstance(a_pred, e_pred); |
| 124 | 1 | protected static final Predicate l_pred = ListTagPred.getInstance(); |
| 125 | 1 | protected static final Predicate p_pred = ParallelEdgePredicate.getInstance(); |
| 126 | ||
| 127 | /** | |
| 128 | * Creates a PajekNetReader with the specified labeling behavior, which does not | |
| 129 | * read location information (if any). | |
| 130 | * | |
| 131 | * @see #PajekNetReader(boolean, boolean) | |
| 132 | */ | |
| 133 | public PajekNetReader(boolean unique_labels) | |
| 134 | { | |
| 135 | 0 | this(unique_labels, false); |
| 136 | 0 | } |
| 137 | ||
| 138 | /** | |
| 139 | * Creates a PajekNetReader with the specified labeling behavior and | |
| 140 | * location assignment behavior. | |
| 141 | * | |
| 142 | * <p>If <code>unique_labels</code> is true, vertices will be labelled | |
| 143 | * using a <code>StringLabeller</code> with key <code>jung.io.PajekNetReader.LABEL</code>. | |
| 144 | * Otherwise, they will be labeled with a user data <code>String</code> with key | |
| 145 | * <code>PajekNetReader.LABEL</code>. (Vertices that have no apparent label | |
| 146 | * information will not be labelled.)</p> | |
| 147 | * | |
| 148 | * <p>If <code>get_locations</code> is true, each vertex line in the file | |
| 149 | * will be assumed to contain (x,y) coordinates in the range [0,1]; if any line | |
| 150 | * lacks this data, an <code>IllegalArgumentException</code> will be thrown. (The Pajek | |
| 151 | * format assumes coordinates are (x,y,z) but we ignore the z-coordinate.) Location | |
| 152 | * data will be stored in a <code>SettabelVertexLocationDecorator</code> instance | |
| 153 | * in the graph's user data with key<code>jung.io.PajekNetReader.LOCATIONS</code>.</p> | |
| 154 | */ | |
| 155 | public PajekNetReader(boolean unique_labels, boolean get_locations) | |
| 156 | 5 | { |
| 157 | 5 | this.unique_labels = unique_labels; |
| 158 | 5 | this.get_locations = get_locations; |
| 159 | 5 | if (get_locations) |
| 160 | 1 | this.v_locations = new DefaultSettableVertexLocationFunction(); |
| 161 | 5 | } |
| 162 | ||
| 163 | /** | |
| 164 | * Creates a PajekNetReader with the specified labeling behavior and | |
| 165 | * location assignment behavior. | |
| 166 | * | |
| 167 | * <p>If <code>unique_labels</code> is true, vertices will be labelled | |
| 168 | * using a <code>StringLabeller</code> with key <code>jung.io.PajekNetReader.LABEL</code>. | |
| 169 | * Otherwise, they will be labeled with a user data <code>String</code> with key | |
| 170 | * <code>PajekNetReader.LABEL</code>. (Vertices that have no apparent label | |
| 171 | * information will not be labelled.)</p> | |
| 172 | * | |
| 173 | * <p>If <code>get_locations</code> is true, each vertex line in the file | |
| 174 | * will be assumed to contain (x,y) coordinates in the range [0,1]; if any line | |
| 175 | * lacks this data, an <code>IllegalArgumentException</code> will be thrown. (The Pajek | |
| 176 | * format assumes coordinates are (x,y,z) but we ignore the z-coordinate.) Location | |
| 177 | * data will be stored in <code>v_locations</code>, a reference to which will be | |
| 178 | * stored in the graph's user data with key <code>jung.io.PajekNetReader.LOCATIONS</code>.</p> | |
| 179 | */ | |
| 180 | public PajekNetReader(boolean unique_labels, SettableVertexLocationFunction v_locations) | |
| 181 | 0 | { |
| 182 | 0 | this.unique_labels = unique_labels; |
| 183 | 0 | this.get_locations = true; |
| 184 | 0 | this.v_locations = v_locations; |
| 185 | 0 | } |
| 186 | ||
| 187 | /** | |
| 188 | * Creates a PajekNetReader whose labels are not required to be unique. | |
| 189 | */ | |
| 190 | public PajekNetReader() | |
| 191 | { | |
| 192 | 4 | this(false, false); |
| 193 | 4 | } |
| 194 | ||
| 195 | /** | |
| 196 | * Returns <code>load(filename, new SparseGraph(), null)</code>. | |
| 197 | * @throws IOException | |
| 198 | */ | |
| 199 | public Graph load(String filename) throws IOException | |
| 200 | { | |
| 201 | 6 | return load(filename, new SparseGraph(), null); |
| 202 | } | |
| 203 | ||
| 204 | /** | |
| 205 | * Returns <code>load(filename, new SparseGraph(), nev)</code>. | |
| 206 | * @throws IOException | |
| 207 | */ | |
| 208 | public Graph load(String filename, NumberEdgeValue nev) throws IOException | |
| 209 | { | |
| 210 | 1 | return load(filename, new SparseGraph(), nev); |
| 211 | } | |
| 212 | ||
| 213 | /** | |
| 214 | * Returns <code>load(filename, g, null)</code>. | |
| 215 | * @throws IOException | |
| 216 | */ | |
| 217 | public Graph load(String filename, Graph g) throws IOException | |
| 218 | { | |
| 219 | 0 | return load(filename, g, null); |
| 220 | } | |
| 221 | ||
| 222 | /** | |
| 223 | * Creates a <code>FileReader</code> from <code>filename</code>, calls | |
| 224 | * <code>load(reader, g, nev)</code>, closes the reader, and returns | |
| 225 | * the resultant graph. | |
| 226 | * @throws IOException | |
| 227 | */ | |
| 228 | public Graph load(String filename, Graph g, NumberEdgeValue nev) throws IOException | |
| 229 | { | |
| 230 | 7 | Reader reader = new FileReader(filename); |
| 231 | 6 | Graph graph = load(reader, g, nev); |
| 232 | 6 | reader.close(); |
| 233 | 6 | return graph; |
| 234 | } | |
| 235 | ||
| 236 | /** | |
| 237 | * Returns <code>load(reader, g, null)</code>. | |
| 238 | * @throws IOException | |
| 239 | */ | |
| 240 | public Graph load(Reader reader, Graph g) throws IOException | |
| 241 | { | |
| 242 | 0 | return load(reader, g, null); |
| 243 | } | |
| 244 | ||
| 245 | /** | |
| 246 | * Returns <code>load(reader, new SparseGraph(), nev)</code>. | |
| 247 | * @throws IOException | |
| 248 | */ | |
| 249 | public Graph load(Reader reader, NumberEdgeValue nev) throws IOException | |
| 250 | { | |
| 251 | 0 | return load(reader, new SparseGraph(), nev); |
| 252 | } | |
| 253 | ||
| 254 | /** | |
| 255 | * Returns <code>load(reader, new SparseGraph(), null)</code>. | |
| 256 | * @throws IOException | |
| 257 | */ | |
| 258 | public Graph load(Reader reader) throws IOException | |
| 259 | { | |
| 260 | 1 | return load(reader, new SparseGraph(), null); |
| 261 | } | |
| 262 | ||
| 263 | /** | |
| 264 | * Returns <code>load(reader, g, nev, new TypedVertexGenerator(g))</code>. | |
| 265 | * @throws IOException | |
| 266 | * @see edu.uci.ics.jung.utils.TypedVertexGenerator | |
| 267 | */ | |
| 268 | public Graph load(Reader reader, Graph g, NumberEdgeValue nev) throws IOException | |
| 269 | { | |
| 270 | 7 | return load(reader, g, nev, new TypedVertexGenerator(g)); |
| 271 | } | |
| 272 | ||
| 273 | /** | |
| 274 | * Populates the graph <code>g</code> with the graph represented by the | |
| 275 | * Pajek-format data supplied by <code>reader</code>. Stores edge weights, | |
| 276 | * if any, according to <code>nev</code> (if non-null). | |
| 277 | * Any existing vertices/edges of <code>g</code>, if any, are unaffected. | |
| 278 | * The edge data are filtered according to <code>g</code>'s constraints, if any; thus, if | |
| 279 | * <code>g</code> only accepts directed edges, any undirected edges in the | |
| 280 | * input are ignored. | |
| 281 | * Vertices are created with the generator <code>vg</code>. The user is responsible | |
| 282 | * for supplying a generator whose output is compatible with this graph and its contents; | |
| 283 | * users that don't want to deal with this issue may use a <code>TypedVertexGenerator</code> | |
| 284 | * or call <code>load(reader, g, nev)</code> for a default generator. | |
| 285 | * @throws IOException | |
| 286 | */ | |
| 287 | public Graph load(Reader reader, Graph g, NumberEdgeValue nev, VertexGenerator vg) throws IOException | |
| 288 | { | |
| 289 | 7 | BufferedReader br = new BufferedReader(reader); |
| 290 | ||
| 291 | // ignore everything until we see '*Vertices' | |
| 292 | 7 | String curLine = skip(br, v_pred); |
| 293 | ||
| 294 | 7 | if (curLine == null) // no vertices in the graph; return empty graph |
| 295 | 0 | return g; |
| 296 | ||
| 297 | 7 | if (get_locations) |
| 298 | 1 | g.addUserDatum(LOCATIONS, v_locations, UserData.SHARED); |
| 299 | ||
| 300 | // create appropriate number of vertices | |
| 301 | 7 | StringTokenizer st = new StringTokenizer(curLine); |
| 302 | 7 | st.nextToken(); // skip past "*vertices"; |
| 303 | 7 | int num_vertices = Integer.parseInt(st.nextToken()); |
| 304 | 40 | for (int i = 1; i <= num_vertices; i++) |
| 305 | 33 | g.addVertex(vg.create()); |
| 306 | 7 | Indexer id = Indexer.getIndexer(g); |
| 307 | ||
| 308 | // read vertices until we see any Pajek format tag ('*...') | |
| 309 | 7 | curLine = null; |
| 310 | 40 | while (br.ready()) |
| 311 | { | |
| 312 | 40 | curLine = br.readLine(); |
| 313 | 40 | if (curLine == null || t_pred.evaluate(curLine)) |
| 314 | 7 | break; |
| 315 | 33 | if (curLine == "") // skip blank lines |
| 316 | 0 | continue; |
| 317 | ||
| 318 | try | |
| 319 | { | |
| 320 | 33 | readVertex(curLine, id, num_vertices); |
| 321 | } | |
| 322 | 0 | catch (IllegalArgumentException iae) |
| 323 | { | |
| 324 | 0 | br.close(); |
| 325 | 0 | reader.close(); |
| 326 | 0 | throw iae; |
| 327 | 33 | } |
| 328 | } | |
| 329 | ||
| 330 | // skip over the intermediate stuff (if any) | |
| 331 | // and read the next arcs/edges section that we find | |
| 332 | 7 | curLine = readArcsOrEdges(curLine, br, g, nev); |
| 333 | ||
| 334 | // ditto | |
| 335 | 7 | readArcsOrEdges(curLine, br, g, nev); |
| 336 | ||
| 337 | 7 | br.close(); |
| 338 | 7 | reader.close(); |
| 339 | ||
| 340 | 7 | return g; |
| 341 | } | |
| 342 | ||
| 343 | /** | |
| 344 | * Parses <code>curLine</code> as a reference to a vertex, and optionally assigns | |
| 345 | * label and location information. | |
| 346 | * @throws IOException | |
| 347 | */ | |
| 348 | private void readVertex(String curLine, Indexer id, int num_vertices) throws IOException | |
| 349 | { | |
| 350 | Vertex v; | |
| 351 | 33 | String[] parts = null; |
| 352 | 33 | int coord_idx = -1; // index of first coordinate in parts; -1 indicates no coordinates found |
| 353 | String index; | |
| 354 | 33 | String label = null; |
| 355 | // if there are quote marks on this line, split on them; label is surrounded by them | |
| 356 | 33 | if (curLine.indexOf('"') != -1) |
| 357 | { | |
| 358 | 30 | String[] initial_split = curLine.trim().split("\""); |
| 359 | // if there are any quote marks, there should be exactly 2 | |
| 360 | 30 | if (initial_split.length < 2 || initial_split.length > 3) |
| 361 | 0 | throw new IllegalArgumentException("Unbalanced (or too many) quote marks in " + curLine); |
| 362 | 30 | index = initial_split[0].trim(); |
| 363 | 30 | label = initial_split[1].trim(); |
| 364 | 30 | if (initial_split.length == 3) |
| 365 | 10 | parts = initial_split[2].trim().split("\\s+", -1); |
| 366 | 30 | coord_idx = 0; |
| 367 | } | |
| 368 | else // no quote marks, but are there coordinates? | |
| 369 | { | |
| 370 | 3 | parts = curLine.trim().split("\\s+", -1); |
| 371 | 3 | index = parts[0]; |
| 372 | 3 | switch (parts.length) |
| 373 | { | |
| 374 | case 1: // just the ID; nothing to do, continue | |
| 375 | 3 | break; |
| 376 | case 2: // just the ID and a label | |
| 377 | 0 | label = parts[1]; |
| 378 | 0 | break; |
| 379 | case 3: // ID, no label, coordinates | |
| 380 | 0 | coord_idx = 1; |
| 381 | 0 | break; |
| 382 | case 4: // ID, label, (x,y) coordinates | |
| 383 | 0 | coord_idx = 2; |
| 384 | break; | |
| 385 | } | |
| 386 | } | |
| 387 | 33 | int v_id = Integer.parseInt(index) - 1; // go from 1-based to 0-based index |
| 388 | 33 | if (v_id >= num_vertices || v_id < 0) |
| 389 | 0 | throw new IllegalArgumentException("Vertex number " + v_id + |
| 390 | "is not in the range [1," + num_vertices + "]"); | |
| 391 | 33 | v = (Vertex) id.getVertex(v_id); |
| 392 | // only attach the label if there's one to attach | |
| 393 | 33 | if (label != null && label.length() > 0) |
| 394 | 30 | attachLabel(v, label); |
| 395 | // parse the rest of the line | |
| 396 | 33 | if (get_locations) |
| 397 | { | |
| 398 | 5 | if (coord_idx == -1 || parts == null || parts.length < coord_idx+2) |
| 399 | 0 | throw new IllegalArgumentException("Coordinates requested, but" + |
| 400 | curLine + " does not include coordinates"); | |
| 401 | 5 | double x = Double.parseDouble(parts[coord_idx]); |
| 402 | 5 | double y = Double.parseDouble(parts[coord_idx+1]); |
| 403 | // if (x < 0 || x > 1 || y < 0 || y > 1) | |
| 404 | // throw new IllegalArgumentException("Coordinates in line " + | |
| 405 | // curLine + " are not all in the range [0,1]"); | |
| 406 | ||
| 407 | 5 | v_locations.setLocation(v, new Point2D.Double(x,y)); |
| 408 | } | |
| 409 | 33 | } |
| 410 | ||
| 411 | ||
| 412 | ||
| 413 | private String readArcsOrEdges(String curLine, BufferedReader br, Graph g, | |
| 414 | NumberEdgeValue nev) | |
| 415 | throws IOException | |
| 416 | { | |
| 417 | 14 | String nextLine = curLine; |
| 418 | ||
| 419 | 14 | Indexer id = Indexer.getIndexer(g); |
| 420 | ||
| 421 | // in case we're not there yet (i.e., format tag isn't arcs or edges) | |
| 422 | 14 | if (! c_pred.evaluate(curLine)) |
| 423 | // nextLine = skip(br, e_pred); | |
| 424 | 5 | nextLine = skip(br, c_pred); |
| 425 | ||
| 426 | // in "*Arcs" and this graph is not strictly undirected | |
| 427 | // boolean reading_arcs = a_pred.evaluate(nextLine) && | |
| 428 | // !PredicateUtils.enforcesUndirected(g); | |
| 429 | // // in "*Edges" and this graph is not strictly directed | |
| 430 | // boolean reading_edges = e_pred.evaluate(nextLine) && | |
| 431 | // !PredicateUtils.enforcesDirected(g); | |
| 432 | ||
| 433 | 14 | boolean reading_arcs = false; |
| 434 | 14 | boolean reading_edges = false; |
| 435 | 14 | if (a_pred.evaluate(nextLine)) |
| 436 | { | |
| 437 | 4 | if (PredicateUtils.enforcesUndirected(g)) |
| 438 | 0 | throw new IllegalArgumentException("Supplied undirected-only graph cannot be populated with directed edges"); |
| 439 | else | |
| 440 | 4 | reading_arcs = true; |
| 441 | } | |
| 442 | 14 | if (e_pred.evaluate(nextLine)) |
| 443 | { | |
| 444 | 5 | if (PredicateUtils.enforcesDirected(g)) |
| 445 | 0 | throw new IllegalArgumentException("Supplied directed-only graph cannot be populated with undirected edges"); |
| 446 | else | |
| 447 | 5 | reading_edges = true; |
| 448 | } | |
| 449 | ||
| 450 | 14 | if (!(reading_arcs || reading_edges)) |
| 451 | 5 | return nextLine; |
| 452 | ||
| 453 | 9 | boolean is_list = l_pred.evaluate(nextLine); |
| 454 | ||
| 455 | 9 | boolean parallel_ok = !PredicateUtils.enforcesNotParallel(g); |
| 456 | ||
| 457 | 47 | while (br.ready()) |
| 458 | { | |
| 459 | 41 | nextLine = br.readLine(); |
| 460 | 41 | if (nextLine == null || t_pred.evaluate(nextLine)) |
| 461 | 2 | break; |
| 462 | 38 | if (curLine == "") // skip blank lines |
| 463 | 0 | continue; |
| 464 | ||
| 465 | 38 | StringTokenizer st = new StringTokenizer(nextLine.trim()); |
| 466 | ||
| 467 | 38 | int vid1 = Integer.parseInt(st.nextToken()) - 1; |
| 468 | 38 | Vertex v1 = (Vertex) id.getVertex(vid1); |
| 469 | ||
| 470 | 38 | if (is_list) // one source, multiple destinations |
| 471 | { | |
| 472 | do | |
| 473 | { | |
| 474 | 0 | createAddEdge(st, v1, reading_arcs, g, id, parallel_ok); |
| 475 | 0 | } while (st.hasMoreTokens()); |
| 476 | } | |
| 477 | else // one source, one destination, at most one weight | |
| 478 | { | |
| 479 | 38 | Edge e = createAddEdge(st, v1, reading_arcs, g, id, parallel_ok); |
| 480 | // get the edge weight if we care | |
| 481 | 38 | if (nev != null) |
| 482 | 6 | nev.setNumber(e, new Float(st.nextToken())); |
| 483 | } | |
| 484 | } | |
| 485 | 9 | return nextLine; |
| 486 | } | |
| 487 | ||
| 488 | protected Edge createAddEdge(StringTokenizer st, Vertex v1, | |
| 489 | boolean directed, Graph g, Indexer id, boolean parallel_ok) | |
| 490 | { | |
| 491 | 38 | int vid2 = Integer.parseInt(st.nextToken()) - 1; |
| 492 | 38 | Vertex v2 = (Vertex) id.getVertex(vid2); |
| 493 | 38 | Edge e = null; |
| 494 | 38 | if (directed) |
| 495 | 18 | e = new DirectedSparseEdge(v1, v2); |
| 496 | else | |
| 497 | 20 | e = new UndirectedSparseEdge(v1, v2); |
| 498 | ||
| 499 | // add this edge if parallel edges are OK, | |
| 500 | // or if this isn't one; otherwise ignore it | |
| 501 | 38 | if (parallel_ok || !p_pred.evaluate(e)) |
| 502 | 38 | g.addEdge(e); |
| 503 | ||
| 504 | 38 | return e; |
| 505 | } | |
| 506 | ||
| 507 | /** | |
| 508 | * Returns the first line read from <code>br</code> for which <code>p</code> | |
| 509 | * returns <code>true</code>, or <code>null</code> if there is no | |
| 510 | * such line. | |
| 511 | * @throws IOException | |
| 512 | */ | |
| 513 | protected String skip(BufferedReader br, Predicate p) throws IOException | |
| 514 | { | |
| 515 | 12 | while (br.ready()) |
| 516 | { | |
| 517 | 8 | String curLine = br.readLine(); |
| 518 | 8 | if (curLine == null) |
| 519 | 1 | break; |
| 520 | 7 | curLine = curLine.trim(); |
| 521 | 7 | if (p.evaluate(curLine)) |
| 522 | 7 | return curLine; |
| 523 | } | |
| 524 | 5 | return null; |
| 525 | } | |
| 526 | ||
| 527 | /** | |
| 528 | * Labels <code>v</code> with <code>string</code>, according to the | |
| 529 | * labeling mechanism specified by <code>unique_labels</code>. | |
| 530 | * Removes quotation marks from the string if present. | |
| 531 | */ | |
| 532 | private void attachLabel(Vertex v, String string) throws IOException | |
| 533 | { | |
| 534 | 30 | if (string == null || string.length() == 0) |
| 535 | 0 | return; |
| 536 | 30 | String label = string.trim(); |
| 537 | // String label = trimQuotes(string).trim(); | |
| 538 | // if (label.length() == 0) | |
| 539 | // return; | |
| 540 | 30 | if (unique_labels) |
| 541 | { | |
| 542 | try | |
| 543 | { | |
| 544 | 0 | StringLabeller sl = StringLabeller.getLabeller((Graph)v.getGraph(), LABEL); |
| 545 | 0 | sl.setLabel(v, label); |
| 546 | } | |
| 547 | 0 | catch (StringLabeller.UniqueLabelException slule) |
| 548 | { | |
| 549 | 0 | throw new FatalException("Non-unique label found: " + slule); |
| 550 | 0 | } |
| 551 | } | |
| 552 | else | |
| 553 | { | |
| 554 | 30 | v.addUserDatum(LABEL, label, UserData.SHARED); |
| 555 | } | |
| 556 | 30 | } |
| 557 | ||
| 558 | /** | |
| 559 | * Sets or clears the <code>unique_labels</code> boolean. | |
| 560 | * @see #PajekNetReader(boolean, boolean) | |
| 561 | */ | |
| 562 | public void setUniqueLabels(boolean unique_labels) | |
| 563 | { | |
| 564 | 0 | this.unique_labels = unique_labels; |
| 565 | 0 | } |
| 566 | ||
| 567 | /** | |
| 568 | * Sets or clears the <code>get_locations</code> boolean. | |
| 569 | * @see #PajekNetReader(boolean, boolean) | |
| 570 | */ | |
| 571 | public void setGetLocations(boolean get_locations) | |
| 572 | { | |
| 573 | 1 | this.get_locations = get_locations; |
| 574 | 1 | } |
| 575 | ||
| 576 | /** | |
| 577 | * A Predicate which evaluates to <code>true</code> if the | |
| 578 | * argument starts with the constructor-specified String. | |
| 579 | * | |
| 580 | * @author Joshua O'Madadhain | |
| 581 | */ | |
| 582 | protected static class TagPred implements Predicate | |
| 583 | { | |
| 584 | private String tag; | |
| 585 | ||
| 586 | public TagPred(String s) | |
| 587 | { | |
| 588 | this.tag = s; | |
| 589 | } | |
| 590 | ||
| 591 | public boolean evaluate(Object arg0) | |
| 592 | { | |
| 593 | String s = (String)arg0; | |
| 594 | return (s != null && s.toLowerCase().startsWith(tag)); | |
| 595 | } | |
| 596 | } | |
| 597 | ||
| 598 | /** | |
| 599 | * A Predicate which evaluates to <code>true</code> if the | |
| 600 | * argument ends with the string "list". | |
| 601 | * | |
| 602 | * @author Joshua O'Madadhain | |
| 603 | */ | |
| 604 | protected static class ListTagPred implements Predicate | |
| 605 | { | |
| 606 | protected static ListTagPred instance; | |
| 607 | ||
| 608 | protected ListTagPred() {} | |
| 609 | ||
| 610 | public static ListTagPred getInstance() | |
| 611 | { | |
| 612 | if (instance == null) | |
| 613 | instance = new ListTagPred(); | |
| 614 | return instance; | |
| 615 | } | |
| 616 | ||
| 617 | public boolean evaluate(Object arg0) | |
| 618 | { | |
| 619 | String s = (String)arg0; | |
| 620 | return (s != null && s.toLowerCase().endsWith("list")); | |
| 621 | } | |
| 622 | } | |
| 623 | ||
| 624 | ||
| 625 | } |
|
this report was generated by version 1.0.5 of jcoverage. |
copyright © 2003, jcoverage ltd. all rights reserved. |