U
    KcG-                     @   s   d dl mZ d dlZd dlZd dlZd dlmZmZ d dlm	Z	m
Z
 d dlmZ ddlmZmZ G dd dejjZd	d
 Zdd ZeG dd dZefejedddZdS )    N)CallableList)wrapspartial)	dataclass   )get_placeholdersget_outputsc                       s(   e Zd Z fddZ fddZ  ZS )ConcretePropc                    sD   t  |}d  fdd}ddlm} |||} r@||jd< |S )NFc                    s   t | tjrd | S | S d S )NT)
isinstancetorchTensor)objZfound_tensor >/tmp/pip-unpacked-wheel-gikjz4vx/functorch/_src/fx_minifier.pyextract_tensor_meta   s    z2ConcreteProp.run_node.<locals>.extract_tensor_metar   )map_aggregateconcrete_value)superrun_nodeZtorch.fx.noder   meta)selfnresultr   r   r   	__class__r   r   r      s    

zConcreteProp.run_nodec                    s   t  j| S N)r   run)r   argsr   r   r   	propagate   s    zConcreteProp.propagate)__name__
__module____qualname__r   r    __classcell__r   r   r   r   r
   
   s   r
   c                 C   s   | j dks| j dkrd S d| _ d| _i | _| j| _| jdd }t|tj	rX|
| n*|
td t| jD ]}t|| qrd S )Noutputplaceholderr   r   )opr   kwargsnametargetr   getr   r   r   appendzeroslistusers_convert_node_to_placeholder)nodeinpsZconcrete_valZ
tuple_userr   r   r   r0   #   s    r0   c                 C   s4   t dt| jj ddd |D  d| j d d S )Nz
# Working Repro with z nodes
inps = c                 S   s   g | ]}|j |j|jjfqS r   )shapeZdtypeZdevicetype).0ir   r   r   
<listcomp>5   s     zdump_state.<locals>.<listcomp>zo
inps = [torch.zeros(())] + [torch.ones(shape, dtype=dtype, device=device) for (shape, dtype, device) in inps]

)printlengraphnodescode)Zfx_gr2   r   r   r   
dump_state2   s    
r>   c                   @   s&   e Zd ZU ejed< eej ed< dS )
ReproStater;   r2   N)	r!   r"   r#   fxGraph__annotations__r   r   r   r   r   r   r   r?   :   s   

r?   )fail_fr>   c                    sd  j }t|j}dfddfddtj|  ||sPtdtd| d ttd	fd
dtdfdd}|dfdd
|dfdd	t	dddt	dfddfdd}|d||dfddd d!  |d"t
jd# fd$d%t	||}	
fd&d'}	|t
|j |j td(ttt|j j }
|	||
d)d*}|d+k	r|}qF|
d( }
d,}|
d-kr|	||
d,d*}|d+k	r|}d)}q|
d( }
q|rqF	|d-}|d+k	r|}qFqqF|j |js(td.td/ d0 t
|j }|||j td1 ||jfS )2a#  
    Minimizes a FX graph with given inputs, such that the resulting FX graph still returns True for module_fails.

    Does 2 main strategies:
    1. Truncates suffix: Removes some suffix from the graph and sets a new output.
    2. Delta Debugging: Tries replacing half of the graph with inputs. If fails,
        tries replacing quarter of the graph, etc.

    >>> failing_function = fx.symbolic_trace(f)
    >>> minimize(failing_function, [torch.randn(5)], lambda fx_g, inps: fx_g(*inps))

    note: module_fails returns True if it fails.
    r   c                    s   t  t| jS r   )r@   GraphModulecopydeepcopyr;   )Zfx_graph)rC   r   r   deepcopy_fx_graphR   s    z#minifier.<locals>.deepcopy_fx_graphc                    s2   t | } d7 t | }|j  ||S )Nr   )rE   rF   r@   rD   r;   Zlint)r;   r2   mod)rC   module_failsnum_queriesr   r   graph_failsV   s
    

zminifier.<locals>.graph_failsz#Input graph did not fail the testerzStarted off with  nodes)strategyr)   c                    s&   t dtd fdd}|S )Nr   )	old_statec           
   
      sL  t   t d d| dt| jj dt| j d	  | jt| j|}|d k	r:t|jj}t| jj}t|j}t| j}tt|j}tt| j}d}	||k rd}	t d| d	| d
 ||krd}	t d| d	| d ||k rd}	t d| d	| d |	std|j|js6t d d S |S t d  d S )Nz
Strategy: z (G: z) (z nodes, z inputs)FTzSUCCESS: Went from z to rL   z inputsz outputsz$Success raised but no progress made?z=WARNING: Something went wrong, not applying this minificationzFAIL: )r9   r:   r;   r<   r2   r.   r	   RuntimeError)
rN   granularity	new_stateZ	new_nodesZ	old_nodesnew_inpsZold_inpsZnew_outsZold_outsZprogress_made)rG   rK   r)   rM   r   r   new_funcd   s8    0



z6minifier.<locals>._register_strategy.<locals>.new_func)r   )r   r?   )rM   r)   rS   )rG   rK   )r)   rM   r   _register_strategyc   s    !z$minifier.<locals>._register_strategyr)   c                    s   t  | dS )NrU   )r   rU   )rT   r   r   register_strategy   s    z#minifier.<locals>.register_strategyzTruncate suffixc           	         s   t  }t }i  t| jD ]\}}|| fdd}|jdkr|| dkr||d  dkr||kr||f}t|jt| jk r||rt	||  S |
| || | |< qd S )Nc                    s    |  S r   r   xenvr   r   <lambda>       z1minifier.<locals>.remove_suffix.<locals>.<lambda>r&   r%   r      )setr@   rA   	enumerater<   	node_copyr'   r%   r:   r?   add
erase_node)		cur_graphcur_inpsrP   Ztested	new_graphidxr1   new_nodeZoutput_noderK   rY   r   remove_suffix   s    
$


zminifier.<locals>.remove_suffixzRemove outputsc                    s   t d|d }t| jD ] \}}||_|jdkr|} q:qt|jd dd d}t|dkr`d S tdt||D ]<}|d | ||| d   f|_ | |rpt	| |  S qpd S )Nr   r^   r%   r   c                 S   s   t | tjr| jS tdS )Ng    eA)r   r@   Noderg   intrW   r   r   r   r[      r\   z2minifier.<locals>.remove_outputs.<locals>.<lambda>)key)
maxr`   r<   rg   r'   sortedr   r:   ranger?   )rd   re   rP   rg   r1   r%   Zoutput_argsri   r   r   remove_outputs   s    
 
z minifier.<locals>.remove_outputs)	cur_statec                 S   s   | j }| j}t|}t|t|ks(tg }tt|D ]4}t|| jdkr^|||  q8|||  q8t|t|k rt	||S d S )Nr   )
r;   r2   r   r:   AssertionErrorrp   r/   rc   r,   r?   )rr   rd   re   Zph_nodesrR   rg   r   r   r   remove_unused_inputs_unchecked   s    
z0minifier.<locals>.remove_unused_inputs_uncheckedc                    s&   | }|d k	r" |j |jr"|S d S r   )r;   r2   )rr   rQ   )rK   rt   r   r   remove_unused_inputs_checked   s    z.minifier.<locals>.remove_unused_inputs_checkedc                    s    t | |S r   )r?   rd   re   rP   )ru   r   r   _remove_unused_wrapper   s    z(minifier.<locals>._remove_unused_wrapperzRemove unused inputszEliminate dead codec                    s    |   r | |rt| |S d S r   )eliminate_dead_coder?   rv   ri   r   r   rx      s    
z%minifier.<locals>.eliminate_dead_codec                    st   t  }i  | jD ]*}|jdkr|| fdd}| |< q| jD ]*}|jdkrD|| fdd}| |< qD|S )Nr&   c                    s    |  S r   r   rW   rY   r   r   r[      r\   z=minifier.<locals>._consolidate_placeholders.<locals>.<lambda>c                    s    |  S r   r   rW   rY   r   r   r[      r\   )r@   rA   r<   r'   ra   )rd   rf   r1   rh   r   rY   r   _consolidate_placeholders   s    





z+minifier.<locals>._consolidate_placeholderszDelta Debugging)rd   c                    s   t | j}td||D ]}d}| }|d d  }t||| }t||D ]*}	t|j|	 }
|
jdkrJd}t|
| qJ|s|q |}t||}|d krt||}|j|j	rt|j|j	  S qd S )Nr   Fr]   T)
r:   r<   rp   minr.   r'   r0   r?   r;   r2   )rd   re   rP   	num_nodesZstart_rangeZis_removingrf   rR   Z	end_rangerg   rh   rQ   )ry   rG   rK   rt   r   r   delta_debugging   s(    


z!minifier.<locals>.delta_debuggingc                    s   t d|  g }t| jj}tt| j}||d krB|g7 }|rR|g7 }| g7 }|D ]}|| |}|d k	rb|  S qbd S )NzTrying granularity r^   )r9   r:   r;   r<   r	   )failing_staterP   use_non_granularZ
strategiesr{   Znum_outputsrM   rQ   )r|   rx   rq   rj   remove_unused_inputsr   r   try_granularity   s    


z!minifier.<locals>.try_granularityr^   T)r~   NFr   z9Uh oh, something went wrong :( Final graph is not failingzMade z queriesz#Wrote minimal repro out to repro.py)r;   r:   r<   r
   r    rO   r9   r   strr?   r@   rA   rD   r2   rl   mathfloorlog2)rC   r2   rI   r>   Zfailing_graphZcur_sizerV   rw   r}   r   rP   rQ   Zhas_progressZ
failing_fxr   )ry   rT   rG   r|   rx   rC   rK   rI   rJ   rq   rj   r   ru   rt   r   minifier?   sn    

%
 




r   )Ztorch.fxr@   rE   r   r   typingr   r   	functoolsr   r   Zdataclassesr   Zcompile_utilsr   r	   ZInterpreterr
   r0   r>   r?   rD   r   r   r   r   r   <module>   s   