o
    <&i[                     @   s|  d Z ddlZddlZddlmZmZmZmZmZm	Z	m
Z
mZmZmZ ddlZe r.edddlZddlmZ g dZedZedZed	Zed
ZeZeZeZeege
ee ef f Zeee egef Zeeee gef ZeZeegef Zeegef Z dedefddZ!dddddee dededee" dee dee  ddfddZ#dddddee dededee" dee dee  ddfddZ$dddddee dededee" dee dee  ddfddZ%dede
ee ef fddZ&dee d edefd!d"Z'dedee fd#d$Z(dedefd%d&Z)ded'ef dedefd(d)Z*ded'ef dedefd*d+Z+e
ee ee f Z,e
ee ee ee f Z-eee e
ee d'f f Z.eeeef gef Z/eeeeef gef Z0eegef Z1eegef Z2eegeegef f Z3e	d,e,eef de3e/eeef  fd-d.Z4e	d,e-eeef de3e0eeeef  fd/d.Z4e	d,ee de3e1eef  fd0d.Z4e	d,e.de3e2e  fd1d.Z4d,e.de3e2e  fd2d.Z4e	d,ee de1eef dedefd3d4Z5e	d,e,eef de/eeef dedefd5d4Z5e	d,e-eeef de0eeeef dedefd6d4Z5d,e.de2e dedefd7d4Z5e	d,ee de1eef dedefd8d9Z6e	d,e,eef de/eeef dedefd:d9Z6e	d,e-eeef de0eeeef dedefd;d9Z6d,e.de2e dedefd<d9Z6d=eege7f dede7fd>d?Z8d=eege7f dede7fd@dAZ9e	d,ee d=e1ee7f dede7fdBdCZ:e	d,e,eef d=e/eee7f dede7fdDdCZ:e	d,e-eeef d=e0eeee7f dede7fdEdCZ:d,e.d=e2e7 dede7fdFdCZ:e	d,ee d=e1ee7f dede7fdGdHZ;e	d,e,eef d=e/eee7f dede7fdIdHZ;e	d,e-eeef d=e0eeee7f dede7fdJdHZ;d,e.d=e2e7 dede7fdKdHZ;dLedMedee fdNdOZ<ded edeee  fdPdQZ=dad edRee> de"fdSdTZ?dUe"defdVdWZ@G dXdY dYZAd ede"fdZd[ZBG d\d] d]eCeZDG d^d_ d_eeDd`ZEdS )ba  
Contains utility functions for working with nested python data structures.

A *pytree* is Python nested data structure. It is a tree in the sense that
nodes are Python collections (e.g., list, tuple, dict) and the leaves are
Python values. Furthermore, a pytree should not contain reference cycles.

pytrees are useful for working with nested collections of Tensors. For example,
one can use `tree_map` to map a function over all Tensors inside some nested
collection of Tensors and `tree_leaves` to get a flat list of all Tensors
inside some nested collection. pytrees are helpful for implementing nested
collection support for PyTorch APIs.
    N)
AnyCallableIterableListOptionaloverloadTupleTypeTypeVarUnionz4C++ pytree utilities do not work with torch::deploy.)
PyTreeSpec)PyTreeContextFlattenFuncUnflattenFuncDumpableContextToDumpableContextFnFromDumpableContextFnTreeSpecLeafSpecregister_pytree_nodetree_flattentree_unflattentree_leavestree_structuretree_map	tree_map_tree_map_onlytree_map_only_tree_alltree_anytree_all_onlytree_any_onlytreespec_dumpstreespec_loadstreespec_pprintTSURfuncreturnc                    s(   t  dtdtdtf fdd}|S )Nargskwargsr+   c                     s    t | i |S N)reversed)r,   r-   r*    BC:\wamp64\www\opt\env\Lib\site-packages\torch/utils/_cxx_pytree.pywrappedV   s   z_reverse_args.<locals>.wrapped)	functoolswrapsr   r*   r3   r1   r0   r2   _reverse_argsU   s   r7   serialized_type_nameto_dumpable_contextfrom_dumpable_contextcls
flatten_fnunflatten_fnr9   r:   r;   c                C   s:   t | |||||d ddlm} |j | |||||d dS )a  Register a container-like type as pytree node.

    Args:
        cls (type): A Python type to treat as an internal pytree node.
        flatten_fn (callable): A function to be used during flattening, taking an instance of
            ``cls`` and returning a pair, with (1) an iterable for the children to be flattened
            recursively, and (2) some hashable auxiliary data to be stored in the treespec and to be
            passed to the ``unflatten_fn``.
        unflatten_fn (callable): A function taking two arguments: the auxiliary data that was
            returned by ``flatten_fn`` and stored in the treespec, and the unflattened children.
            The function should return an instance of ``cls``.
        serialized_type_name (str, optional): A keyword argument used to specify the fully
            qualified name used when serializing the tree spec.
        to_dumpable_context (callable, optional): An optional keyword argument to custom specify how
            to convert the context of the pytree to a custom json dumpable representation. This is
            used for json serialization, which is being used in :mod:`torch.export` right now.
        from_dumpable_context (callable, optional): An optional keyword argument to custom specify
            how to convert the custom json dumpable representation of the context back to the
            original context. This is used for json deserialization, which is being used in
            :mod:`torch.export` right now.

    Example::

        >>> # xdoctest: +SKIP
        >>> # Registry a Python type with lambda functions
        >>> register_pytree_node(
        ...     set,
        ...     lambda s: (sorted(s), None, None),
        ...     lambda children, _: set(children),
        ... )
    r8      )_pytreeN)_private_register_pytree_node r@   )r<   r=   r>   r9   r:   r;   pythonr1   r1   r2   r   ]   s"   (	
r   c                C   s&   t jddd t| |||||d dS )a  Register a container-like type as pytree node for the C++ pytree only.

    The ``namespace`` argument is used to avoid collisions that occur when different libraries
    register the same Python type with different behaviors. It is recommended to add a unique prefix
    to the namespace to avoid conflicts with other libraries. Namespaces can also be used to specify
    the same class in different namespaces for different use cases.

    .. warning::
        For safety reasons, a ``namespace`` must be specified while registering a custom type. It is
        used to isolate the behavior of flattening and unflattening a pytree node type. This is to
        prevent accidental collisions between different libraries that may register the same type.

    Args:
        cls (type): A Python type to treat as an internal pytree node.
        flatten_fn (callable): A function to be used during flattening, taking an instance of
            ``cls`` and returning a pair, with (1) an iterable for the children to be flattened
            recursively, and (2) some hashable auxiliary data to be stored in the treespec and to be
            passed to the ``unflatten_fn``.
        unflatten_fn (callable): A function taking two arguments: the auxiliary data that was
            returned by ``flatten_fn`` and stored in the treespec, and the unflattened children.
            The function should return an instance of ``cls``.
        serialized_type_name (str, optional): A keyword argument used to specify the fully
            qualified name used when serializing the tree spec.
        to_dumpable_context (callable, optional): An optional keyword argument to custom specify how
            to convert the context of the pytree to a custom json dumpable representation. This is
            used for json serialization, which is being used in :mod:`torch.export` right now.
        from_dumpable_context (callable, optional): An optional keyword argument to custom specify
            how to convert the custom json dumpable representation of the context back to the
            original context. This is used for json deserialization, which is being used in
            :mod:`torch.export` right now.
    z}torch.utils._cxx_pytree._register_pytree_node is deprecated. Please use torch.utils._cxx_pytree.register_pytree_node instead.   )
stacklevelr8   N)warningswarnrA   r<   r=   r>   r9   r:   r;   r1   r1   r2   _register_pytree_node   s   (
rI   c                C   s(   t | st j| |t|dd dS dS )zThis is an internal function that is used to register a pytree node type
    for the C++ pytree only. End-users should use :func:`register_pytree_node`
    instead.
    torch)	namespaceN)optreeZis_structseq_classr   r7   rH   r1   r1   r2   rA      s   

rA   treec                 C      t j| dddS )a  Flatten a pytree.

    See also :func:`tree_unflatten`.

    The flattening order (i.e., the order of elements in the output list) is deterministic,
    corresponding to a left-to-right depth-first tree traversal.

    >>> tree = {'b': (2, [3, 4]), 'a': 1, 'c': None, 'd': 5}
    >>> tree_flatten(tree)
    ([1, 2, 3, 4, None, 5], PyTreeSpec({'a': *, 'b': (*, [*, *]), 'c': *, 'd': *}, NoneIsLeaf))
    >>> tree_flatten(1)
    ([1], PyTreeSpec(*, NoneIsLeaf))
    >>> tree_flatten(None)
    ([None], PyTreeSpec(*, NoneIsLeaf))

    For unordered dictionaries, :class:`dict` and :class:`collections.defaultdict`, the order is
    dependent on the **sorted** keys in the dictionary. Please use :class:`collections.OrderedDict`
    if you want to keep the keys in the insertion order.

    >>> from collections import OrderedDict
    >>> tree = OrderedDict([('b', (2, [3, 4])), ('a', 1), ('c', None), ('d', 5)])
    >>> tree_flatten(tree)
    ([2, 3, 4, 1, None, 5], PyTreeSpec(OrderedDict([('b', (*, [*, *])), ('a', *), ('c', *), ('d', *)]), NoneIsLeaf))

    Args:
        tree (pytree): A pytree to flatten.

    Returns:
        A pair ``(leaves, treespec)`` where the first element is a list of leaf values and the
        second element is a treespec representing the structure of the pytree.
    TrJ   none_is_leafrK   )rL   r   rM   r1   r1   r2   r      s
    r   leavestreespecc                 C   s*   t |tstdt| dt|| S )ad  Reconstruct a pytree from the treespec and the leaves.

    The inverse of :func:`tree_flatten`.

    >>> tree = {'b': (2, [3, 4]), 'a': 1, 'c': None, 'd': 5}
    >>> leaves, treespec = tree_flatten(tree)
    >>> tree == tree_unflatten(leaves, treespec)
    True

    Args:
        leaves (iterable): The list of leaves to use for reconstruction. The list must match the
            number of leaves of the treespec.
        treespec (TreeSpec): The treespec to reconstruct.

    Returns:
        The reconstructed pytree, containing the ``leaves`` placed in the structure described by
        ``treespec``.
    z^tree_unflatten(values, spec): Expected `spec` to be instance of TreeSpec but got item of type .)
isinstancer   	TypeErrortyperL   r   )rR   rS   r1   r1   r2   r     s   
r   c                 C   rN   )a^  Get the leaves of a pytree.

    See also :func:`tree_flatten`.

    >>> tree = {'b': (2, [3, 4]), 'a': 1, 'c': None, 'd': 5}
    >>> tree_leaves(tree)
    [1, 2, 3, 4, None, 5]
    >>> tree_leaves(1)
    [1]
    >>> tree_leaves(None)
    [None]

    Args:
        tree (pytree): A pytree to flatten.

    Returns:
        A list of leaf values.
    TrJ   rO   )rL   r   rQ   r1   r1   r2   r   ,  s   r   c                 C   rN   )a  Get the treespec for a pytree.

    See also :func:`tree_flatten`.

    >>> tree = {'b': (2, [3, 4]), 'a': 1, 'c': None, 'd': 5}
    >>> tree_structure(tree)
    PyTreeSpec({'a': *, 'b': (*, [*, *]), 'c': *, 'd': *}, NoneIsLeaf)
    >>> tree_structure(1)
    PyTreeSpec(*, NoneIsLeaf)
    >>> tree_structure(None)
    PyTreeSpec(*, NoneIsLeaf)

    Args:
        tree (pytree): A pytree to flatten.

    Returns:
        A treespec object representing the structure of the pytree.
    TrJ   rO   )rL   r   rQ   r1   r1   r2   r   B  s
   r   .c                 C      t j| |dddS )a	  Map a function over leaves in a pytree to produce a new pytree.

    See also :func:`tree_map_`.

    >>> tree_map(lambda x: x + 1, {'x': 7, 'y': (42, 64)})
    {'x': 8, 'y': (43, 65)}
    >>> tree_map(lambda x: x is None, {'x': 7, 'y': (42, 64), 'z': None})
    {'x': False, 'y': (False, False), 'z': True}

    Args:
        func (callable): A function that takes a single argument, to be applied at the corresponding
            leaves of the pytree.
        tree (pytree): A pytree to be mapped over, with each leaf providing the argument to function
            ``func``.

    Returns:
        A new pytree with the same structure as ``tree`` but with the value at each leaf given by
        ``func(x)`` where ``x`` is the value at the corresponding leaf in ``tree``.
    TrJ   rO   )rL   r   r*   rM   r1   r1   r2   r   \  s   r   c                 C   rX   )am  Like :func:`tree_map`, but do an inplace call on each leaf and return the original tree.

    See also :func:`tree_map`.

    Args:
        func (callable): A function that takes a single argument, to be applied at the corresponding
            leaves of the pytree.
        tree (pytree): A pytree to be mapped over, with each leaf providing the argument to function
            ``func``.

    Returns:
        The original ``tree`` with the value at each leaf is given by the side-effect of function
        ``func(x)`` (not the return value) where ``x`` is the value at the corresponding leaf in
        ``tree``.
    TrJ   rO   )rL   r   rY   r1   r1   r2   r   x  s   r   __type_or_typesc                 C      d S r.   r1   rZ   r1   r1   r2   map_only     r]   c                 C   r[   r.   r1   r\   r1   r1   r2   r]     r^   c                 C   r[   r.   r1   r\   r1   r1   r2   r]     r^   c                 C   r[   r.   r1   r\   r1   r1   r2   r]     r^   c                    s.   dt tgtf dt tgtf f fdd}|S )a  
    Suppose you are writing a tree_map over tensors, leaving everything
    else unchanged.  Ordinarily you would have to write:

        def go(t):
            if isinstance(t, Tensor):
                return ...
            else:
                return t

    With this function, you only need to write:

        @map_only(Tensor)
        def go(t):
            return ...

    You can also directly use 'tree_map_only'
    r*   r+   c                    s&   t  dtdtf fdd}|S )Nxr+   c                    s   t |  r	| S | S r.   rU   )r_   )rZ   r*   r1   r2   r3     s   
z*map_only.<locals>.wrapper.<locals>.wrapped)r4   r5   r&   r   r6   r\   r0   r2   wrapper  s   zmap_only.<locals>.wrapper)r   r&   r   )rZ   ra   r1   r\   r2   r]     s   *	c                 C   r[   r.   r1   rZ   r*   rM   r1   r1   r2   r        r   c                 C   r[   r.   r1   rb   r1   r1   r2   r     rc   c                 C   r[   r.   r1   rb   r1   r1   r2   r     rc   c                 C      t t| ||S r.   )r   r]   rb   r1   r1   r2   r        c                 C   r[   r.   r1   rb   r1   r1   r2   r     rc   r   c                 C   r[   r.   r1   rb   r1   r1   r2   r     rc   c                 C   r[   r.   r1   rb   r1   r1   r2   r     rc   c                 C   rd   r.   )r   r]   rb   r1   r1   r2   r     re   predc                 C      t |}tt| |S r.   )r   allmaprf   rM   	flat_argsr1   r1   r2   r        r   c                 C   rg   r.   )r   anyri   rj   r1   r1   r2   r      rl   r    c                 C   r[   r.   r1   rZ   rf   rM   r1   r1   r2   r!   #  rc   r!   c                 C   r[   r.   r1   rn   r1   r1   r2   r!   ,  rc   c                 C   r[   r.   r1   rn   r1   r1   r2   r!   5  rc   c                        t |}t fdd|D S )Nc                 3   "    | ]}t | r|V  qd S r.   r`   .0r_   rZ   rf   r1   r2   	<genexpr>D       z tree_all_only.<locals>.<genexpr>)r   rh   rZ   rf   rM   rk   r1   rs   r2   r!   >     c                 C   r[   r.   r1   rn   r1   r1   r2   r"   G  rc   r"   c                 C   r[   r.   r1   rn   r1   r1   r2   r"   P  rc   c                 C   r[   r.   r1   rn   r1   r1   r2   r"   Y  rc   c                    ro   )Nc                 3   rp   r.   r`   rq   rs   r1   r2   rt   h  ru   z tree_any_only.<locals>.<genexpr>)r   rm   rv   r1   rs   r2   r"   b  rw   prefix_tree	full_treec                 C   rX   )ag  Return a list of broadcasted leaves in ``prefix_tree`` to match the number of leaves in ``full_tree``.

    If a ``prefix_tree`` is a prefix of a ``full_tree``, this means the ``full_tree`` can be
    constructed by replacing the leaves of ``prefix_tree`` with appropriate **subtrees**.

    This function returns a list of leaves with the same size as ``full_tree``. The leaves are
    replicated from ``prefix_tree``. The number of replicas is determined by the corresponding
    subtree in ``full_tree``.

    >>> broadcast_prefix(1, [1, 2, 3])
    [1, 1, 1]
    >>> broadcast_prefix([1, 2, 3], [1, 2, 3])
    [1, 2, 3]
    >>> broadcast_prefix([1, 2, 3], [1, 2, 3, 4])
    Traceback (most recent call last):
        ...
    ValueError: list arity mismatch; expected: 3, got: 4; list: [1, 2, 3, 4].
    >>> broadcast_prefix([1, 2, 3], [1, 2, (3, 4)])
    [1, 2, 3, 3]
    >>> broadcast_prefix([1, 2, 3], [1, 2, {'a': 3, 'b': 4, 'c': (None, 5)}])
    [1, 2, 3, 3, 3, 3]

    Args:
        prefix_tree (pytree): A pytree with the same structure as a prefix of ``full_tree``.
        full_tree (pytree): A pytree with the same structure as a suffix of ``prefix_tree``.
        is_leaf (callable, optional): An optionally specified function that will be called at each
            flattening step. It should return a boolean, with :data:`True` stopping the traversal
            and the whole subtree being treated as a leaf, and :data:`False` indicating the
            flattening should traverse the current object.

    Returns:
        A list of leaves in ``prefix_tree`` broadcasted to match the number of leaves in ``full_tree``.
    TrJ   rO   )rL   broadcast_prefix)rx   ry   r1   r1   r2   rz   k  s   "rz   c                 C   sB   t |tsJ tdg|j |}zt| |W S  ty    Y d S w )Nr   )rU   r   r   
num_leavesrz   
ValueError)rM   rS   ry   r1   r1   r2   _broadcast_to_and_flatten  s   r}   protocolc                 C   sP   t | tstdt|  dddlm}m} |tdg| j | }|||dS )z&Serialize a treespec to a JSON string.zVtreespec_dumps(spec): Expected `spec` to be instance of TreeSpec but got item of type rT   r?   )r   r#   r   )r~   )	rU   r   rV   rW   r@   r   r#   r   r{   )rS   r~   Z_tree_structureZ_treespec_dumpsorig_treespecr1   r1   r2   r#     s   
r#   
serializedc                 C   s6   ddl m}m} || }|dg|j |}t|}|S )z*Deserialize a treespec from a JSON string.r?   )r   r$   r   )r@   r   r$   r{   r   )r   Z_tree_unflattenZ_treespec_loadsr   
dummy_treerS   r1   r1   r2   r$     s
   r$   c                   @   s   e Zd ZdefddZdS )
_DummyLeafr+   c                 C   s   dS )N*r1   )selfr1   r1   r2   __repr__  s   z_DummyLeaf.__repr__N)__name__
__module____qualname__strr   r1   r1   r1   r2   r     s    r   c                 C   s"   t dd t| jD | }t|S )Nc                 S   s   g | ]}t  qS r1   )r   )rr   _r1   r1   r2   
<listcomp>  s    z#treespec_pprint.<locals>.<listcomp>)r   ranger{   repr)rS   r   r1   r1   r2   r%     s
   r%   c                   @   s   e Zd ZdedefddZdS )LeafSpecMetainstancer+   c                 C   s   t |to| S r.   )rU   r   Zis_leaf)r   r   r1   r1   r2   __instancecheck__  s   zLeafSpecMeta.__instancecheck__N)r   r   r   objectboolr   r1   r1   r1   r2   r     s    r   c                   @   s   e Zd ZdddZdS )r   r+   c                 C   s   t jddS )NT)rP   )rL   Ztreespec_leaf)r<   r1   r1   r2   __new__  s   zLeafSpec.__new__N)r+   r   )r   r   r   r   r1   r1   r1   r2   r     s    r   )	metaclassr.   )F__doc__r4   rF   typingr   r   r   r   r   r   r   r	   r
   r   rJ   Z_running_with_deployImportErrorrL   r   __all__r&   r'   r(   r)   r   r   r   r   r   ZOpTreeUnflattenFuncr   r   r   r7   r   r   rI   rA   r   r   r   r   r   r   ZType2ZType3ZTypeAnyZFn2ZFn3ZFnZFnAnyZ	MapOnlyFnr]   r   r   r   r   r    r!   r"   rz   r}   intr#   r$   r   r%   rW   r   r   r1   r1   r1   r2   <module>   s   0
B
=
'*.$ 





  


	


	2	