U
    yh                  
   @   s  d dl Z d dlZd dlZd dlZd dlZd dlmZ d dlmZm	Z	m
Z
mZmZmZmZmZmZ d dlZd dlmZmZmZmZmZ ddlmZ erd dlmZ d dlmZ d	d
lmZm Z  dddddgZ!G dd de"Z#G dd de#Z$G dd de#Z%ddde&ee' ee' dddZ(ddde&ee' ee' dddZ)ej*G dd dZ+G dd de"Z,dCdd Z-ej*G d!d" d"e+e,d#Z.ej*G d$d% d%Z/ej*G d&d' d'e+Z0ee.e0f Z1dDej2e'ee& d(d)dZ3e1e	e'e'ged* f d+eed,  eed*ed- e	f  e
e&d.f d/d0d1Z4e	d2ef eeed3d4d5Z5dEd7d8Z6G d9d: d:Z7dFe	eed2f ee
e&ef  eee
e&ef ee ee f  eee1  d;d<d=Z8ee
e&ef ee ee df d>d?d@Z9e&ee
e&ef ee ee f ee
e&ef ee ee f dAdBdZ:dS )G    N)defaultdict)	AnyCallableDictListOptionalSetTupleTYPE_CHECKINGUnion)_get_node_typeBUILTIN_TYPESSUPPORTED_NODEStree_flattentree_map   )ExportedProgram)Symbol)Source   )ShapeEnvStrictMinMaxConstraint
ConstraintDimdimsdynamic_dim*refine_dynamic_shapes_from_suggested_fixesc                   @   s\   e Zd ZdZe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 )_Dimz*
    Metaclass for :func:`Dim` types.
    c                 C   s   |dkrd }|t jd krd }|d kr:|d kr:d|  dS |d krTd|  d| dS |d krnd|  d| dS d|  d| d| dS )	Nr   r   zDim('z')z', max=)z', min=, max=)sysmaxsize)namemin_max_ r%   M/var/www/html/venv/lib/python3.8/site-packages/torch/export/dynamic_shapes.pyreadable*   s    z_Dim.readablec                    s6   t  tk	r$td  d| j d|  fddS )NzAttempted to add z to m, where an integer was expected. (Only increasing linear operations with integer coefficients are supported.)c                    s   |   S Nr%   xotherr%   r&   <lambda>?       z_Dim.__add__.<locals>.<lambda>typeintNotImplementedError__name___deriveclsr-   r%   r,   r&   __add__8   s
    z_Dim.__add__c                 C   s   | | S r)   r%   r6   r%   r%   r&   __radd__A   s    z_Dim.__radd__c                    s6   t  tk	r$td  d| j d|  fddS )NzAttempted to subtract z from r(   c                    s   |   S r)   r%   r*   r,   r%   r&   r.   K   r/   z_Dim.__sub__.<locals>.<lambda>r0   r6   r%   r,   r&   __sub__D   s
    z_Dim.__sub__c                 C   s   t d| j dd S )NzAttempted to negate zN. (Only increasing linear operations with integer coefficients are supported.))r3   r4   r6   r%   r%   r&   __rsub__M   s    z_Dim.__rsub__c                    s>   t  tk	s dkr,td  d| j d|  fddS )Nr   zAttempted to multiply z with zu, where a positive integer was expected. (Only increasing linear operations with integer coefficients are supported.)c                    s   |   S r)   r%   r*   r,   r%   r&   r.   Z   r/   z_Dim.__mul__.<locals>.<lambda>r0   r6   r%   r,   r&   __mul__S   s
    z_Dim.__mul__c                 C   s   | | S r)   r%   r6   r%   r%   r&   __rmul__\   s    z_Dim.__rmul__c                 C   s   ddl m} t||| jS )Nr   )sympify)sympyr>   strr4   )r7   fnr>   r%   r%   r&   _derived_name_   s    z_Dim._derived_namec                 C   s   t | |tf| |dS )NrootrA   )_DerivedDimrB   r2   )r7   rA   r%   r%   r&   r5   d   s    z_Dim._deriveN)r4   
__module____qualname____doc__staticmethodr'   r8   r9   r:   r;   r<   r=   rB   r5   r%   r%   r%   r&   r   %   s   
			r   c                   @   s(   e Zd ZdZedd Zedd ZdS )
_StaticDimz
    Meta class for static :func:`Dim` types.

    This class is only for setting and checking static dim constraints,
    and the user should never interact with it.
    c                 C   s   | j S r)   valueselfr%   r%   r&   minp   s    z_StaticDim.minc                 C   s   | j S r)   rK   rM   r%   r%   r&   maxt   s    z_StaticDim.maxN)r4   rF   rG   rH   propertyrO   rP   r%   r%   r%   r&   rJ   h   s
   
rJ   c                   @   s0   e Zd ZdZedd Zedd Zdd ZdS )	rE   a  
    Metaclass for derived :func:`Dim` types.

    Currently we only support increasing linear expressions with integer coefficients.
    In other words, a derived Dim can always be written in the form Ax + B, where
    x is a regular Dim (i.e., non-derived Dim), A and B are integers, and A is positive.
    (In particular, the latter ensures that x < y => Ax + B < Ay + B.)
    These restrictions on the form of derived Dims makes the metatheory simpler: e.g.,
    it simplifies computing ranges for derived Dims, solving for underlying regular Dims,
    deciding equalities between derived Dims, and so on.

    The function lambda x: Ax + B is expressed by `fn`, where x is a normal Dim, `root`.
    The range of a derived Dim is computed by mapping `fn` over the range of its `root`.
    c                 C   sV   ddl m} | || jj}| j}|dksNtd| j d|j d|j dt|S )Nr   IntegerzExpected derived min value of z9 to be >= 0. Please specify an appropriate min value for  (currently ).)r?   rS   rA   rD   rO   AssertionErrorr4   r2   )rN   rS   Z_min_symintrD   r%   r%   r&   rO      s    
z_DerivedDim.minc              
   C   sh   ddl m} | || jj}| j}|tjd ks`td| j dtjd  d|j d|j d	t	|S )	Nr   rR   r   zExpected derived max value of z
 to be <= z.. Please specify an appropriate max value for rT   rU   )
r?   rS   rA   rD   rP   r    r!   rV   r4   r2   )rN   rS   Z_max_symintrD   r%   r%   r&   rP      s    (z_DerivedDim.maxc                    s&   t  tfj fdddS )Nc                    s     | S r)   )rA   r*   rA   rN   r%   r&   r.      r/   z%_DerivedDim._derive.<locals>.<lambda>rC   )rE   rB   r2   rD   )rN   rA   r%   rW   r&   r5      s
    z_DerivedDim._deriveN)r4   rF   rG   rH   rQ   rO   rP   r5   r%   r%   r%   r&   rE   y   s   

rE   rO   rP   )r"   rO   rP   c                C   s   |dkrdn|}|dkr"t jd nt|t jd }||ksPtd| d| t| tf||d}tt	t
 d d dd|_|S )	an  
    :func:`Dim` constructs a type analogous to a named symbolic integer with a range.
    It can be used to describe multiple possible values of a dynamic tensor dimension.
    Note that different dynamic dimensions of the same tensor, or of different tensors,
    can be described by the same type.

    Args:
        name (str): Human-readable name for debugging.
        min (Optional[int]): Minimum possible value of given symbol (inclusive)
        max (Optional[int]): Maximum possible value of given symbol (inclusive)

    Returns:
        A type that can be used in dynamic shape specifications for tensors.
    Nr   r   z(Cannot create Dim with inconsistent min=r   rX   r4   __main__)r    r!   builtinsrO   rV   r   r2   getattrinspect	getmodulestackrF   )r"   rO   rP   _min_maxdimr%   r%   r&   r      s    $  )namesrO   rP   c                    s   t  fdd|D S )z4
    Util to create multiple :func:`Dim` types.
    c                 3   s   | ]}t | d V  qdS )rX   N)r   ).0r"   rP   rO   r%   r&   	<genexpr>   s     zdims.<locals>.<genexpr>)tuple)rO   rP   rb   r%   rd   r&   r      s    c                   @   s*   e Zd ZU dZeed< eed< eed< dS )_ConstraintTargetz{
    This represents input tensor dimensions.  Don't create this
    class directly; instead, use :func:`dynamic_dim`.
    w_tensort_idra   N)r4   rF   rG   rH   r   __annotations__r2   r%   r%   r%   r&   rg      s   
rg   c                       s*   e Zd ZdZdd Zd fdd	Z  ZS )_ConstraintFactoryzO
    Metaclass that ensures a private constructor for :class:`_Constraint`
    c                 O   s   t | j d| j dd S )N.zO has no public constructor. Please use torch.export.dynamic_dim() to create one)	TypeErrorrF   rG   )r7   argskwargsr%   r%   r&   __call__   s    z_ConstraintFactory.__call__Nc                    s   t  ||||||S r)   )superrp   )r7   rh   ri   ra   constraint_rangeshared
debug_name	__class__r%   r&   _create   s         z_ConstraintFactory._create)NN)r4   rF   rG   rH   rp   rw   __classcell__r%   r%   ru   r&   rk      s
      rk   c                 C   s   t | |||||S r)   )_Constraintrw   )rh   ri   ra   rr   rs   rt   r%   r%   r&   _create_constraint   s         rz   c                   @   s   e Zd ZU dZded< dZee ed< dZee	 ed< ddd	Z
d
d Zdd Zdd Zdd Zdd Zedd Zdd ZdS )ry   z

    .. warning::
        Do not construct :class:`_Constraint` directly, use :func:`dynamic_dim` instead.

    This represents constraints on input tensor dimensions, e.g., requiring
    them to be fully polymorphic or within some range.

    r   rr   Nrs   rt   r   c                 C   sb   ddl m} ddlm} |d kr*tjd }|| jj|||d@ dd}t| j	| j
| j|| j| jS )Nr   r   ValueRangesr   lowerupperFvrZ	warn_only)%torch.fx.experimental.symbolic_shapesr   torch.utils._sympy.value_rangesr}   r    r!   rr   r   rz   rh   ri   ra   rs   rt   )rN   r   r   r   r}   rr   r%   r%   r&   _clone_with_range  s     
z_Constraint._clone_with_rangec                 C   s   | j |dS )Nr   r   rN   r   r%   r%   r&   __ge__"  s    z_Constraint.__ge__c                 C   s   | j |d dS )Nr   r   r   r   r%   r%   r&   __gt__%  s    z_Constraint.__gt__c                 C   s   | j |dS )Nr   r   rN   r   r%   r%   r&   __le__(  s    z_Constraint.__le__c                 C   s   | j |d dS )Nr   r   r   r   r%   r%   r&   __lt__+  s    z_Constraint.__lt__c                 C   s   t dd S )NzCannot determine truth value of _Constraint. If you are trying to combine _Constraint's with logical connectives, you can specify them separately instead.)rm   rM   r%   r%   r&   __bool__.  s    z_Constraint.__bool__c                 C   s   | j | j| jjj| jjjdS N)ri   ra   rO   rP   ri   ra   rr   r   r   r   rM   r%   r%   r&   serializable_spec9  s
    
z_Constraint.serializable_specc              	   C   s   t |tstdt| dddlm} || jj|jj@ dd}| jd krT|j}n |jd ksn| j|jksnt	| j}t
| j| j| j|t|j|j|j|dS )NzPA dynamic dim can be specified equal only to another dynamic dim. Equality with z is not supported.r   r{   Fr   )rs   rt   )
isinstancery   rm   r1   r   r   rr   r   rt   rV   rz   rh   ri   ra   rg   )rN   r-   r   rr   rt   r%   r%   r&   __eq__I  s*    

z_Constraint.__eq__)r   N)r4   rF   rG   rH   rj   rs   r   rg   rt   r@   r   r   r   r   r   r   rQ   r   r   r%   r%   r%   r&   ry      s   


ry   )	metaclassc                   @   s*   e Zd ZU dZeed< ded< eed< dS )_PhantomRoota  
    This represents the root of a derived Dim where the root does not directly
    specify the shape of any input dimension, but the derived Dim does.

    e.g., the input shapes 2*dim and dim + 1 are related via a "phantom" dim.

    The fields `name`, `constraint_range`, and `val` carried by a phantom root
    help create a symbol for it. Any derived dims with this phantom root are
    backed by expressions over this symbol.
    r"   r   rr   valN)r4   rF   rG   rH   r@   rj   r2   r%   r%   r%   r&   r   f  s   
r   c                   @   sZ   e Zd ZU dZeeef ed< eed< ded< dZ	e
e ed< edd	 Zed
d ZdS )_DerivedConstraintz
    This represents a derived Dim, whose root is either a regular constraint target
    (which directly specifies the shape of some input dimension) or a phantom root
    (which does so indirectly).
    rD   rA   r   rr   Nrt   c                 C   s   d S r)   r%   rM   r%   r%   r&   rs     s    z_DerivedConstraint.sharedc                 C   s   | j | j| jjj| jjjdS r   r   rM   r%   r%   r&   r     s
    z$_DerivedConstraint.serializable_spec)r4   rF   rG   rH   r   rg   r   rj   r   rt   r   r@   rQ   rs   r   r%   r%   r%   r&   r   x  s   


r   )tindexrt   c              	   C   s   ddl m}m} t| tjs2||jdt|  |  dk rJ||jd||  krx||jd|  d  d| ddd	l	m
} dd
lm} tt| t| |||dtjd ddd|dS )a%
  
    .. warning::
        (This feature is DEPRECATED. See :func:`Dim` instead.)

    :func:`dynamic_dim` constructs a :class:`_Constraint` object that describes the dynamism of
    a dimension ``index`` of tensor ``t``. :class:`_Constraint` objects should be passed to
    ``constraints`` argument of :func:`export`.

    Args:
        t (torch.Tensor): Example input tensor that have dynamic dimension size(s)
        index (int): Index of dynamic dimension

    Returns:
        A :class:`_Constraint` object that describes shape dynamism. It can be passed to :func:`export` so
        that :func:`export` does not assume static size of specified tensor, i.e. keeping it dynamic
        as a symbolic size rather than specializing according to size of example tracing input.

    Specifically :func:`dynamic_dim` can be used to express following types of dynamism.

    - Size of a dimension is dynamic and unbounded::

        t0 = torch.rand(2, 3)
        t1 = torch.rand(3, 4)

        # First dimension of t0 can be dynamic size rather than always being static size 2
        constraints = [dynamic_dim(t0, 0)]
        ep = export(fn, (t0, t1), constraints=constraints)

    - Size of a dimension is dynamic with a lower bound::

        t0 = torch.rand(10, 3)
        t1 = torch.rand(3, 4)

        # First dimension of t0 can be dynamic size with a lower bound of 5 (inclusive)
        # Second dimension of t1 can be dynamic size with a lower bound of 2 (exclusive)
        constraints = [
            dynamic_dim(t0, 0) >= 5,
            dynamic_dim(t1, 1) > 2,
        ]
        ep = export(fn, (t0, t1), constraints=constraints)

    - Size of a dimension is dynamic with an upper bound::

        t0 = torch.rand(10, 3)
        t1 = torch.rand(3, 4)

        # First dimension of t0 can be dynamic size with a upper bound of 16 (inclusive)
        # Second dimension of t1 can be dynamic size with a upper bound of 8 (exclusive)
        constraints = [
            dynamic_dim(t0, 0) <= 16,
            dynamic_dim(t1, 1) < 8,
        ]
        ep = export(fn, (t0, t1), constraints=constraints)

    - Size of a dimension is dynamic and it is always equal to size of another dynamic dimension::

        t0 = torch.rand(10, 3)
        t1 = torch.rand(3, 4)

        # Sizes of second dimension of t0 and first dimension are always equal
        constraints = [
            dynamic_dim(t0, 1) == dynamic_dim(t1, 0),
        ]
        ep = export(fn, (t0, t1), constraints=constraints)

    - Mix and match all types above as long as they do not express conflicting requirements

    r   	UserErrorUserErrorTypez0Expected tensor as input to dynamic_dim but got r   z-Cannot mark 0-dimension tensors to be dynamiczCExpected the dimension passed to dynamic_dim to be in the range [0:z
] but got z., which is out of bounds for the given tensor.r{   r|   r~   Fr   rt   )torch._dynamo.excr   r   r   torchTensorZDYNAMIC_DIMr1   ra   r   r   r   r}   rz   weakrefrefidr    r!   )r   r   rt   r   r   r   r}   r%   r%   r&   r     s8    E  r   r   )r   r   )r   r   r   )
constraintget_sources	shape_envsource_pairsderived_equalitiesphantom_symbolsc           	         s   || j | j^ }| fdd|D  t| tsj| jdk	r|| jj | jj}| fdd|D  nt| jts|| jj | jjd }nX| jj|kr|| jj }n>|j	| jj
tjj| jjtjjjjj| jjd}||| jj< | j}| ||f dS )z
    Updates `source_pairs`, `derived_equalities`, and `phantom_symbols` (which become
    fields of `EqualityConstraint`) based on a given input `constraint`.
    c                 3   s   | ]} |fV  qd S r)   r%   rc   Zother_sourcesourcer%   r&   re     s     z&_process_equalities.<locals>.<genexpr>Nc                 3   s   | ]} |fV  qd S r)   r%   r   r   r%   r&   re     s    r   )r   r   r   Zconstraint_dim)ri   ra   extendr   r   rs   rD   r   r"   Zcreate_symbolr   r   Z_dynamor   ZConstantSourceZfxZexperimentalZsymbolic_shapesZ
DimDynamicZDYNAMICrr   rA   append)	r   r   r   r   r   r   Zother_sourcesrD   rA   r%   r   r&   _process_equalities  s*    


r   .)functreedynamic_shapesreturnc                    s.   dd  fdd t  |f|diS )a"  
    Customized tree_map for mapping pytrees to dynamic_shapes.

    For built-in types (e.g., standard collections) this behaves exactly like tree_map.

    OTOH for a user-defined class C registered with pytree, we cannot assume that a C
    containing tensors can be mapped to a C containing dynamic shapes (i.e., C may not
    be a polymorphic container). In that case we use the flattened form of C instead.
    Thus a C(**tensors) that flattens to (**tensors) will map to (**dynamic_shapes).

    Args:
        func: function to apply to each (int, float, str, bool, None, torch.Tensor)
        tree: input pytree
        dynamic_shapes: zero or more (typically one) dynamic_shapes to match

    Returns:
        output pytree mapping func to each (int, float, str, bool, None, torch.Tensor)
    c                 S   s   t | tkS r)   )r   r   )r   r%   r%   r&   is_leafR  s    z_tree_map.<locals>.is_leafc                    sF   t | }|tkr4t t| | d f|diS | f| S d S )Nr   r   )r   r   r   Z
flatten_fn)r   r   typfr   r   r%   r&   r   Y  s    z_tree_map.<locals>.fr   )r   )r   r   r   r%   r   r&   	_tree_map:  s    r   Fc                 C   s\   t | tr|  } |sXt | tjjr0t| jnt| }|d k	rF|ni }|j	||j
S |S r)   )r   r   moduler   nnModuler\   	signatureforwardbind	arguments)r   rn   ro   _is_torch_jit_tracer   r%   r%   r&   _combine_argsk  s    
r   c                   @   s:   e Zd ZdZdd Zdd Zdd Zdd	 ZdddZd
S )ShapesCollectionab  
    Builder for dynamic_shapes.
    Used to assign dynamic shape specifications to tensors that appear in inputs.

    Example::
        args = ({"x": tensor_x, "others": [tensor_y, tensor_z]})

        dim = torch.export.Dim(...)
        dynamic_shapes = torch.export.ShapesCollection()
        dynamic_shapes[tensor_x] = (dim, dim + 1, 8)
        dynamic_shapes[tensor_y] = {0: dim * 2}
        # This is equivalent to the following (now auto-generated):
        # dynamic_shapes = {"x": (dim, dim + 1, 8), "others": [{0: dim * 2}, None]}

        torch.export(..., args, dynamic_shapes=dynamic_shapes)
    c                 C   s
   i | _ d S r)   )_shapesrM   r%   r%   r&   __init__  s    zShapesCollection.__init__c                 C   sj   t |tjstdt| t|}|| jkrX| j| }||ksftd| d| n|| jt|< d S )Nz'Cannot assign shape to non-tensor type z1Shapes assigned to tensor do not match: expected z, got )r   r   r   rV   r1   r   r   )rN   r   shaperi   _shaper%   r%   r&   __setitem__  s     

zShapesCollection.__setitem__c                 C   s$   t |}|| jkr| j| S d S d S r)   )r   r   )rN   r   ri   r%   r%   r&   __getitem__  s    

zShapesCollection.__getitem__c                 C   s
   t | jS r)   )lenr   rM   r%   r%   r&   __len__  s    zShapesCollection.__len__Nc                    sN   t   fdd}t|||}t||}tfdd jD rJtd|S )z*
        Generate dynamic_shapes.
        c                    s.   t | }| jkr&|  j| S d S d S r)   )r   r   add)r   ri   rN   t_idsr%   r&   
find_shape  s
    


z3ShapesCollection.dynamic_shapes.<locals>.find_shapec                 3   s   | ]}| kV  qd S r)   r%   )rc   ri   )r   r%   r&   re     s     z2ShapesCollection.dynamic_shapes.<locals>.<genexpr>zSome tensors that were assigned shapes were not found in args. Maybe such tensors were copied when passing them as args? Maybe such tensors are contained in classes that were not registered with pytree?)setr   r   anyr   
ValueError)rN   mrn   ro   r   combined_argsr   r%   r   r&   r     s    
zShapesCollection.dynamic_shapes)N)	r4   rF   rG   rH   r   r   r   r   r   r%   r%   r%   r&   r   {  s   r   )r   rn   ro   r   r   c                    s`  ddl m m |d ks$t|dkr(d S tti g  fddi  fdd fdd fd	d
}t| |||d}t|tst|t	tfst
t|| }||| g }D ]"}|jj}	|	krԈ|	 d |_qԈ D ]Z}
tdd |
D r$||
 n4|
^}}|rN|D ]}|||k q6n
|| q |S )Nr   r   c           
         s  dd l ddlm} ddlm ddlm}  fdd}t tr j	}|j
	kr	|j
 d }t|j|j|j}nF|j
krt|j
|||j|jddd	| d
}||j
< n
|j
 }ttt| j|| j jddd	 j
d}	t|tr|	 nt trXttt|| j jddd	 j
d}	nBt j
d}	 jdkr~|	 jk}	 jtjd kr|	 jk}	|	S )Nr   r{   )	try_solver|   c                     sx   j jjdd} | }|j | }|d k	rHt|d S  jd dj  d| d|  d	d S )	NT)integerr   zExpected shape[z] = z# of input Tensor to be of the form z, where z is an integer)r   rD   r4   rA   Eqr   r2   ZCONSTRAINT_VIOLATION)symbolexprZsolution)r   r   ra   ir?   tensorr   r%   r&   
root_value  s    
"zB_process_dynamic_shapes.<locals>.to_constraint.<locals>.root_valuer~   Fr   )r"   rr   r   r   r   )r?   r   r   Ztorch.utils._sympy.solver   r   r}   r   rE   rD   r4   rg   rh   ri   ra   r   rO   rP   r   r   r   r   rA   r   rJ   rz   rL   r   r    r!   )
ra   r   r   r   r}   r   Zdim_rootZroot_constraintrD   r   )r   r   %derived_constraints_with_phantom_rootphantom_rootssymbols)ra   r   r?   r   r   r&   to_constraint  sp    


 


z._process_dynamic_shapes.<locals>.to_constraintc              	      s   | j krr| j  \}}| j|ks,| j|krt| j ||}t| j | j| j} jd| d| d|  dn| j| jf| j < d S )NzFound different definitions z and z! for the same symbolic dimension !)r4   rO   rP   r   r'   INVALID_INPUT)ra   r#   r$   Zthis_Zthat_)r   r   boundsr   r%   r&   check_same_bounds(  s    
z2_process_dynamic_shapes.<locals>.check_same_boundsc              
      sR  dd }t |tr| D ]z\}}t |ttfrlt |trF|| ||}| || |}|j | q|d k	r jd| d| d| dqnt |tt	fr0t
|D ]|\}}t |ttfrt |tr|| ||}| || |}|j | q|d k	r jd| d| d| dqn|d k	rN jd| dd S )Nc                 S   s   t t|tfd|iS )NrL   )rJ   r@   r2   )r   r   rL   r%   r%   r&   _create_static_dim8  s    zK_process_dynamic_shapes.<locals>.update_symbols.<locals>._create_static_dimzUnexpected item #z (z) in dynamic_shape z of Tensor, try None insteadzUnexpected dynamic_shape )r   dictitemsr2   r   r4   r   r   rf   list	enumerate)r   r   r   r   ra   r   )r   r   r   r   r   r%   r&   update_symbols7  s@    




z/_process_dynamic_shapes.<locals>.update_symbolsc                    s     fdd}t || | d S )Nc                    sB   t | tjr| | n&|d k	r> jd| dt|  dd S )NzCannot associate shape z to non-tensor type z, expected None)r   r   r   r   r1   )r   Zdynamic_shaper   r   r   r%   r&   assoc_shapea  s    zB_process_dynamic_shapes.<locals>.assoc_shapes.<locals>.assoc_shape)r   )r   r   r   r   r%   r&   assoc_shapes`  s    z-_process_dynamic_shapes.<locals>.assoc_shapes)r   c                 s   s   | ]}t |tV  qd S r)   )r   r   )rc   r   r%   r%   r&   re     s    z*_process_dynamic_shapes.<locals>.<genexpr>)r   r   r   r   r   r   r   r   r   rf   rV   r1   valuesrD   r"   allr   r   )r   rn   ro   r   r   r   r   constraintsZ$derived_constraint_with_phantom_rootZphantom_root_nameZdynamic_dimsprimaryZothersr-   r%   )	r   r   r   r   r   r   r   r   r   r&   _process_dynamic_shapes  sJ    R)   


r   )r   c                 C   sX   i }t | dd dd D ]:}|d kst|tr0q|||j< t|tr|j||jj< q|S )Nc                 S   s
   t | tS r)   )r   r   r*   r%   r%   r&   r.     r/   z'_get_dim_name_mapping.<locals>.<lambda>)r   r   )r   r   r2   r4   rE   rD   )r   name_to_dimra   r%   r%   r&   _get_dim_name_mapping  s    

r   )msgr   r   c              
      s   ddl }ddlddlm}m} ddlm} z| dd  }W n0 t	k
rr } z||j
d|W 5 d}~X Y nX i |dD ]}| }|d	| }	r|	d}
d
\}}|d| }rt|d}|d| }rt|d}t|
||d|
< q|d\}
}|}t|jr6t||
< q||
< qt|t } D ]z\}}t|tttjfsxtt|jr||st||< |ttt|j t|trV||jj qV D ]"\}}|ks||kstqi   fdd}t |||S )aU  
    For working with export's dynamic shapes suggested fixes, and/or automatic dynamic shapes.
    Refines the given dynamic shapes spec, given a ConstraintViolation error message and the original dynamic shapes.

    For most cases behavior is straightforward - i.e. for suggested fixes that specialize or refine a Dim's range,
    or fixes that suggest a derived relation, the new dynamic shapes spec will be updated as such.

    e.g.
    Suggested fixes:

        dim = Dim('dim', min=3, max=6) -> this just refines the dim's range
        dim = 4 -> this specializes to a constant
        dy = dx + 1 -> dy was specified as an independent dim, but is actually tied to dx with this relation

    However, suggested fixes associated with derived dims can be more complicated.
    For example, if a suggested fix is provided for a root dim, the new derived dim value is evaluated based on the root.

    e.g.
    dx = Dim('dx')
    dy = dx + 2
    dynamic_shapes = {"x": (dx,), "y": (dy,)}

    Suggested fixes:

        dx = 4  # specialization will lead to dy also specializing = 6
        dx = Dim('dx', max=6)  # dy now has max = 8

    Derived dims suggested fixes can also be used to express divisibility constraints.
    This involves creating new root dims that aren't tied to a particular input shape.
    In this case the root dims won't appear directly in the new spec, but as a root of
    one of the dims.

    e.g.
    Suggested fixes:

        _dx = Dim('_dx', max=1024)  # this won't appear in the return result, but dx will
        dx = 4*_dx  # dx is now divisible by 4, with a max value of 4096
    r   Nr   )_is_supported_equivalencezSuggested fixes:r   z`Suggested fixes not found in error message given to refine_dynamic_shapes_from_suggested_fixes()
z(.*) = Dim\('(.*)'.*\))NNz!.* = Dim\('.*', min\=([0-9]+).*\)z.* = Dim\('.*'.*max\=([0-9]+)\)rX   z = c                    s6  | d kst | tr| S | jkr| j }t |jrt| krN t| S tt|j}|jkrr|j }n|jkst	|j }j
j||\}}|} |dkrt||  } |dkr| t| } |  t|< | S n|S nPt | tr2| jjkr2| j kr | j S | | jj }| | j< |S | S )Nr   r   )r   r2   r4   Exprr@   nextiterfree_symbolsr"   rV   ZpolysZ	polytoolsdivrE   rD   rA   )ra   dummyfixr   rD   modulus	remainderZ_dimZderived_dim_cacher   Zshape_fixesr?   r%   r&   apply_fixes  s8    





z?refine_dynamic_shapes_from_suggested_fixes.<locals>.apply_fixes)!rer?   r   r   r   r   r   splitstrip	Exceptionr   matchgroupr2   r   r>   r   Numberr   r   r   r   rE   r   rV   r   r@   r   r   r   rD   r4   r   )r   r   r  r   r   r   Zshape_fixes_msgexcr   r  r"   r_   r`   Z	match_minZ	match_maxr   rootskcr  r%   r  r&   r     sX    +


$)NN)N)F)NNF);rZ   dataclassesr\   r    r   collectionsr   typingr   r   r   r   r   r   r	   r
   r   r   Ztorch.utils._pytreer   r   r   r   r   Zexported_programr   r?   r   Ztorch._guardsr   Zfx.experimental.symbolic_shapesr   r   __all__r1   r   rJ   rE   r@   r2   r   r   	dataclassrg   rk   rz   ry   r   r   r   r   r   r   r   r   r   r   r   r   r%   r%   r%   r&   <module>   s   ,	C9""   
k"j

4
1
J   
 
 S