U
    ¹mœdç'  ã                   @   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�r€t ˆ ƒ 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  �q¼d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   úS/home/sam/Atlas/atlas_env/lib/python3.8/site-packages/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Ä qðq–||krÒ|}q–| ||¡râd}| ||¡ q–|sþt 	|¡}|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 r®z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

>
