All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgrapht.io.Graph6Sparse6Exporter Maven / Gradle / Ivy

There is a newer version: 1.5.2
Show newest version
/*
 * (C) Copyright 2017-2017, by Joris Kinable and Contributors.
 *
 * JGraphT : a free Java graph-theory library
 *
 * This program and the accompanying materials are dual-licensed under
 * either
 *
 * (a) the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation, or (at your option) any
 * later version.
 *
 * or (per the licensee's choosing)
 *
 * (b) the terms of the Eclipse Public License v1.0 as published by
 * the Eclipse Foundation.
 */
package org.jgrapht.io;

import java.io.*;
import java.util.*;

import org.jgrapht.*;

/**
 * Exporter which exports graphs in graph6 or sparse6 format. A description of the format can be found
 * here. graph6 and sparse6 are formats for storing
 * undirected graphs in a compact manner, using only printable ASCII characters. Files in these formats have text format
 * and contain one line per graph. graph6 is suitable for small graphs, or large dense graphs. sparse6 is more
 * space-efficient for large sparse graphs. Typically, files storing graph6 graphs have the 'g6' extension. Similarly,
 * files storing sparse6 graphs have a 's6' file extension. sparse6 graphs support loops and multiple edges, graph6
 * graphs do not.
 * 

* In particular, the length of a Graph6 string representation of a graph depends only on the number of vertices. * However, this also means that graphs with few edges take as much space as graphs with many edges. On the other * hand, Sparse6 is a variable length format which can use dramatically less space for sparse graphs but can have * a much larger storage size for dense graphs. * * @author Joris Kinable * * @param graph vertex type * @param graph edge type */ public class Graph6Sparse6Exporter implements GraphExporter{ /** * Format type: graph6 (g6) or sparse6(s6) */ public enum Format{GRAPH6, SPARSE6} private Format format; private ByteArrayOutputStream byteArrayOutputStream; /** * The default format used by the exporter. */ public static final Format DEFAULT_GRAPH6SPARSE6_FORMAT = Format.GRAPH6; /** * Constructs a new exporter with a given vertex ID provider. * */ public Graph6Sparse6Exporter() { this(DEFAULT_GRAPH6SPARSE6_FORMAT); } /** * Constructs a new exporter with a given vertex ID provider. * * @param format the format to use */ public Graph6Sparse6Exporter(Format format) { this.format = Objects.requireNonNull(format, "Format cannot be null"); } @Override public void exportGraph(Graph g, Writer writer) throws ExportException { GraphTests.requireUndirected(g); if(format == Format.GRAPH6 && !GraphTests.isSimple(g)) throw new ExportException("Graphs exported in graph6 format cannot contain loops or multiple edges."); //Map all vertices to a unique integer List vertices = new ArrayList<>(g.vertexSet()); byteArrayOutputStream = new ByteArrayOutputStream(); currentByte=0; bitIndex=0; try { if (format == Format.SPARSE6) writeSparse6(g, vertices); else writeGraph6(g, vertices); }catch (IOException e){ e.printStackTrace(); } String g6=""; try { g6=byteArrayOutputStream.toString("UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } PrintWriter out = new PrintWriter(writer); out.print(g6); out.flush(); } private void writeSparse6(Graph g, List vertices) throws IOException { int[][] edges=new int[g.edgeSet().size()][2]; int index=0; for(int j=0; j v+1){ writeBit(true); writeIntInKBits(edges[m][1], k); v = edges[m][1]; }else if(edges[m][1] == v + 1){ writeBit(true); writeIntInKBits(edges[m][0], k); v++; m++; }else{ writeBit(false); writeIntInKBits(edges[m][0], k); m++; } } //Pad right hand side with '1's to fill the last byte. This may not be the 'correct' way of padding as //described in the sparse6 format descr, but it's hard to make sense of the sparse6 description. This seems to work fine. if(bitIndex != 0) { int padding = 6 - bitIndex; for (int i = 0; i < padding; i++) writeBit(true); writeByte(); //push the last byte } } private void writeGraph6(Graph g, List vertices) throws IOException { writeNumberOfVertices(vertices.size()); //Write the lower triangle of the adjacency matrix of G as a bit vector x of length n(n-1)/2, //using the ordering (0,1),(0,2),(1,2),(0,3),(1,3),(2,3),...,(n-1,n). for(int i=0; i= 0; if(n <= 62) byteArrayOutputStream.write(n+63); else if(n <= 258047){ //write number in 4 bytes writeIntInKBits(63,6); writeIntInKBits(n, 18); }else{ //write number in 8 bytes writeIntInKBits(63,6); writeIntInKBits(63,6); writeIntInKBits(n, 36); } } private byte currentByte; private int bitIndex; private void writeIntInKBits(int number, int k){ for(int i=k-1; i>=0; i--) writeBit((number & (1 << i)) != 0); } private void writeBit(boolean bit){ if(bitIndex == 6) writeByte(); if(bit) currentByte |= 1 << (5-bitIndex); bitIndex++; } private void writeByte(){ byteArrayOutputStream.write(currentByte+63); currentByte=0; bitIndex=0; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy