/* * @(#)PajekParser.java 1.0 Dec 8, 2010 * * Copyright 2010-2011 ETH Zurich. All Rights Reserved. * * This software is the proprietary information of ETH Zurich. * Use is subject to license terms. * * @(#) $Id: PajekParser.java 1995 2011-10-12 20:09:21Z D\michagro $ */ package org.zoodb.test.jdo.sna; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; /** * Parses a file in the Pajek format and uses a GraphBuilder to generate output. * * @author Michael Grossniklaus <grossniklaus@inf.ethz.ch> * @version 1.0 */ public class PajekParser { private static final char COMMENT_MARKER = '%'; private static final char CONTEXT_MARKER = '*'; private final VersantBuilder builder; public PajekParser(final VersantBuilder builder) { this.builder = builder; } public void parse(final File file) throws IOException { this.parse(new FileInputStream(file)); } public void parse(final String name) throws IOException { final File file = new File(name); if (file.exists()) { this.parse(file); } else { // final ClassLoader loader = ClassLoader.getSystemClassLoader(); // final InputStream in = loader.getResourceAsStream(name); final InputStream in = this.getClass().getResourceAsStream(name); this.parse(in); } } private void parse(final InputStream in) throws IOException { final ParseState state = new ParseState(); String line = null; final BufferedReader reader = new BufferedReader(new InputStreamReader(in)); while ((line = reader.readLine()) != null) { line = line.trim(); if (line.length() > 0) { final char marker = line.charAt(0); switch (marker) { case COMMENT_MARKER: break; case CONTEXT_MARKER: if (line.length() > 1) { final String[] tokens = line.split("[ ]+"); final ParseContext context = ParseContext.valueOf(tokens[0] .substring(1).toUpperCase()); switch (context) { case VERTICES: if (tokens.length > 1) { state.setTotalNodes(Long.valueOf(tokens[1])); if (tokens.length > 2) { state.setPartitionIndex(Long.valueOf(tokens[2])); } else { state.setPartitionIndex(state.getTotalNodes()); } } state.resetCurrentNode(); break; case ARCS: // Do nothing case EDGES: // Do nothing case ARCSLIST: // Do nothing case EDGESLIST: // Do nothing case MATRIX: state.resetCurrentNode(); default: // This case *should* not occur } state.setContext(context); } break; default: this.parseLine(state, line); } } } reader.close(); } private void parseLine(final ParseState state, final String line) { final String content = line; Object[] tokens; switch (state.getContext()) { case VERTICES: tokens = this.parseVertex(content); if (tokens != null && tokens.length > 1) { this.builder.handleNode((Long) tokens[0], (String) tokens[1]); } state.incrementCurrentNode(); break; case ARCS: tokens = this.parseEdge(content); if (tokens != null && tokens.length > 2) { this.builder .handleArc((Long) tokens[0], (Long) tokens[1], (Double) tokens[2]); } break; case EDGES: tokens = this.parseEdge(content); if (tokens != null && tokens.length > 2) { this.builder.handleEdge((Long) tokens[0], (Long) tokens[1], (Double) tokens[2]); } break; case ARCSLIST: tokens = this.parseEdgesList(content); if (tokens != null && tokens.length > 1) { final Long source = (Long) tokens[0]; for (int i = 1; i < tokens.length; i++) { this.builder.handleArc(source, (Long) tokens[i], 1.0); } } break; case EDGESLIST: tokens = this.parseEdgesList(content); if (tokens != null && tokens.length > 1) { final Long source = (Long) tokens[0]; for (int i = 1; i < tokens.length; i++) { this.builder.handleEdge(source, (Long) tokens[i], 1.0); } } break; case MATRIX: tokens = this.parseMatrixRow(content); if (tokens != null && tokens.length == state.getPartitionSize()) { final long start = state.getPartitionStartNode(); final Long source = Long.valueOf(state.getCurrentNode()); for (int i = 0; i < tokens.length; i++) { final Long target = Long.valueOf(i + start); this.builder.handleEdge(source, target, (Double) tokens[i]); } state.incrementCurrentNode(); } break; default: // This case *should* not occur } } Object[] parseVertex(final String line) { final int splitPos = line.indexOf(" "); if (splitPos > 0) { final String id = line.substring(0, splitPos); String label = line.substring(splitPos + 1); int endPos; if (label.startsWith("\"")) { endPos = label.indexOf("\"", 1); } else { endPos = label.indexOf(" ", 0); } label = label.substring(1, endPos); return new Object[] { Long.valueOf(id), label }; } return null; } Object[] parseEdge(final String line) { final String[] tokens = line.split("[ ]+"); if (tokens.length > 1) { Double value = null; if (tokens.length > 2) { value = Double.valueOf(tokens[2]); } return new Object[] { Long.valueOf(tokens[0]), Long.valueOf(tokens[1]), value }; } return null; } Object[] parseEdgesList(final String line) { final String[] tokens = line.split("[ ]+"); if (tokens.length > 1) { final Object[] result = new Object[tokens.length]; for (int i = 0; i < tokens.length; i++) { result[i] = Long.valueOf(tokens[i]); } return result; } return null; } Object[] parseMatrixRow(final String line) { final String[] tokens = line.split("[ ]+"); final Object[] result = new Object[tokens.length]; for (int i = 0; i < tokens.length; i++) { result[i] = Double.valueOf(tokens[i]); } return result; } private enum ParseContext { VERTICES, ARCS, ARCSLIST, EDGES, EDGESLIST, MATRIX }; private class NodePartition { private final long startNode; private final long endNode; NodePartition(final long startNode, final long endNode) { this.startNode = startNode; this.endNode = endNode; } long getStartNode() { return this.startNode; } // long getEndNode() { // return this.endNode; // } long getSize() { return this.endNode - this.startNode + 1; } } private class ParseState { private ParseContext context; private long totalNodes; private long currentNode; private final NodePartition[] partitions; ParseState() { this.context = null; this.totalNodes = 0; this.currentNode = 0; // At the moment, I am only aware of graphs with two partitions. this.partitions = new NodePartition[2]; } ParseContext getContext() { return this.context; } void setContext(final ParseContext context) { this.context = context; } long getTotalNodes() { return this.totalNodes; } void setTotalNodes(final long totalNodes) { this.totalNodes = totalNodes; } long getCurrentNode() { return this.currentNode; } void resetCurrentNode() { this.currentNode = 1; } void incrementCurrentNode() { this.currentNode++; } void setPartitionIndex(final long index) { this.partitions[0] = new NodePartition(1, index); if (index < this.totalNodes) { this.partitions[1] = new NodePartition(index + 1, this.totalNodes); } } long getPartitionSize() { if (this.isPartitioned()) { return this.partitions[1].getSize(); } return this.partitions[0].getSize(); } long getPartitionStartNode() { if (this.isPartitioned()) { return this.partitions[1].getStartNode(); } return this.partitions[0].getStartNode(); } private boolean isPartitioned() { return this.partitions[1] != null && this.partitions[1].getSize() > 0; } } }