U
    dQ                     @   s   d dl mZ d dlmZ d dlmZmZ eedddZdeeedd	d
Z	eeege
f ee dddZeedddZeedddZG dd dZdS )    wrapsunwrap)CallableList)fnreturnc                    s   t   fdd}|S )z
    Convenience wrapper for passes which modify an object inplace. This
    wrapper makes them return the modified object instead.

    Args:
        fn (Callable[Object, Any])

    Returns:
        wrapped_fn (Callable[Object, Object])
    c                    s    |  | S N )Zgmr   r   @/tmp/pip-unpacked-wheel-ua33x9lu/torch/fx/passes/pass_manager.py
wrapped_fn   s    z#inplace_wrapper.<locals>.wrapped_fnr   )r   r   r   r   r   inplace_wrapper   s    r   N	base_passn_iter	predicatec                    s4   dk	dk	A st dt  fdd}|S )aW  
    Convenience wrapper for passes which need to be applied multiple times.

    Exactly one of `n_iter`or `predicate` must be specified.

    Args:
        base_pass (Callable[Object, Object]): pass to be applied in loop
        n_iter (int, optional): number of times to loop pass
        predicate (Callable[Object, bool], optional):

    Nz8Exactly one of `n_iter`or `predicate` must be specified.c                    sb   | }d k	r,dkr,t D ]} |}qn2d k	rH|r^ |}q4ntd d d|S )Nr   z3loop_pass must be given positive int n_iter (given z) xor predicate (given ))rangeRuntimeError)sourceoutput_r   r   r   new_pass,   s    zloop_pass.<locals>.new_pass)AssertionErrorr   )r   r   r   r   r   r   r   	loop_pass   s    r   )
constraintpassesc                 C   sn   t |D ]`\}}t ||d d  D ]B\}}| ||r8q$td| d| d| d| d| d| dq$qd S )	N   z,pass schedule constraint violated. Expected z before z but found z
 at index z and z	 at indexz in pass list.)	enumerater   )r   r   iajbr   r   r   "_validate_pass_schedule_constraintC   s    
(r%   )thisthatc                    s   t t d fdd}|S )zd
    Defines a partial order ('depends on' function) where `this` must occur
    before `that`.
    r"   r$   c                    s   |  kr|krdS dS NFTr   r(   r'   r&   r   r   
depends_onW   s    z4this_before_that_pass_constraint.<locals>.depends_onr   )r&   r'   r+   r   r*   r    this_before_that_pass_constraintQ   s    r-   thesethosec                    s   t t d fdd}|S )a_  
    Defines a partial order ('depends on' function) where `these` must occur
    before `those`. Where the inputs are 'unwrapped' before comparison.

    For example, the following pass list and constraint list would be invalid.
    ```
    passes = [
        loop_pass(pass_b, 3),
        loop_pass(pass_a, 5),
    ]

    constraints = [
        these_before_those_pass_constraint(pass_a, pass_b)
    ]
    ```

    Args:
        these (Callable): pass which should occur first
        those (Callable): pass which should occur later

    Returns:
        depends_on (Callable[[Object, Object], bool]
    r(   c                    s    t | krt | krdS dS r)   r   r(   r.   r   r   r+   x   s    z6these_before_those_pass_constraint.<locals>.depends_onr,   )r/   r0   r+   r   r.   r   "these_before_those_pass_constraint_   s    r1   c                   @   sz   e Zd ZU dZg Zee ed< g Zee ed< dZ	e
ed< dddZed	d
 ZedddZdd Zdd Zdd ZdS )PassManageraT  
    Construct a PassManager.

    Collects passes and constraints. This defines the pass schedule, manages
    pass constraints and pass execution.

    Args:
        passes (Optional[List[Callable]]): list of passes. A pass is a
            callable which modifies an object and returns modified object
        constraint (Optional[List[Callable]]): list of constraints. A
            constraint is a callable which takes two passes (A, B) and returns
            True if A depends on B and False otherwise. See implementation of
            `this_before_that_pass_constraint` for example.
    r   constraintsF
_validatedNc                 C   s   |r
|| _ |r|| _d S r
   )r   r3   )selfr   r3   r   r   r   __init__   s    zPassManager.__init__c                 C   s   t |}|S r
   )r2   )clsr   Zpmr   r   r   build_from_passlist   s    zPassManager.build_from_passlist)_passc                 C   s   | j | d| _d S NF)r   appendr4   )r5   r9   r   r   r   add_pass   s    zPassManager.add_passc                 C   s   | j | d| _d S r:   )r3   r;   r4   r5   r   r   r   r   add_constraint   s    zPassManager.add_constraintc                 C   s,   | j r
dS | jD ]}t|| j qd| _ dS )z
        Validates that current pass schedule defined by `self.passes` is valid
        according to all constraints in `self.constraints`
        NT)r4   r3   r%   r   r=   r   r   r   validate   s
    
zPassManager.validatec                 C   s$   |    |}| jD ]}||}q|S r
   )r?   r   )r5   r   outr9   r   r   r   __call__   s
    

zPassManager.__call__)NN)__name__
__module____qualname____doc__r   r   r   __annotations__r3   r4   boolr6   classmethodr8   r<   r>   r?   rA   r   r   r   r   r2      s   
  


r2   )NN)	functoolsr   inspectr   typingr   r   r   intr   rG   r%   r-   r1   r2   r   r   r   r   <module>   s   ( !