
    !&h                     	   U d dl Z d dlZd dlZd dlmZ d dlmZ d dlmZm	Z	m
Z
mZ d dl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 d d	lmZmZmZ d d
lm Z  d dl!m"Z" d dl#m$Z$m%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/ g dZ0ej                  jb                  jd                  ej                  jb                  jf                  ej                  jb                  jh                  hZ5e G d d             Z6de+dede7fdZ8de+dede7fdZ9de:ee:e;e;f   f   de<e   fdZ=d Z>de	de	fdZ?de@de	fd ZAde+de
e<e+      fd!ZBd"e'd#e<e+   de'fd$ZCd%ej                  j                  defd&ZEd%ej                  j                  d'e*de@d(ede+f
d)ZFde+d*e:e@ej                  j                  f   d+e:e+e7f   de7fd,ZGde+de<eH   fd-ZId.e<eH   de	e+ge<eH   f   fd/ZJ ed0d1      ZK eKd2d3      ejn                   eJdg      eL eJd4g      i eKd2d5      eHeIi eKd2d6      eHeIi eKd2d7      eHeIi eKd2d8      eH eJdg      i eKd2d9      eHeIi eKd2ej                        eHeIi eKd2d:      eH eJdg      i eKd2d;      eH eJdg      i eKd2ej                        eH eJdg      i eKd2d<      eHeIiiZOe:eKe:ee;ej                  f   e	e+ge<eH   f   f   f   eQd=<   i ZRe:ee;ej                  f   e	e+ge<eH   f   f   eQd><   de+de:ee;ej                  f   e	e+ge<eH   f   f   fd?ZS	 	 d[de+d*e:e@ej                  f   d@e
e;ej                        dAede
e+   f
dBZTdCe*dDeUedEf   dFe+de+fdGZVdHe/dIe7deUe<e@   e<e;e      f   fdJZW	 	 d[de+dKe:e@ej                  j                  f   dLedMe
e   de7f
dNZX	 	 d[de+dKe:e@ej                  j                  f   dLedMe
e   de7f
dOZYde+dKe:e@ej                  j                  f   de
ej                  j                     fdPZZde+dQej                  j                  dKe:e@ej                  j                  f   d'e*de+f
dRZ[de+dQej                  j                  dKe:e@ej                  j                  f   d'e*de+f
dSZ\de+dKe:e@ej                  j                  f   de
e+   fdTZ]d'e*fdUZ^dVeeef   defdWZ_	 d\dLedXedYe7de7fdZZ`y)]    N)
namedtuple)	dataclass)AnyCallableOptionalUnion)
QConfigAny	QuantType)DTypeWithConstraints)FakeQuantizeBaseFixedQParamsFakeQuantize)_is_activation_post_processFixedQParamsObserverObserverBase)float16_dynamic_qconfigfloat16_static_qconfigqconfig_equals)QConfigMapping)DeQuantStub)_assert_and_get_unique_device"activation_is_statically_quantized)GraphModulemap_arg)GraphNode   )quantized_decomposed_lib)PrepareCustomConfig)all_node_args_except_firstall_node_args_have_no_tensorsassert_and_get_unique_devicecollect_producer_nodescreate_getattr_from_value'create_node_from_old_node_preserve_metaEMPTY_ARG_DICTget_custom_module_class_keysget_linear_prepack_op_for_dtypeget_new_attr_name_with_prefix(get_non_observable_arg_indexes_and_typesget_qconv_prepack_op#get_skipped_module_name_and_classes graph_module_from_producer_nodesmaybe_get_next_moduleNodeInfonode_arg_is_biasnode_arg_is_weightNON_OBSERVABLE_ARG_DICTNON_QUANTIZABLE_WEIGHT_OPSreturn_arg_listObservedGraphModuleAttrsc                       e Zd ZU eeef   ed<   eeeeef   f   ed<   e	ed<   eee
f   ed<   eed<   eed<   ee   ed<   dZeed	<   d
Zeee      ed<   d
Zeee      ed<   y
)r4   node_name_to_qconfignode_name_to_scopeprepare_custom_config!equalization_node_name_to_qconfigqconfig_mappingis_qatobserved_node_namesFis_observed_standalone_moduleN&standalone_module_input_quantized_idxs'standalone_module_output_quantized_idxs)__name__
__module____qualname__dictstrr	   __annotations__tupletyper   r   r   boolsetr=   r>   r   listintr?        t/var/www/pru.catia.catastroantioquia-mas.com/valormas/lib/python3.12/site-packages/torch/ao/quantization/fx/utils.pyr4   r4   J   s    sJ//S%T	"2233..'+CH~5##LS!*/!4/BF*HT#Y,?FCG+Xd3i-@GrM   r4   nodeargreturnc                     d}d| j                   v r| j                   d   j                  dd      }|*|t        | j                        k  r| j                  |   |u ry| j                  j                  d      |u S )zReturns if node arg is weightNtarget_dtype_infoweight_indexTweightmetagetlenargskwargs)rO   rP   rT   s      rN   r0   r0   X   sq    Ldii'yy!4599.$O 3tyy>)IIl#s*;;??8$++rM   c                     d}d| j                   v r| j                   d   j                  dd      }|*|t        | j                        k  r| j                  |   |u ry| j                  j                  d      |u S )zReturns if node arg is biasNrS   
bias_indexTbiasrV   )rO   rP   r]   s      rN   r/   r/   f   sq    Jdii'YY2377dK
TYY'IIj!S(;;??6"c))rM   custom_module_mappingc                     t               }t        j                  t        j                  t        j                  fD ]2  }| j                  |i       }t        |j                               }||z  }4 t        |      S )a  Get all the unique custom module keys in the custom config dict
    e.g.
    Input:
    {
        QuantType.STATIC: {
            CustomModule1: ObservedCustomModule
        },
        QuantType.DYNAMIC: {
            CustomModule2: DynamicObservedCustomModule
        },
        QuantType.WEIGHT_ONLY: {
            CustomModule3: WeightOnlyObservedCustomModule
        },
    }

    Output:
    # extract the keys across all inner STATIC, DYNAMIC, and WEIGHT_ONLY dicts
    [CustomModule1, CustomModule2, CustomModule3]
    )rI   r
   STATICDYNAMICWEIGHT_ONLYrX   keysrJ   )r_   float_custom_module_classes
quant_modequant_mode_custom_module_config quant_mode_custom_module_classess        rN   r&   r&   t   sy    . -0E ''):):I<Q<QR H
*?*C*CJPR*S'+./N/S/S/U+V(#'GG#H +,,rM   c                     | t         j                  k(  r$t         j                  j                  j                  S | t         j
                  k(  r$t         j                  j                  j                  S t        d|       )Nz&can't get linear prepack op for dtype:)torchfloat16ops	quantizedlinear_prepack_fp16qint8linear_prepack	Exception)dtypes    rN   r'   r'      sT    yy""666	%++	yy""111@%HHrM   conv_opc                    t         j                  j                  j                  t         j                  j
                  j                  t         j                  j                  j                  t         j                  j
                  j                  t         j                  j                  j                  t         j                  j
                  j                  t         j                  j                  j                  t         j                  j
                  j                  t         j                  j                  j                  t         j                  j
                  j                  t         j                  j                  j                  t         j                  j
                  j                   i}|j#                  | d       }|s
J d|         |S )NzDidn't find prepack op for )rj   nn
functionalconv1drl   rm   conv1d_prepackconv2dconv2d_prepackconv3dconv3d_prepackconv_transpose1dconv_transpose1d_prepackconv_transpose2dconv_transpose2d_prepackconv_transpose3dconv_transpose3d_prepackrX   )rs   prepack_ops
prepack_ops      rN   r*   r*      s   ""EII$7$7$F$F""EII$7$7$F$F""EII$7$7$F$F,,eii.A.A.Z.Z,,eii.A.A.Z.Z,,eii.A.A.Z.ZK $/J>4WI>>:rM   prefixc                 l      j                  dd       dt        j                  j                  f fd}|S )N._modulec                     dt         ffd}d} ||      }t        | |      r|dz  } ||      }t        | |      r|S )Nic                      t        |       z   S N)rD   )r   r   s    rN   get_attr_namezOget_new_attr_name_with_prefix.<locals>.get_new_attr_name.<locals>.get_attr_name   s    CF?"rM   r   r   )rK   hasattr)r   r   r   	attr_namer   s       rN   get_new_attr_namez8get_new_attr_name_with_prefix.<locals>.get_new_attr_name   sQ    	#S 	# !!$	fi(FA%a(I fi( rM   )replacerj   ru   Module)r   r   s   ` rN   r(   r(      s/    ^^C%F	%((// 	 rM   c                    | g}| g}|r|j                         } t        | j                        t        | j                  j	                               z   }|D ]i  }t        |t              s|j                  dk(  r y|j                  |       |j                  dk(  r|j                  t        k(  rY|j                  |       k |r|S )a   Starting from a target node, trace back until we hit inpu or
    getattr node. This is used to extract the chain of operators
    starting from getattr to the target node, for example
    def forward(self, x):
      observed = self.observer(self.weight)
      return F.linear(x, observed)
    collect_producer_nodes(observed) will either return a list of nodes that
    produces the observed node or None if we can't extract a self contained
    graph without free variables(inputs of the forward function).
    placeholderNcall_function)poprJ   rZ   r[   values
isinstancer   opappendtargetgetattr)rO   nodesfrontierall_argsrP   s        rN   r"   r"      s     FEvH
||~		?T$++*<*<*>%?? 	%Cc4(vv&LLFFo-#**2G$	%  LrM   rootproducer_nodesc                     t        |      dkD  sJ d       |j                          t               }i fd}|D ]  }|j                  ||      |<    |j	                   ||d                t        | |      }|S )a,  Construct a graph module from extracted producer nodes
    from `collect_producer_nodes` function
    Args:
      root: the root module for the original graph
      producer_nodes: a list of nodes we use to construct the graph
    Return:
      A graph module constructed from the producer nodes
    r   z'list of producer nodes can not be emptyc                 "    t        | fd      S )Nc                     |    S r   rL   )rO   envs    rN   <lambda>zDgraph_module_from_producer_nodes.<locals>.load_arg.<locals>.<lambda>   s    s4y rM   )r   )ar   s    rN   load_argz2graph_module_from_producer_nodes.<locals>.load_arg   s    q011rM   )rY   reverser   	node_copyoutputr   )r   r   graphr   producer_nodegraph_moduler   s         @rN   r,   r,      s     ~"M$MM"GEC2 ( F"__]HEMF	LL.,-.tU+LrM   r   c                     t        |       S )z
    Returns the unique device for a module, or None if no device is found.
    Throws an error if multiple devices are detected.
    )r   )r   s    rN   r!   r!      s    
 )00rM   r   valuec                 (   t        |      } ||       }t        |       }t        |t        j                        r|j                         j                         nt        j                  ||      }| j                  ||       |j                  d|      }|S )z
    Given a value of any type, creates a getattr node corresponding to the value and
    registers the value as a buffer to the module.
    )deviceget_attr)
r(   r!   r   rj   Tensordetachclonetensorregister_buffercreate_node)	r   r   r   r   r   r   r   	new_value	attr_nodes	            rN   r#   r#      s     6f=!&)I)&1F eU\\* 	\\%/ 
 9i0!!*i8IrM   modulescachec                    |r	| |v r||    S d}t        | t              sd}n| j                  dk(  rd}n| j                  dk(  rQt        | j                  t              sJ t        || j                           r{t        | j                  d   ||      }n_| j                  dk(  rd}nL| j                  dk(  r8| j                  t        j                  u rt        | j                  d   ||      }n| j                  dk(  rd}n| j                  t        u r| j                  d   d	v rd}n| j                  d
k(  r| j                  dk(  rd}nd}| j                  D ]  }t        |t              r?|D ]9  }t        |t              st        |||      }|xs | }|s+| }|r||| <   |c c S  nGt        |t              rn6t        |t              r$t        |||      }|xs | }|r| }|r||| <   |c S d}| } |r||| <   |S )z
    If we know for sure that all of this node's args have no
    tensors (are primitives), return True.  If we either
    find a tensor or are not sure, return False. Note: this
    function is not exact.
    FTr   call_moduler   r   r   r   )ndimshapecall_methodsize)r   r   r   r   rD   r   r    rZ   operatorgetitemr   rJ   rK   )	rO   r   r   resultfound_one_tensorrP   list_el!this_list_el_args_have_no_tensorsthis_arg_args_have_no_tensorss	            rN   r    r      s    T{FdD!	M	!	M	!$++s+++&wt{{';<2499Q<%PF	M	!	O	#x7G7G(G.tyy|WeL	J			DIIaL4E$E	M	!dkkV&; 99 *	*C#t$" *G!'409'7ER : ,< , AA ) ,)9%9F$.4d#)M#*$ C%c4(4QWe51 (8 (99 % (%5!5 *0E$K%'+$))FU*	*V dMrM   c                 R    t        t        dt        | j                                    S )z2
    Returns all node arg indices after first
    r   )rJ   rangerY   rZ   )rO   s    rN   r   r   h  s     aTYY())rM   arg_indicesc                 :     dt         dt        t           f fd}|S )zu
    Constructs a function that takes a node as arg and returns the arg_indices
    that are valid for node.args
    rO   rQ   c                 `    D cg c]  }|t        | j                        k  s| c}S c c}w r   )rY   rZ   )rO   r   r   s     rN   arg_indices_funcz)return_arg_list.<locals>.arg_indices_funcu  s&    &=a!c$))n*<===s   ++)r   rJ   rK   )r   r   s   ` rN   r3   r3   o  s"    >t >S	 > rM   r.   z	op targetr   masked_fill   permuterepeatreshaper   	transpose	unsqueeze
unsqueeze_viewr1   r%   c                 v    t        | j                  | j                        }t        j	                  |t
              S )z
    Returns a dict with of non float tensor types as keys and values which correspond to a
    function to retrieve the list (which takes the node as an argument)
    )r.   r   r   r1   rX   r%   )rO   infos     rN   r)   r)     s+     DGGT[[)D"&&t^<<rM   target_module_typetarget_functional_typec                     | j                   j                         D ]_  }|j                  dk(  r(|&t        |t	        |j
                           |      r|c S |j                  dk(  sJ|M|j
                  |k(  s]|c S  y)a$  Gets the next module that matches what is needed in
    is_target_module_type if it exists

    Args:
        node: The node whose users we want to look at
        target_module_type: Module type that we want to check
        target_functional_type: Functional type that we want to check
    r   Nr   )usersrd   r   r   rD   r   )rO   r   r   r   users        rN   r-   r-     sw     

! GG}$".73t{{#346HIKGG&&255K rM   quantized_graphcreate_node_args.old_nodec                 F     | j                   | }|j                  |_        |S )zU
    Creates `new_node` and copies the necessary metadata to it from `old_node`.
    )r   stack_trace)r   r   r   new_nodes       rN   r$   r$     s*     +**,<=H#//HOrM   r8   is_standalone_modulec                 R   t        j                   | j                        }t        j                   | j                        }|sd|t        | j                  j                               z  }|t        | j                  j                               z  }|t        | j                        z  }||fS r   )	copynon_traceable_module_namesnon_traceable_module_classesrJ   standalone_module_namesrd   standalone_module_classesr&   float_to_observed_mapping)r8   r   skipped_module_namesskipped_module_classess       rN   r+   r+     s      99%:%U%UV!YY::  !99>>@!
 	
 	$!;;@@B#
 	
 	">!;;#
 	
  !777rM   named_modulesqconfigqhandlerc                    t        | |      }||t        |t        j                  j                  j
                  j                  j                        sJ t        |t        j                  j                        xr t        |      xr |j                         S t        |t        j                  j                  j                  j                        S )zD
    Return whether this refers to the custom module LSTM flow.
    )_get_moduler   rj   aoquantizationfxquantize_handlerQuantizeHandlerru   LSTMr   is_custom_modulequantizablerO   r   r   r   mods        rN   _is_custom_module_lstmr    s     dM
*Cx3(EHH$9$9$<$<$M$M$]$]^^^sEHHMM* ,27;,))+	
 #uxx{{66;;<<rM   c                    t        | |      }||t        |t        j                  j                  j
                  j                  j                        sJ t        |t        j                  j                        xr t        |      xr |j                         S t        |t        j                  j                  j                  j                        S )zR
    Return whether this refers to the custom module MultiheadAttention flow.
    )r   r   rj   r   r   r   r   r   ru   MultiheadAttentionr   r   r   r   s        rN   _is_custom_module_mhar    s     dM
*Cx3(EHH$9$9$<$<$M$M$]$]^^^sEHH778 ,27;,))+	
 #uxx{{66IIJJrM   c                     | j                   dk(  r/t        | j                        |v r|t        | j                           S y)zO
    If `node` refers to a call_module node, return the module, else None.
    r   N)r   rD   r   )rO   r   s     rN   r   r     s7     ww-C$4$ES-..rM   modelc                     d}t        |      } ||      }t               }t        |||       |||<   |j                  |       5  |j	                  || f      cddd       S # 1 sw Y   yxY w)z
    Attach a `DeQuantStub` to the model and create a node that calls this
    `DeQuantStub` on the output of `node`, similar to how observers are inserted.
    dequant_stub_N)r(   r   setattrinserting_afterr   )rO   r  r   r   r   get_new_dequant_stub_namedequant_stub_namedequant_stubs           rN   _insert_dequant_stubr    st     F =f E1%8=LE$l3'3M#$			t	$ =  !2TG<= = =s   A  A)c                 >   |j                  |       5  |j                  t        j                  | df      }t	        ||||      }ddd       |j                        5  |j                  t        j                  | df      }ddd       |j                        5  |j                  t        j                  |df      }t	        ||||      }ddd       |j                        5  |j                  t        j                  |df      }	t	        |	|||      }
ddd       |j                  
      5  |j                  t
        ||
gf      }ddd       |j                        5  |j                  t
        ||gf      }ddd       t        | j                  j                               D ]   }|k7  s	||k7  s|j                  |        " t        |       S # 1 sw Y   xY w# 1 sw Y   dxY w# 1 sw Y   'xY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w)a8  
    Insert DeQuantStubs after each internal output node of custom module LSTM.

    Custom module LSTM outputs are nested tuples of the structure (output, (hidden0, hidden1)),
    Since we cannot dequantize a tuple as a whole, we must first break down the tuple into its
    components through `getitem`. This function transforms the graph as follows:

      (1) Split the LSTM node into (output, (hidden0, hidden1))
      (2) Insert a DeQuantStub after each internal node
      (3) Recombine the DeQuantStubs into the same structure as before
      (4) Reroute all consumers of the original LSTM node and its sub-nodes
          (e.g. lstm[0])

    Before:
                   lstm_output
                        |
                        v
                  original_user(s)
    After:
                   lstm_output
                  /           \
                 /  (getitem)  \
                /               \
               v                 v
             output            hidden
               |               /   \
         (DeQuantStub)        (getitem)
               |             /       \
               v            v         v
           output_dq     hidden0    hidden1
               |            |         |
               |    (DeQuantStub) (DeQuantStub)
               |            |         |
               |            v         v
               |      hidden0_dq  hidden1_dq
               |            \       /
               |              (tuple)
               |              \   /
               |               v  v
               |             hidden_dq
               \               /
                \   (tuple)   /
                 v            v
                 lstm_output_dq
                       |
                       v
                original_user(s)

    For step (4), reroute all users of the original LSTM node(s) as follows:
      lstm_output -> lstm_output_dq
      lstm_output[0] -> output_dq
      lstm_output[1] -> hidden_dq
      lstm_output[1][0] -> hidden0_dq
      lstm_output[1][1] -> hidden1_dq

    Return the node `lstm_output_dq`.
    r   Nr   )r  r   r   r   r  rF   rJ   r   rd   replace_input_with_reroute_tuple_getitem_pattern)rO   r  r   r   r   	output_dqhiddenhidden0
hidden0_dqhidden1
hidden1_dq	hidden_dqlstm_output_dqr   s                 rN   3_insert_dequant_stubs_for_custom_module_lstm_outputr  2  s   B 
		t	$ N$$X%5%5ayA(uM	N 
		y	) B$$X%5%5ayAB			v	& P%%h&6&6D)'5-O
P 
		z	* P%%h&6&6D)'5-O
P
 
		z	* L''Z0H/JK	L			y	) O,,Ui5K4MNO TZZ__&' :6>dfn##D.9: #5)7N NB BP PP P
L LO OsG   1G#G!1G."1G;,HHG!G+.G8;HHHc                     	 fd}fd}d }d 	dt         t           dt        t           f 	fd}|||g	||||g||||g	|||gg}|D ]  } ||      }||c S  y)	aC  
    Given an argument of a node, if the argument refers to the path through which the node
    is a consumer of custom module LSTM, return the custom module LSTM node, or None otherwise.

    This is used to determine whether a node is a consumer of custom module LSTM, and, if so,
    skip inserting input observers for this node. This is because custom module LSTM produces
    quantized outputs, so inserting an input observer for the consumer of custom module LSTM
    would unnecessarily quantize the outputs again.

      lstm -> consumer

    In practice, however, custom module LSTM outputs a tuple (output, (hidden0, hidden1)) with
    DeQuantStubs attached to each internal node (see `_insert_dequant_stubs_for_custom_module_lstm_output`).
    This tuple can be consumed in one of four ways:

      lstm -> getitem -> DeQuantStub -> consumer                       # consume lstm[0]
      lstm -> getitem -> getitem -> DeQuantStub -> tuple -> consumer   # consume lstm[1]
      lstm -> getitem -> getitem -> DeQuantStub -> consumer            # consume lstm[1][0] or lstm[1][1]
      lstm -> getitem -> DeQuantStub -> tuple -> consumer              # consume lstm

    Thus, we must match against the above patterns instead of simply checking the parent node
    to determine whether this node is a consumer of a custom module LSTM.
    c                 8    t        t        |       t              S r   )r   r   r   r   r   s    rN   match_dqz=_maybe_get_custom_module_lstm_from_node_arg.<locals>.match_dq  s    +a7EErM   c                     t        |       S r   )r  r  s    rN   
match_lstmz?_maybe_get_custom_module_lstm_from_node_arg.<locals>.match_lstm  s    %a77rM   c                 ^    | j                   dk(  xr | j                  t        j                  k(  S Nr   )r   r   r   r   r   s    rN   match_getitemzB_maybe_get_custom_module_lstm_from_node_arg.<locals>.match_getitem  s%    tt&G188x7G7G+GGrM   c                 J    | j                   dk(  xr | j                  t        k(  S r#  )r   r   rF   r$  s    rN   match_tuplez@_maybe_get_custom_module_lstm_from_node_arg.<locals>.match_tuple  s    tt&<188u+<<rM   match_patternrQ   c                     }t        |       D ]H  \  }} ||      s y|t        |       dz
  k  s"|k(  r|j                  d   d   }:|j                  d   }J |S )z
        Traverse up the graph and match the args one by one.
        If there is a match, return the last matched node, or None otherwise.
        Nr   r   )	enumeraterY   rZ   )r(  r   r   matchrP   r'  s       rN   _match_patternzC_maybe_get_custom_module_lstm_from_node_arg.<locals>._match_pattern  sk    
 !-0 	"HAu83}%))K'q	!Aq	A	" rM   N)rJ   r   r   r   )
rP   r   r  r!  r%  r,  all_match_patternspmatched_noder'  s
   ``       @rN   +_maybe_get_custom_module_lstm_from_node_argr0    s    8F8H=d8n $ $ 
=*-	h}jI	=-<	hz:	    %a(#  rM   c                   
 dt         dt        t           dt        t            dt        t        t               dt        t        t         t        t        df   f      f

fd
g }t               }| j
                  D ]  } 
|g g ||        |D ]  }|d   }|d	   }|j                  d
k(  r|j                  t        k(  sJ |j                  d
k(  r|j                  t        j                  k(  sJ |j                  d   }|j                  d   |   }t        |j                  j                               D ]  }	|	j                  ||         y)a  
    Search for patterns where N consecutive `tuple` call_function nodes are followed by
    N consecutive `getitem` call_function nodes that are "reverses" of the `tuple` nodes.
    If we find this pattern, reroute the consumers of the last `getitem` to skip these
    N `tuple` and `getitem` nodes.

    Before:

        a   b     c
        |   \   /
        \   tuple
         \   /
          tuple
            |
        getitem(1)
            |
        getitem(0)
            |
            d

    After:

        b
        |
        d
    rO   index_stackcurrent_patternmatched_patternsseen.c           	         t        |      dk(  rBt        |      dkD  r4|j                  t        j                  |             |j                          | t	        |      f}||v ry|j                  |       | j                  D ]  }|j                  dk(  rh|j                  t        k(  rUt        |j                  d         D ]9  \  }}|| k(  s|j                  |       |j                  |        	|||||       ; z|j                  dk(  s|j                  t        j                  k(  st        |      dkD  s|j                  d   |d   k(  s|j                          |j                  |        	|||||        |S )aP  
        Traverse the graph recursively to match for the N-tuple - N-getitem patterns,
        starting at the given node.

        We use a stack to keep track of the expected `getitem` indices, since these are
        reversed from the `tuple` indices. In the above example, the stack after
        (b -> tuple -> tuple) will be [0, 1], which will be popped by getitem(1) first
        and then by getitem(0).

        TODO: traverse upwards from the output and handle the case when tuple is not a
        separate node, e.g. graph.call_function(operator.getitem, args=(a, (b, c)))
        r   Nr   r   r   )rY   r   r   clearrF   addr   r   r   r*  rZ   r   r   r   )
rO   r2  r3  r4  r5  stater   r   user_argfind_patternss
            rN   r;  z5_reroute_tuple_getitem_pattern.<locals>.find_patterns  sa   & {q S%9A%=##DIIo$>?!!# u[)*D= JJ 	Dww/)dkkU.B#,TYYq\#: KAx4'#**1-'..t4% +@PRV	 O+x?O?O0O{#a'yy|{26#)'..t4% +@PRV	"  rM   r   r   r   r   N)r   rJ   rK   rI   rF   r   r   r   r   r   rZ   r   rd   r  )r   r4  r5  rO   patternfirst_tuplelast_getitemlast_getitem_index	new_inputr   r;  s             @rN   r  r    sZ   8/ / #Y/  d/  tDz*	/ 
 %eCHo-.// d *,.1eD <dB$4d;<
 $ =ajr{~~0[5G5G55PPPOO.##x'7'77	
8 *..q1$$Q'(:;	++0023 	=D##L)<	==rM   activation_post_processc                 b    t        | t              r| S t        | t              sJ | j                  S )z
    If `activation_post_process` is an observer, return the observer.
    If `activation_post_process` is a fake quantize, return the internal observer.
    )r   r   r   rA  )rA  s    rN   *_get_observer_from_activation_post_processrC  ;  s3     )<8&&13CDDD&>>>rM   dtype_with_constraintsis_activationc                 4    dt         t        t        f   dt        dt        dt
        f fd} |j                  y|r j                  n j                  }|rdnd}d}|8 |       }t        |      sJ |j                  |j                  k7  ry ||||      }|S )	a  
    Return whether `qconfig` satisfies the following constraints from the backend,
    specified through the activation and weight DTypeWithConstraints.

        1. QConfig specified a quantization range that falls within the backend's, if any
        2. QConfig specified a min scale value that is >= the backend's, if any
        3. QConfig specified a FixedQParamsObserver or FixedQParamsFakeQuantize that has
           scale and zero point that match the backend's, if any

    If `is_activation` is True, we check `qconfig.activation`, else we check `qconfig.weight`.
    If `qconfig` or `dtype_with_constraints.dtype` is None, or the dtypes do not match, return True.
    rA  rD  debug_stringrQ   c                    t        |       }t        |dd       }t        |dd       }t        |dd       }|j                  }|j                  }|j                  }	|j
                  }
|j                  }|T|R||t        j                  d| d        y||k  s||kD  r(t        j                  d| d| d| d	| d| d
        y|	E|t        j                  d| d        y||	k  r"t        j                  d| d| d|	 d
        y|
|t        t        fD ]  }t        |      s y d}t        | t              s,t        | t              st        j                  d d|        y|j                  |
k7  s|j                   |k7  r<t        j                  d|j                   d|j                    d|
 d| d
 d|        yy)N	quant_min	quant_maxepszQConfig z4 must specify 'quant_min' and 'quant_max', ignoring FzE quantization range must fall within the backend's:
QConfig range = (z, z), BackendConfig range = (z), ignoring z must specify 'eps', ignoring z eps (zB) must be greater than or equal to the backend's min scale value (TzPlease use torch.ao.quantization.get_default_qconfig_mapping or torch.ao.quantization.get_default_qat_qconfig_mapping. Example:
    qconfig_mapping = get_default_qconfig_mapping("fbgemm")
    model = prepare_fx(model, qconfig_mapping, example_inputs)zjQConfig must specify a FixedQParamsObserver or a FixedQParamsFakeQuantize for fixed qparams ops, ignoring z.
zQConfig fixed scale (z) and zero point (z) do not match the backend's (z and )rC  r   quant_min_lower_boundquant_max_upper_boundscale_min_lower_boundscale_exact_matchzero_point_exact_matchwarningswarnr   r   r   r   r   r   scale
zero_point)rA  rD  rG  observerapp_quant_minapp_quant_maxapp_scale_minbackend_quant_minbackend_quant_maxbackend_scale_minbackend_scale_exact_matchbackend_zero_point_exact_matchaccepted_qconfigsuggestion_strr   s                 rN   ;_activation_post_process_satisfies_dtype_config_constraintszp_qconfig_satisfies_dtype_config_constraints.<locals>._activation_post_process_satisfies_dtype_config_constraints\  sw   
 >>UV+t<+t<  %62HH2HH2HH$:$L$L!)?)V)V&(->-J$(=|n,`ah`ij !22mFW6W|n -((5b H..?-@CTBU V  'y* ($|n,J7)T 00|nF=/ B66G5HU\T]_  &1.: &<=T$U   !'+;< Q  ')= !8:RS77>is>BRT ";;&&*HH+HNN+;;MhNaNaMb c33L2MUSqRr s  'yN+;=
 rM   T
activationrU   )
r   r   r   r   rD   rH   rr   ra  rU   r   )r   rD  rE  r`  activation_post_process_ctrrG  satisfies_constraintsrA  s   `       rN   +_qconfig_satisfies_dtype_config_constraintsrd  I  s    &N!&|5E'E!FN 4N N 
	N` 066> ,   $1<hL "."="?*+BCCC"((,B,H,HHG')? 	
 ! rM   )NN)T)ar   r   rQ  collectionsr   dataclassesr   typingr   r   r   r   rj   torch.nnru   torch.ao.quantizationr	   r
   $torch.ao.quantization.backend_configr   #torch.ao.quantization.fake_quantizer   r   torch.ao.quantization.observerr   r   r   torch.ao.quantization.qconfigr   r   r   %torch.ao.quantization.qconfig_mappingr   torch.ao.quantization.stubsr   torch.ao.quantization.utilsr   r   torch.fxr   r   torch.fx.graphr   r   _decomposedr   custom_configr   __all__rv   
layer_norm
group_norminstance_normr2   r4   rH   r0   r/   rC   rG   rJ   r&   r'   r*   rD   r(   r"   r,   r   r!   r#   r    rK   r   r3   r.   floatr   r   r1   rr   rE   r%   r)   r-   rF   r$   r+   r  r  r   r  r  r0  r  rC  rd  rL   rM   rN   <module>rz     s	      " ! 1 1   7 E 
 
 A 3 * & 2 .4 
HH""	HH""	HH%%  
H 
H 
H,T , , ,*4 *c *d *-	4d
+; ;<-	#Y->I( x &# ( " (4:*> 8
'+Dz81 1S 1HHOO$)36?B	*P
Pc588??23P<@t<LP	Pf*T *d3i *	c 	xS	8I/J 	 j+. ]M*

OQC(s#- ]I&.H(I]H%-G'H]I&.H(I]F#c?A3+?%@]K(30J*K]EOO,s4N.O]K(30D*E]L)C!1E+F]EOO,sOQC4H.I]F#c+E%F d5u{{*+Xtfd3i6G-HHII & OQU4,-xS	8I/JJK P	=
	=	%ekk!
"HdVT#Y->$?
?@	= 59"&	
#ryy.! !bii1  	
 d^@

CHo
 
 
	
8.8FJ8
49d49o%&82 "=
=UXX__,-= =
 sm= 
=2 "K
KUXX__,-K K
 smK 
K,	
	#C$89	ehhoo	=
=88??= UXX__,-= 	=
 
=(\
\88??\ UXX__,-\ 	\
 
\~D	DUXX__,-D d^DN`=% `=F?"<1A#AB??" v!v!0v! v! 
	v!rM   