U
    :vf'                     @   s   d Z ddlZddlmZ ddlmZmZ ddlm	Z	m
Z
 dddd	gZd
d Zdd ZdddZe
ddddd Ze	de
dddddd	ZdS )aP  Functions for reading and writing graphs in the *sparse6* format.

The *sparse6* file format is a space-efficient format for large sparse
graphs. For small graphs or large dense graphs, use the *graph6* file
format.

For more information, see the `sparse6`_ homepage.

.. _sparse6: https://users.cecs.anu.edu.au/~bdm/data/formats.html

    N)NetworkXError)	data_to_n	n_to_data)not_implemented_for	open_filefrom_sparse6_bytesread_sparse6to_sparse6_byteswrite_sparse6c                 #   s  t | }|dkrtd|r"dV  dV  t|D ]}tt|d V  q0dd> |k rdd7 qNfdd}td	d
 |  D }g  d}|D ]\}}	||kr d  	||	 q||d kr|d7 } d  	||	 q|} d  	||  d  	||	 qdk r|d> krt   d kr||d k r d  	dgt   d   n 	dgt   d    fddt
dt  dD }
|
D ]}tt|d V  qdV  dS )a%  Yield bytes in the sparse6 encoding of a graph.

    `G` is an undirected simple graph. `nodes` is the list of nodes for
    which the node-induced subgraph will be encoded; if `nodes` is the
    list of all nodes in the graph, the entire graph will be
    encoded. `header` is a Boolean that specifies whether to generate
    the header ``b'>>sparse6<<'`` before the remaining data.

    This function generates `bytes` objects in the following order:

    1. the header (if requested),
    2. the encoding of the number of nodes,
    3. each character, one-at-a-time, in the encoding of the requested
       node-induced subgraph,
    4. a newline character.

    This function raises :exc:`ValueError` if the graph is too large for
    the graph6 format (that is, greater than ``2 ** 36`` nodes).

    l       @ z?sparse6 is only defined if number of nodes is less than 2 ** 36   >>sparse6<<   :?      c                    s    fddt D S )zBig endian k-bit encoding of xc                    s(   g | ] }d  d  | > @ r d ndqS )r   r    .0i)kxr   >/tmp/pip-unpacked-wheel-_lngutwb/networkx/readwrite/sparse6.py
<listcomp><   s     z8_generate_sparse6_bytes.<locals>.enc.<locals>.<listcomp>)ranger   )r   r   r   enc:   s    z$_generate_sparse6_bytes.<locals>.encc                 s   s&   | ]\}}t ||t||fV  qd S )N)maxmin)r   uvr   r   r   	<genexpr>>   s     z*_generate_sparse6_bytes.<locals>.<genexpr>r      c                    sl   g | ]d} |d   d>  |d  d>   |d  d>   |d  d>   |d  d>   |d  d >  qS )r      r            r   r   )bitsr   r   r   Y   s   z+_generate_sparse6_bytes.<locals>.<listcomp>   
N)len
ValueErrorr   strencodechrsortededgesappendextendr   )Gnodesheaderndr   r,   Zcurvr   r   datar   )r$   r   r   _generate_sparse6_bytes   sP    




:


r5   c           	         s  |  dr| dd } |  ds(tddd | dd D }t|\} dd> |k rdd7 qN fd	d
}d}t }|t| d}| D ]X\}}|dkr|d7 }||ks||kr qq||kr|}q|||rd}||| q|st	|}|S )aV  Read an undirected graph in sparse6 format from string.

    Parameters
    ----------
    string : string
       Data in sparse6 format

    Returns
    -------
    G : Graph

    Raises
    ------
    NetworkXError
        If the string is unable to be parsed in sparse6 format

    Examples
    --------
    >>> G = nx.from_sparse6_bytes(b":A_")
    >>> sorted(G.edges())
    [(0, 1), (0, 1), (0, 1)]

    See Also
    --------
    read_sparse6, write_sparse6

    References
    ----------
    .. [1] Sparse6 specification
           <https://users.cecs.anu.edu.au/~bdm/data/formats.html>

    r      Nr   z!Expected leading colon in sparse6c                 S   s   g | ]}|d  qS )r   r   )r   cr   r   r   r      s     z&from_sparse6_bytes.<locals>.<listcomp>r   c                  3   s   t  } d}d}|dk r@zt| }W n tk
r:   Y dS X d}|d8 }||? d@ }|d|> d @ }|}|k rzt| }W n tk
r   Y dS X d}|d> | }|d7 }qh|| ? }| }||fV  qdS )z6Returns stream of pairs b[i], x[i] for sparse6 format.Nr   r   r   )iternextStopIteration)chunksr3   ZdLenbr   ZxLenr4   r   r   r   	parseData   s0    
z%from_sparse6_bytes.<locals>.parseDatar   FT)

startswithr   r   nxZ
MultiGraphZadd_nodes_fromr   Zhas_edgeZadd_edgeZGraph)	stringcharsr2   r>   r   r/   Z
multigraphr<   r   r   r=   r   r   h   s6    !



Tc                 C   s2   |dk	r|  |} tj| dd} dt| ||S )a  Convert an undirected graph to bytes in sparse6 format.

    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<<' bytes to head of data.

    Raises
    ------
    NetworkXNotImplemented
        If the graph is directed.

    ValueError
        If the graph has at least ``2 ** 36`` nodes; the sparse6 format
        is only defined for graphs of order less than ``2 ** 36``.

    Examples
    --------
    >>> nx.to_sparse6_bytes(nx.path_graph(2))
    b'>>sparse6<<:An\n'

    See Also
    --------
    to_sparse6_bytes, read_sparse6, write_sparse6_bytes

    Notes
    -----
    The returned bytes end with a newline character.

    The format does not support edge or node labels.

    References
    ----------
    .. [1] Graph6 specification
           <https://users.cecs.anu.edu.au/~bdm/data/formats.html>

    Nr+   Zordering    )subgraphr@   convert_node_labels_to_integersjoinr5   )r/   r0   r1   r   r   r   r	      s    ,
rb)modec                 C   sJ   g }| D ]$}|  }t|sq|t| qt|dkrB|d S |S dS )a  Read an undirected graph in sparse6 format from path.

    Parameters
    ----------
    path : file or string
       File or filename to write.

    Returns
    -------
    G : Graph/Multigraph or list of Graphs/MultiGraphs
       If the file contains multiple lines then a list of graphs is returned

    Raises
    ------
    NetworkXError
        If the string is unable to be parsed in sparse6 format

    Examples
    --------
    You can read a sparse6 file by giving the path to the file::

        >>> import tempfile
        >>> with tempfile.NamedTemporaryFile(delete=False) as f:
        ...     _ = f.write(b">>sparse6<<:An\n")
        ...     _ = f.seek(0)
        ...     G = nx.read_sparse6(f.name)
        >>> list(G.edges())
        [(0, 1)]

    You can also read a sparse6 file by giving an open file-like object::

        >>> import tempfile
        >>> with tempfile.NamedTemporaryFile() as f:
        ...     _ = f.write(b">>sparse6<<:An\n")
        ...     _ = f.seek(0)
        ...     G = nx.read_sparse6(f)
        >>> list(G.edges())
        [(0, 1)]

    See Also
    --------
    read_sparse6, from_sparse6_bytes

    References
    ----------
    .. [1] Sparse6 specification
           <https://users.cecs.anu.edu.au/~bdm/data/formats.html>

    r   r   N)stripr&   r-   r   )pathZglistliner   r   r   r      s    3Zdirectedr   wbc                 C   s@   |dk	r|  |} tj| dd} t| ||D ]}|| q,dS )a  Write graph G to given path in sparse6 format.

    Parameters
    ----------
    G : Graph (undirected)

    path : file or string
       File or filename to write

    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

    Raises
    ------
    NetworkXError
        If the graph is directed

    Examples
    --------
    You can write a sparse6 file by giving the path to the file::

        >>> import tempfile
        >>> with tempfile.NamedTemporaryFile(delete=False) as f:
        ...     nx.write_sparse6(nx.path_graph(2), f.name)
        ...     print(f.read())
        b'>>sparse6<<:An\n'

    You can also write a sparse6 file by giving an open file-like object::

        >>> with tempfile.NamedTemporaryFile() as f:
        ...     nx.write_sparse6(nx.path_graph(2), f)
        ...     _ = f.seek(0)
        ...     print(f.read())
        b'>>sparse6<<:An\n'

    See Also
    --------
    read_sparse6, from_sparse6_bytes

    Notes
    -----
    The format does not support edge or node labels.

    References
    ----------
    .. [1] Sparse6 specification
           <https://users.cecs.anu.edu.au/~bdm/data/formats.html>

    Nr+   rC   )rE   r@   rF   r5   write)r/   rK   r0   r1   r<   r   r   r   r
   :  s
    8
)NT)NT)__doc__Znetworkxr@   Znetworkx.exceptionr   Znetworkx.readwrite.graph6r   r   Znetworkx.utilsr   r   __all__r5   r   r	   r   r
   r   r   r   r   <module>   s   Ra
2

>
