def generate_sparse6(G, nodes=None, header=True): """Generate sparse6 format string from an undirected graph. Parameters ---------- G : Graph (undirected) nodes: list or iterable Nodes are labeled 0...n-1 in the order provided. If None the ordering given by G.nodes() is used. header: bool If True add '>>sparse6<<' string to head of data Returns ------- s : string String in sparse6 format Raises ------ NetworkXError If the graph is directed Examples -------- >>> G = nx.MultiGraph([(0, 1), (0, 1), (0, 1)]) >>> nx.generate_sparse6(G) '>>sparse6<<:A_' See Also -------- read_sparse6, parse_sparse6, write_sparse6 Notes ----- The format does not support edge or node labels. References ---------- Sparse6 specification: http://cs.anu.edu.au/~bdm/data/formats.txt for details. """ n = G.order() k = 1 while 1 << k < n: k += 1 def enc(x): """Big endian k-bit encoding of x""" return [1 if (x & 1 << (k - 1 - i)) else 0 for i in range(k)] if nodes is None: ns = list(G.nodes()) # number -> node else: ns = list(nodes) ndict = dict(((ns[i], i) for i in range(len(ns)))) # node -> number edges = [(ndict[u], ndict[v]) for (u, v) in G.edges()] edges = [(max(u, v), min(u, v)) for (u, v) in edges] edges.sort() bits = [] curv = 0 for (v, u) in edges: if v == curv: # current vertex edge bits.append(0) bits.extend(enc(u)) elif v == curv + 1: # next vertex edge curv += 1 bits.append(1) bits.extend(enc(u)) else: # skip to vertex v and then add edge to u curv = v bits.append(1) bits.extend(enc(v)) bits.append(0) bits.extend(enc(u)) if k < 6 and n == (1 << k) and ((-len(bits)) % 6) >= k and curv < (n - 1): # Padding special case: small k, n=2^k, # more than k bits of padding needed, # current vertex is not (n-1) -- # appending 1111... would add a loop on (n-1) bits.append(0) bits.extend([1] * ((-len(bits)) % 6)) else: bits.extend([1] * ((-len(bits)) % 6)) data = [(bits[i + 0] << 5) + (bits[i + 1] << 4) + (bits[i + 2] << 3) + (bits[i + 3] << 2) + (bits[i + 4] << 1) + (bits[i + 5] << 0) for i in range(0, len(bits), 6)] res = (':' + data_to_graph6(n_to_data(n)) + data_to_graph6(data)) if header: return '>>sparse6<<' + res else: return res
def generate_sparse6(G, nodes=None, header=True): """Generate sparse6 format string from an undirected graph. Parameters ---------- G : Graph (undirected) nodes: list or iterable Nodes are labeled 0...n-1 in the order provided. If None the ordering given by G.nodes() is used. header: bool If True add '>>sparse6<<' string to head of data Returns ------- s : string String in sparse6 format Raises ------ NetworkXError If the graph is directed Examples -------- >>> G = nx.MultiGraph([(0, 1), (0, 1), (0, 1)]) >>> nx.generate_sparse6(G) '>>sparse6<<:A_' See Also -------- read_sparse6, parse_sparse6, write_sparse6 Notes ----- The format does not support edge or node labels. References ---------- Sparse6 specification: http://cs.anu.edu.au/~bdm/data/formats.txt for details. """ n = G.order() k = 1 while 1<<k < n: k += 1 def enc(x): """Big endian k-bit encoding of x""" return [1 if (x & 1 << (k-1-i)) else 0 for i in range(k)] if nodes is None: ns = list(G.nodes()) # number -> node else: ns = list(nodes) ndict = dict(((ns[i], i) for i in range(len(ns)))) # node -> number edges = [(ndict[u], ndict[v]) for (u, v) in G.edges()] edges = [(max(u,v), min(u,v)) for (u, v) in edges] edges.sort() bits = [] curv = 0 for (v, u) in edges: if v == curv: # current vertex edge bits.append(0) bits.extend(enc(u)) elif v == curv + 1: # next vertex edge curv += 1 bits.append(1) bits.extend(enc(u)) else: # skip to vertex v and then add edge to u curv = v bits.append(1) bits.extend(enc(v)) bits.append(0) bits.extend(enc(u)) if k < 6 and n == (1 << k) and ((-len(bits)) % 6) >= k and curv < (n - 1): # Padding special case: small k, n=2^k, # more than k bits of padding needed, # current vertex is not (n-1) -- # appending 1111... would add a loop on (n-1) bits.append(0) bits.extend([1] * ((-len(bits)) % 6)) else: bits.extend([1] * ((-len(bits)) % 6)) data = [(bits[i+0]<<5) + (bits[i+1]<<4) + (bits[i+2]<<3) + (bits[i+3]<<2) + (bits[i+4]<<1) + (bits[i+5]<<0) for i in range(0, len(bits), 6)] res = (':' + data_to_graph6(n_to_data(n)) + data_to_graph6(data)) if header: return '>>sparse6<<' + res else: return res
def test_data_sparse6_data_conversion(self): for data in [[], [0], [63], [63, 63], [0] * 42, [0, 1, 62, 42, 3, 11, 0, 11]]: assert_equal(g6.graph6_to_data(g6.data_to_graph6(data)), data) assert_equal(len(g6.data_to_graph6(data)), len(data))
def test_data_sparse6_data_conversion(self): for data in [[], [0], [63], [63, 63], [0]*42, [0, 1, 62, 42, 3, 11, 0, 11]]: assert_equal(g6.graph6_to_data(g6.data_to_graph6(data)), data) assert_equal(len(g6.data_to_graph6(data)), len(data))