o
    OeW                     @   s   d dl mZ d dlZd dlmZ d dlmZ d dlmZm	Z	 d dl
mZ ddlmZmZ dd	lmZmZmZmZ dd
lmZmZmZmZ ddlmZmZmZmZ dddZdd ZG dd de Z!G dd de Z"dd Z#ej$dddZ%ej$dddZ&dS )    )OrderedDictN)compat)	framework)Operatordefault_main_program)
as_tensors   )add
fill_const)lookup_orig2primlookup_prim2origop_position_inputsop_position_output)_jvp
_orig2prim
_prim2orig
_transpose)flattenflatten_and_remove_noneget_input_var_listget_output_var_listc                    s8  |du r	t   n|}g }g }t  t | D ]}|du s&|j|ks&J d| t|< q fdd}|jD ]}||rP|| tt|D ]}| t|< qGq6t fdd|D fdd}	t	|D ]}|	|r|| tt
|D ]}|t|< qwqffdd	| D }
 fd
d	|D }tt	||
|fS )a  Returns the list of ops on the path from `xs` to `ys` in topological
    order.

    TODO(Tongxin): supporting control flow and nested blocks.
    Args:
        xs: a list|tuple of vars as source
        ys: a list|tuple of vars as sink
        block: the program block containing the path, optional
    Returns:
        (path, unused_xs, unreached_ys): a tuple comprised of the resulting op
        path, the unused variables in `xs`, and the unreached variables in `ys`
    Nz"x is not None and x.block != blockc                       t  fddtt| D S )Nc                 3       | ]	}t | v V  qd S Nid.0vreached_vars ND:\Projects\ConvertPro\env\Lib\site-packages\paddle/incubate/autograd/primx.py	<genexpr>D   
    

.topo_path.<locals>.<lambda>.<locals>.<genexpr>)anyr   r   opr   r!   r"   <lambda>D       
ztopo_path.<locals>.<lambda>c                 3   s(    | ]}t | v rt ||fV  qd S r   r   r   yr   r!   r"   r#   R   s   & ztopo_path.<locals>.<genexpr>c                    r   )Nc                 3   r   r   r   )r   out	used_varsr!   r"   r#   S   r$   r%   )r&   r   r   r'   r.   r!   r"   r)   S   r*   c                       g | ]
}t | vr|qS r!   r   r   xr.   r!   r"   
<listcomp>_       ztopo_path.<locals>.<listcomp>c                    r0   r!   r   r+   r   r!   r"   r3   `   r4   )r   current_blockr   blockr   opsappendr   r   reversedr   list)xsysr6   pathZbackpathr2   Zreachingr(   varZback_reaching	unused_xsZunreached_ysr!   )r    r/   r"   	topo_path'   s8   


r@   c                 C   s2   t  }| D ]}tt|D ]}||t|< qq|S )zReturns the output variables of all the ops on the path from `xs`
    to `ys`.

    Args:
        path: a list of ops on which to find the output variables

    Returns:
        vars: the output vars
    )r   r   r   r   )r=   varsr(   r-   r!   r!   r"   output_vars_on_pathe   s   
rB   c                   @   s`   e Zd ZdZg dZdd Zdd Zdd Zd	d
 Zdd Z	dd Z
dd Zdd Zdd ZdS )VarMapz~A general map data structure for linking variables to variables.

    An example is linking variables to their gradients.
    )namevarsettabc                 C   s   || _ || _t | _d S r   )rD   rE   r   rF   )selfrD   rE   r!   r!   r"   __init__   s   zVarMap.__init__c                 C   s   t || jt |< d S r   r   rF   )rG   key_var	value_varr!   r!   r"   r	      s   z
VarMap.addc                 C   s   |d u rd S t |tjjjr*t |tjjjstdt| t|| jt|< d S t	|t	|ksAJ dt	| dt	| dt
||D ]
\}}| || qFd S )Nz%value_vars must be Variable, but got zDlen(key_vars) shoule be equal to len(value_vars), but len(key_vars)=z and len(value_vars)=.)
isinstancepaddlefluidr   Variable	TypeErrortyper   rF   lenzipadd_rec)rG   key_vars
value_varsrJ   rK   r!   r!   r"   rU      s$   zVarMap.add_recc                 C   s(   | j t|}|d ur| j|S d S r   )rF   getr   rE   )rG   rJ   Zvalue_idr!   r!   r"   lookup   s   zVarMap.lookupc                 C   s&   t |}|| jv r| jt |= d S d S r   rI   )rG   rJ   varidr!   r!   r"   delete   s   
zVarMap.deletec                 C   s(   |D ]}t |}|| jv r| j|= qd S r   rI   )rG   rV   r>   rZ   r!   r!   r"   delete_keyvars   s   
zVarMap.delete_keyvarsc                    s<   dd |D   fdd| j  D }|D ]}| j |= qd S )Nc                 S   s   g | ]}t |qS r!   r   r   r!   r!   r"   r3      s    z+VarMap.delete_valuevars.<locals>.<listcomp>c                    s   g | ]
\}}| v r|qS r!   r!   )r   kr   Zidsr!   r"   r3      r4   )rF   items)rG   rW   keysr]   r!   r^   r"   delete_valuevars   s
   
zVarMap.delete_valuevarsc                 C   s   | j t|S r   )rF   __contains__r   )rG   rJ   r!   r!   r"   contain_var   s   zVarMap.contain_varc                 C   s   t || j v S r   )r   rF   values)rG   rK   r!   r!   r"   contain_value   s   zVarMap.contain_valueN)__name__
__module____qualname____doc__	__slots__rH   r	   rU   rY   r[   r\   ra   rc   re   r!   r!   r!   r"   rC   w   s    rC   c                   @   sd   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd ZdddZdddZdS )	TransformzXAn object that maintains the state of transformations applied to a
    primitve program.c                 C   sH   |t   ksJ d|| _| || _td| j| _td| j| _d S )Nz8only support transform on current block of main program.var2dotZdot2var)r   r5   r6   	init_varsrA   rC   rl   dot2bar)rG   r6   r!   r!   r"   rH      s   zTransform.__init__c                 C   s*   t  }|j D ]
\}}||t|< q|S r   )r   rA   r_   r   )rG   r6   rA   _r>   r!   r!   r"   rm      s   zTransform.init_varsc                 C   s   | j dd |D  d S )Nc                 S   s   i | ]}|d urt ||qS r   r   r   r!   r!   r"   
<dictcomp>       z&Transform.add_vars.<locals>.<dictcomp>)rA   update)rG   new_varsr!   r!   r"   add_vars   s   zTransform.add_varsc                 C   sh   |d u rd S t |tjjjr| jt||i d S t |ts(t	dt
| |D ]}| | q*d S )Nznew_vars must be list, but got )rM   rN   rO   r   rP   rA   rr   r   r:   rQ   rR   add_vars_rec)rG   rs   r>   r!   r!   r"   ru      s   
zTransform.add_vars_recc                 C   sH   | j }t|D ]}|j||d  qt|D ]}|j|= q|  d S )Nr   )r6   r9   desc
_remove_opr7   _sync_with_cpp)rG   Zordered_indexesr6   Zop_indexr!   r!   r"   	erase_ops   s   
zTransform.erase_opsc                 C   sx   |D ]}t || jv r| jt |= q| j| | j| | j}|D ]}|j}|j	t
| |j|= q#|  d S r   )r   rA   rn   r\   rl   ra   r6   rD   rv   _remove_varcptto_bytesrx   )rG   Zvars_to_eraser>   r6   rD   r!   r!   r"   
erase_dots   s   
zTransform.erase_dotsc                    s6   t |tjjjr j|}|S  fdd|D }|S )zLookup var2dot recursively.c                       g | ]}  |qS r!   )var2dot_recr   r>   rG   r!   r"   r3          z)Transform.var2dot_rec.<locals>.<listcomp>)rM   rN   rO   r   rP   rl   rY   )rG   rA   dotdotsr!   r   r"   r      s
   zTransform.var2dot_recc                    sF   t |tjjjr j|}|d usJ d|S  fdd|D }|S )Nzbar must be not Nonec                    r~   r!   )dot2bar_rec)r   r   r   r!   r"   r3     r   z)Transform.dot2bar_rec.<locals>.<listcomp>)rM   rN   rO   r   rP   rn   rY   )rG   r   barZbarsr!   r   r"   r      s   zTransform.dot2bar_recNc                    sH  |du rdd |D }  | nt|t|ks'J dt| dt| t||D ]/\}}|j|jksBJ d|j d|j |j|jksTJ d|j d	|j  j|| q,t|| j\}}}|D ]} j	| qh|D ]#}	t
|	}
 |
}t|	g|R  } | t|	} j|| qs fd
d|D }||fS )a  Performs the linearization transform, a.k.a, forward mode AD
        transform, on a primitive lowered program.

        Args:
            xs: a list of input variables
            ys: a list of output variables
            xs_dot: optional, a list of gradient input variables. The list size
                must be equal to `len(xs)`. The shape and dtype of each element
                must be the same as in `xs`

        Returns:
            (xs_dot, ys_dot): a tuple of two lists. `xs_dot` is the list of
            gradient inputs of the resulting linearized program. `ys_dot` is
            the list gradient outputs of the resulting linearized program

        Nc                 S   s   g | ]}t d |j|jdqS )      ?shapedtype)r
   r   r   r1   r!   r!   r"   r3     rq   z'Transform.linearize.<locals>.<listcomp>z4len(xs) should be equal to len(xs_dot), but len(xs)=z and len(xs_dot)=z2x.dtype should be equal to dot.dtype, but x.dtype=z and dot.dtype=z2x.shape should be equal to dot.shape, but x.shape=z and dot.shape=c                       g | ]} j |qS r!   )rl   rY   r+   r   r!   r"   r3   <      )rt   rS   rT   r   r   rl   r	   r@   r6   r[   r   r   r   ru   r   rU   )rG   r;   r<   xs_dotr2   r   r=   r?   ro   r(   insZjvp_insZouts_dotZoutsys_dotr!   r   r"   	linearize  sL   

zTransform.linearizeFc                    s  t dd |D sJ dt dd |D sJ d|du r7g }|D ]}|td|j|jd q"| nDt|t|ksMJ d	t| d
t| t||D ](\}}|j|jkshJ d|j d|j |j|jkszJ d|j d|j qRt||D ]\}}	j	||	 qt
||j\}
}}|D ]}j| qt|
  dd |D   fdd}t|
D ]y}t|}|}t|||}t|trt|}n|g}| t|}tt|}t|t|ksJ dt| dt| t||D ]0\}}	|	dur0j|}|du rj	||	 qt	||	}|g j	|| qqfdd|D }|st|
dkrt }|
D ]}|tt| qKg }j}t|jD ]\}}||
v r~|| |
d t|
dkr~ nqb | !| ||fS )a  Performs the transpose transform, a.k.a, reverse mode AD
        transform, on a linearized primitive program.

        Note, `transpose` is supposed to be used in couple with `linearize`.

        Args:
            ys_dot: a list of outputs of the linearized program.
            xs_dot: a list of inputs of the linearized program.
            ys_bar: optional, a list of inputs of the resulting transposed
                program. The list size must be equal to `len(ys_dot)`. The shape
                and dtype of each element must be the same as in `ys_dot`

        Returns:
            (ys_bar, xs_bar): a tuple of two lists. `ys_bar` is the list of
            inputs of the resulting transposed program. `xs_bar` is
            the list outputs of the resulting transposed program

        c                 s       | ]}|d uV  qd S r   r!   r   r!   r!   r"   r#   R      z&Transform.transpose.<locals>.<genexpr>z`xs_dot` includes None.c                 s   r   r   r!   r   r!   r!   r"   r#   S  r   z`ys_dot` includes None.Nr   r   z<len(ys_dot) should be equal to len(ys_bar), but len(ys_dot)=z and len(ys_bar)=z<y_dot.shape should be equal to y_bar.shape, but y_dot.shape=z and y_bar.shape=z<y_dot.dtype should be equal to y_bar.dtype, but y_dot.dtype=z and y_bar.dtype=c                 s   s    | ]	}t ||fV  qd S r   r   r   r!   r!   r"   r#   t  s    c                    s   t |  v S r   r   )r   )dotvarsr!   r"   r)   v  s    z%Transform.transpose.<locals>.<lambda>z7len(ins) should be equal to len(ins_bar), but len(ins)=z and len(ins_bar)=c                    r   r!   )rn   rY   r1   r   r!   r"   r3     r   z'Transform.transpose.<locals>.<listcomp>r   )"allr8   r
   r   r   rt   rS   rT   rn   r	   r@   r6   r[   rB   rr   r9   r   r   r   rM   tupler:   ru   r   r   rY   setr   r   	enumerater7   popry   r}   )rG   r   r   Zys_barZ
retain_fwdr,   Zy_dotZy_barr   r   r=   Zunused_xs_dotro   Zis_dotr(   r-   Zout_bar_recZins_bar_recZins_barr   ZgradZxs_barvars_to_removeZ
op_indexesr6   ir!   )r   rG   r"   	transpose?  s   












zTransform.transposer   )NF)rf   rg   rh   ri   rH   rm   rt   ru   ry   r}   r   r   r   r   r!   r!   r!   r"   rk      s    		

;rk   c                    sZ   fdd fddfdd|rt nt}|rtnt}i }i }i }| j D ]}| | || < q)g }	t }
t	t
| jD ]}| j| }|	| ||jd ur|j|vrt|} ||| tt|t||g|R  D ]'\}}|d u |d u A rJ d|
|j |||j< |j||j< |j||j< qxqCi }t	t
|jD ]}||j| |||j| < qi }t	t
|jD ]}||j| ||j| < qi }t|jD ]	}||||< qdd	lm} | j }||( || t| ||j|||d
}W d    n	1 sw   Y  W d    n	1 s"w   Y  | j| qCt|	D ]}| j||d  | j|= q2|    t	t
| jD ]0}| j| }|j!D ]}||v rg|"|||  qX|j#D ]}||v r{|$|||  qlqNt|
D ]#}||v sJ d%|||| kr| j&t'(| | j)|= q|    d S )Nc                    sf   t t| D ]*}t| | tr | | || q| | d ur0| | j|v r0||| | j  | |< qd S r   )rangerS   rM   r:   rD   )argsto_bindvalue_tabler   )bindr!   r"   r     s   z_lower.<locals>.bindc                    sH   g }| D ]}t |tr| || q|||v r|| n| q|S r   rM   r:   r8   )namesr   return_listrD   )	bind_namer!   r"   r     s   
z_lower.<locals>.bind_namec                    s4   g }| D ]}t |tr| | }q|| q|S r   r   )r;   r   r2   )expand_nested_listr!   r"   r     s   
z"_lower.<locals>.expand_nested_listz"orig_out and new_out should match.r   )param_guard)r6   rv   rR   inputsoutputsattrsr   z$var_name "{}" is not in to_bind_rev.)*r   r   r   r   rv   Zall_varsr>   rD   r   r   rS   r7   r8   rR   r   rT   r   r   r	   Zinput_namesinputZoutput_namesoutputsortedZ
attr_namesattrZpaddle.fluid.dygraph.baser   Z	append_opr   r9   rw   rx   Zinput_arg_namesZ_rename_inputZoutput_arg_namesZ_rename_outputformatrz   r{   r|   rA   )r6   reverse	blacklistZlower_fnZ	lookup_fnr   r   Zto_bind_revr>   Zops_to_remover   Zop_idxr(   Z
input_argsZorig_outZnew_outr   r   r   r   rD   r   Znew_op_descZin_nameZout_namevar_namer!   )r   r   r   r"   _lower  s   	





 	




r   c                 C   s>   | du r	t   n| } | t   ksJ dt| dg d dS )a'  
    Note:
        **This API is ONLY available in the static mode.**
        **Args block must be None or current block of main program.**

    All operators in the target block are processed as follows.
    If it is an original operator, it will be transformed into
    one or a series of automatic differential basic operators with
    equivalent function.

    Args:
        block(paddle.static.Block|None, optional): The
            target block to process on. Default None, and will
            process on the current block of main program.
    N7block is neither None nor current block of main programFr   r   r   r5   r   )r6   r!   r!   r"   	orig2prim#  s
   r   c                 C   sN   | du r	t   n| } | t   ksJ d|du rg n|}t| d|d dS )a  
    Note:
        **ONLY available in the static mode.**
        **Args block must be None or current block of main program.**

    All operators in the target block are processed as follows.
    If it is an automatic differential basic operator, it will be
    transformed into one or a series of original operators with
    equivalent function to support execution.

    Args:
        block(paddle.static.Block|None, optional): The
            target block to process on. Default None, and will
            process on the current block of main program.
        blacklist(list[string]|None, optional): The names of automatic
            differential basic operator that will not be transformed
            into original operators. Default None, and the blacklist
            is treated as empty list.

    Examples:

        .. code-block:: python

            import paddle
            from paddle.incubate.autograd import enable_prim, prim_enabled, prim2orig

            paddle.enable_static()
            enable_prim()

            x = paddle.ones(shape=[2, 2], dtype='float32')
            x.stop_gradients = False
            y = x * x
            dy_dx = paddle.static.gradients(y, x)
            if prim_enabled():
                prim2orig()
    Nr   Tr   r   )r6   r   r!   r!   r"   	prim2orig<  s   'r   r   )NN)'collectionsr   rN   r   r{   Zpaddle.fluidr   Zpaddle.fluid.frameworkr   r   Zpaddle.incubate.autograd.utilsr   Zprimopsr	   r
   Zprimregr   r   r   r   Z	primrulesr   r   r   r   utilsr   r   r   r   r@   rB   objectrC   rk   r   Zstatic_onlyr   r   r!   r!   r!   r"   <module>   s(   
>A {q