
    Vh                       d Z ddlmZ ddlZddlZddlZddlmZmZm	Z	 ddl
Z
ddlZ
ddlZ
ddlmZmZmZ e	rddlmZ ddlZddlmZ ddlmZ 	 	 	 	 	 	 	 	 dd	Z	 	 	 	 	 	 dd
Z G d d      Z G d d      ZddZ	 	 	 	 ddZy)z2Dispatcher for AtenLib functions from onnx-script.    )annotationsN)AnyCallableTYPE_CHECKING)diagnosticsregistration
type_utils)Sequence)graph_building)OnnxRegistryc           	         d}|D ];  }|j                   }|d|j                   d|j                   d|j                   dz  }= d|j                   d| S )<Format the diagnostic message for the nearest match warning. zONNX Node: z[opset=z;is_custom=z]. 
z	FX Node: z. 
)onnx_functionnameopset	is_customtarget)	fnselfnodedefault_and_custom_functionsargskwargsall_function_overload_namessymbolic_funcoverload_funcs	            _/home/dcms/DCMS/lib/python3.12/site-packages/torch/onnx/_internal/fx/onnxfunction_dispatcher.pyF_find_opschema_matched_symbolic_function_disagnostic_message_formatterr       s     #%5 O%33#]5G5G4HP]PcPcOddop}  qH  qH  pI  IN  (O  	O#O t{{m4(C'DEE    c                "    d|j                    dS )r   zSearching operator overload: 'z' in onnx registry...
)r   )r   r   r   r   r   s        r   G_find_operator_overloads_in_onnx_registry_disagnostic_message_formatterr"   0   s     ,DKK=8OPPr    c                  @   e Zd ZdZ	 	 	 	 d
dZ	 	 	 	 	 	 	 	 	 	 ddZ	 	 	 	 	 	 ddZ ej                  ej                  j                  e      	 	 	 	 	 	 	 	 	 	 dd       Z	 	 	 	 	 	 ddZ ej                  ej                  j                  e      	 	 	 	 	 	 dd       Zy	)OnnxFunctionDispatchera  A dispatcher that finds the best ONNX Function for ATen/Custom operators.

    It uses the `torch.ops` name to find the function. If not found, it falls back to default.
    Otherwise, the best match is found among all function overloads. An exact match has
    higher precedence over the closest ones.

    Below is a breakdown on how the dispatch mechanism works:

    1. Use the torch.ops name to find the function:
        a. Check if the ATen overload exists in the registry.
        b. If not, check if the default overload exists in the registry.

    2. Find the nearest match among all overloaded functions:
        a. If the types match perfectly, select the function.
        b. Otherwise, find the nearest one with the highest matching score. Because of
            the potential wrongly annotated dtypes and attributes matching, we use
            nearest match to find the best function once the aten name is targeted.

    3. Tie-breaker: If there are multiple nearest matches, we will select the one with
        the highest matching score.

    NOTE: The nearest match `doesn't guarantee` a correct match, and a warning message is logged.
    c                     || _         || _        y)zInitialize the ONNX Function dispatcher.

        Args:
            onnx_registry: The ONNX registry.
            diagnostic_context: The diagnostic context to use for reporting errors.
        N)onnx_registrydiagnostic_context)r   r&   r'   s      r   __init__zOnnxFunctionDispatcher.__init__T   s     +"4r    c                P    | j                  ||      }| j                  |||||      S )a  Dispatches an ONNX function based on the given FX node, arguments, and keyword arguments.
        Args:
            node: The TorchFX node to dispatch the function for.
            onnx_args: The arguments of the ONNX function.
            onnx_kwargs: The keyword arguments of the ONNX function.
            diagnostic_context: The diagnostic context to use for reporting errors.
        Returns:
            Either an `onnxscript.OnnxFunction` or `onnxscript.TracedOnnxFunction` instance based on the dispatch algorithm.
        Raises:
            RuntimeError: If there are no overloaded functions available for the given FX node.
        )get_function_overloads/_find_the_perfect_or_nearest_match_onnxfunction)r   r   	onnx_argsonnx_kwargsr'   r   s         r   dispatchzOnnxFunctionDispatcher.dispatchb   s?    , (,'B'B$(
$ CC(
 	
r    c           	     z   |j                   D cg c]  }t        |       }}t        |      r|D cg c]  }|j                  s| }}|s| j	                  ||      j                         }t        j                  t        j                  j                  t        j                  j                  d| d|j                   d|      }|j                  |       t        j                  |      |S |D cg c]  }|j                  r| }}|s| j	                  ||      j                         }t        j                  t        j                  j                  t        j                  j                  d| d|j                   d|      }|j                  |       t        j                  |      |S c c}w c c}w c c}w )z<Filter the complex functions if the input has complex dtype.z.Cannot find any COMPLEX symbolic function for #, which should be registered under .unsupported_fx_nodez,Can ONLY find COMPLEX symbolic function for )r   _is_arg_with_complex_dtypeany
is_complex_get_aten_namequalified_namer   UnsupportedFxNodeDiagnosticrules&no_symbolic_function_for_call_functionlevelsERRORr   logRuntimeErrorWithDiagnostic)	r   r   r   r'   argargs_with_complex_dtypefuncop_full_name
diagnostics	            r   _filter_or_keep_complexz.OnnxFunctionDispatcher._filter_or_keep_complex   s    OSii"Xs#=c#B"X"X&'!=,,( , 0#22,  ."  )DD%%LL&&,,D\N S88<}AG(,
 #&&z2!<<ZHH& ,+! ">,T__,( , 0#22,  ."  )DD%%LL&&,,B<. Q88<}AG(,
 #&&z2!<<ZHH++K #Y,$,s   F.F3F32F8F8)diagnostic_message_formatterc           	        i |j                         }t              D ]G  }t        |j                        }|j	                  |||      r|j                  c S |j
                  |<   I j                         D 	
ci c]  \  }	}
|
	|	|
 c}
}	s| j                  ||      j                         }t        j                  t        j                  j                  t        j                  j                  d| d|j                   d|      }|j!                  |       t        j"                  |      |j%                  d       t        j                  j&                  |_        t+        fdd      }|d	   j                  S c c}
}	w )
a  Find the perfect/nearest matched OnnxFunction for the given FX node, arguments, and keyword arguments.

        Args:
            default_and_custom_functions: The list includes overloaded functions, with
                custom ones appearing after the default ones.
            onnx_args: Arguments organized in PyTorch inputs way.
            onnx_kwargs: Keyword arguments organized in PyTorch inputs way.
            diagnostic_context: The diagnostic context to use for reporting errors.

            Returns:
                Either an `onnxscript.OnnxFunction` or `onnxscript.TracedOnnxFunction` instance based on the dispatch algorithm.
            Raises:
                RuntimeError: If there are no overloaded functions available for the given FX node.
        z?Cannot find any perfect/nearest match of symbolic function for z",which should be registered under r1   r2   z### Exact match is not found!
Cannot find a perfect match of symbolic overload, a nearest match is found. Please check the ONNX output carefully. 
c                F    |    | j                   j                  |       fS N)r   index)kr   overload_match_rankings    r   <lambda>zXOnnxFunctionDispatcher._find_the_perfect_or_nearest_match_onnxfunction.<locals>.<lambda>  s'    &q),2215 r    T)keyreverser   )inflight_diagnosticreversed_OnnxSchemaCheckerr   perfect_match_inputsmatch_scoreitemsr7   r8   r   r9   r:   r;   r<   r=   r   r>   r?   warningWARNINGlevelsorted)r   r   r   r,   r-   r'   rD   symbolic_functionfunction_opschemarK   vrC   symbolic_function_listrL   s     `          @r   r+   zFOnnxFunctionDispatcher._find_the_perfect_or_nearest_match_onnxfunction   s   8 OQ';;=
 "**F!G 		V 23D3R3R S !55I{ )6668I8U8U"#45		V 499;"
Qq}AqD"
 &  ..(n  %@@!!HH""((QR^Q_ `448KK=C$(J "":.88DDS	

 '--55
 CI"
 C
 &a(666K"
s   =
FFc                   |j                   t        j                  k(  r!t        j                  j                  dd      S t        |j                   t        j                  j                        r|j                   t        j                  j                  j                  k7  r}t        j                  t        j                  j                   t        j"                  j$                  d|j                    d|      }|j'                  |       t        j(                  |      |j                   j*                  }t        j                  j-                  |      S t        |j                   t.        j0                        r=|j2                  D ]  }t        |t        j4                  j6                  t8        t:        f      rHt        |t        j4                  j6                        sXt=        j>                  |j@                  d         r{t        j                  t        j                  j                   t        j"                  j$                  d	| d
tC        |       d|j                    d|      }|j'                  |       t        j(                  |       t        j                  jE                  |j                         S t        |j                   t        j                  jF                        r*t        j                  j-                  |j                         S t        j                  t        j                  j                   t        j"                  j$                  d|j                    |      }|j'                  |       t        j(                  |      )a"  Get the OpName from the target.

        Args:
            node: The TorchFX node to get the aten name for.
            diagnostic_context: The diagnostic context to use for reporting errors.

        Returns:
            The internal op name within dataclass: registration.OpName.
        atengetitem)	namespaceop_namezUnsupported OverloadPacket: z3, aten.sym_size is the only allowed OverloadPacket!r2   )op_overloadvalzUnsupported node arg: z (type z) with builtin function: z@, only int/float/SymInt/SymFloat is supported with built-in ops!zUnknown call_function target: )$r   operatorr`   r   OpNamefrom_name_parts
isinstancetorch_opsOpOverloadPacketopsr_   sym_sizer   r9   r:   r;   r<   r=   r>   r?   defaultfrom_op_overloadtypesBuiltinFunctionTyper   fxNodeintfloatfx_type_utilsis_torch_symbolic_typemetatypefrom_builtin_function
OpOverload)r   r   r'   rD   aten_op_defaultnode_args         r   r7   z%OnnxFunctionDispatcher._get_aten_name
  s    ;;(***&&66 ) 7   dkk5::#>#>? {{eiinn555(DD%%LL&&,,24;;-?rs(,	
 #&&z2!<<ZHH #kk11O&&77O7TTdkk5#<#<= II M"8ehhmmS%-HIx7)@@uAUV!,!H!H#))PP#**000
'$x.AQQjkokvkvjw xZ Z,0"J '**:6%@@LLM  &&<<T[[IIdkk5::#8#89&&77DKK7PP !<<DD$$,T[[M: $	

 	z*44Z@@r    c           	        | j                  ||      }d}| j                  j                  |j                  |j                  |j
                        }|| j                  j                  |j                  |j                  d      }|P|j                         }|j                         }|j                  d       t        j                  j                  |_        || j                  |||      }|S |j                         }t        j                  t        j                  j                   t        j                  j"                  d| d|j$                   d|      }|j'                  |       t        j(                  |      )	ab  Get the function overloads from the registry.

        Args:
            node: The node to get the function overloads for.
            diagnostic_context: The diagnostic context to use for reporting errors.

        Returns:
            The list contains ONNXFunctions, starting with the default ones and
            followed by any custom ones.
        )r   r'   N)ra   rb   overloadz### The operator overload is not found in onnx registry!
Cannot find the operator overload in onnx registry, but the default overload is found. Please check the ONNX output carefully. 
z"Cannot find symbolic function for r0   r1   r2   )r7   r&   get_op_functionsra   rb   r   r8   rP   rV   r   r<   rW   rX   rE   r9   r:   r;   r=   r   r>   r?   )r   r   r'   internal_opnamefunction_grouprC   rD   s          r   r*   z-OnnxFunctionDispatcher.get_function_overloadsK  s   ( 04/B/B*< 0C 0
 BF++<<%//#++$-- = 
 !!//@@)33'// A N
 ).==?/CCE
""`
 $/#5#5#=#=
 %!99n&8N "!&557 <<DD$$0 ?004}A? $

 	z*44Z@@r    N)r&   r   r'   diagnostics.DiagnosticContext)
r   torch.fx.Noder,   USequence[fx_type_utils.TensorLike | str | int | float | bool | list | complex | None]r-   !dict[str, fx_type_utils.Argument]r'   r   return7onnxscript.OnnxFunction | onnxscript.TracedOnnxFunction)r   list[registration.ONNXFunction]r'   r   r   r   )
r   r   r   r   r,   r   r-   r   r'   r   )r   r   r'   r   r   zregistration.OpName)r   r   r'   r   r   r   )__name__
__module____qualname____doc__r(   r.   rE   r   diagnose_callr:   'find_opschema_matched_symbolic_functionr   r+   r7   (find_operator_overloads_in_onnx_registryr"   r*    r    r   r$   r$   ;   s\   05#5 :5"
"

"
 7"
 :"
 
A"
H-, 'F-, :	-,
 
)-,^ [AA%kO7O7 'FO7
	O7 7O7 :O7	O7b?A!?A7T?A	?AB [BB%l?A?A :?A 
)	?A	?Ar    r$   c                      e Zd ZdZ	 	 d	dZed
d       Z	 	 	 	 	 	 	 	 ddZ	 d	 	 	 	 	 	 	 ddZ	 	 	 	 ddZ		 d	 	 	 	 	 	 	 	 	 ddZ
y)rR   a>  
    The OnnxSchemaChecker class is a checker for ONNX OpSchema and param schema.

    It provides methods to check for input compatibility based on the OpSchema. It also
    provides a matching score to indicate how well the OpSchema matches the input and
    kwargs types. A function will be evaluated as perfect match, nearest match eligible,
    or no match.

    Here are some common examples in categories:

    1. [NOTE: Perfect match]: The number of inputs and attributes are exactly the same as
        the OpSchema. The types of inputs and attributes are exactly the same as the
        OpSchema.

        ```python
        inputs = (Tensor[2, 3], Tensor[2, 3])
        attributes = {"alpha": 1.0}


        @torch_op("aten::op")
        def aten_op(self: TReal, other: TReal, alpha: float = 1) -> TReal: ...
        ```
        Result: Perfect match.

    2. [NOTE: Optional input]: The dispatcher recognizes optional inputs. However,
        the input can't be ignored. None must be provided.

        ```python
        inputs = (Tensor([2, 3]), None)
        attributes = {}

        aten_op(X: TTensor, Y: Optional[INT64]):
            ...
        ```
        Result: Perfect match.
        Real example: `aten::convolution`.

    3. [NOTE: Different attributes]: If an attribute is provided with value, it's
        a must to match the attribute in function signature.
        ```python
        inputs = (Tensor([2, 3]),)
        attributes = {"a":1, "b":2}

        aten_op(X: TTensor, a: int):
            ...
        ```
        Result: No match.
        Real example: `aten::div` vs `aten::div.Tensor_mode`.

    4. [NOTE: Default attributes]: Default attribute will fill in the value into
        inputs/attributes.
        ```python
        inputs = (Tensor([2, 3]),)
        attributes = {}

        aten_op(X: TTensor, a: int = 3):
            ...
        ```
        Result: Perfect match.
        Real example: `aten::clone`

    5. [NOTE: Ignore attribute with None value]: The attributes with None value
        will be ignored in matching.
        ```python
        inputs = (Tensor([2, 3]),)
        attributes = {"a": None}

        aten_op(X: TTensor):
            ...
        ```
        Result: Perfect match.

        ```python
        inputs = (Tensor([2, 3]),)
        attributes = {"a": None}

        aten_op(X: TTensor, a: int = 3):
            ...
        ```
        Result: Nearest match eligible.

        Real example: `aten::div` vs `aten::div.Tensor_mode`.

    Attributes:
        onnxfunction: The OnnxFunction.
        param_schema: The parameter schema defined in the OnnxFunction.
        op_schema: The ONNX OpSchema.
        type_constraints: The type constraints defined in the OpSchema.
        attributes: The attributes defined in the OpSchema.
        _matching_score: The matching score of the OnnxSchemaChecker .

    c                n   || _         | j                   j                         | _        | j                   j                  }|J || _        | j                  j                  D ci c]"  }|j
                  t        |j                        $ c}| _        | j                  j                  | _        d| _	        yc c}w )zfInitialize the OnnxSchemaChecker .

        Args:
            onnxfunction: The OnnxFunction.
        N)
onnxfunctionparam_schemasparam_schema	op_schematype_constraintstype_param_strsetallowed_type_strs
attributes_matching_score)r   r   r   
constraints       r   r(   z_OnnxSchemaChecker.__init__  s     ) --;;=%%//	 $$$" #nn==!
  %%s:+G+G'HH!

 ..33+/!
s    'B2c                    | j                   S )a  The matching score of the OnnxSchemaChecker .

        If this remains None, it means the matching score has not been calculated,
        and it's not a nearest match candidate.

        Returns:
            The matching score of the OnnxSchemaChecker .
        )r   )r   s    r   rT   z_OnnxSchemaChecker.match_score  s     ###r    c           	          j                   j                  ||d      \  }|j                  t        j                  d      5  |j                  dt        j                  t        j                   j                               d}t        |      t         j                  j                        k7  ru|j                  t        j                  d      5  |j                  dt        |      t         j                  j                               ddd       |j                  d       d	}t              t         j                        k7  re|j                  t        j                  d
      5  |j                  dt        j                   fd             ddd       |j                  d       d	}|s
	 ddd       y	t         j                  j                  |      D ]  \  }}t!        |      } j"                  |j$                     }	|	j'                  |      r<t)        d |	D              rO|j                  t        j                  d|j*                        5  |j                  d||	       ddd       d	} j-                         D ]w  \  }
} j/                  |
|      r|j                  t        j                  d|
      5  |j                  dt1        |       j                  |
   j0                         ddd       d	}y  j3                  |       |j                  d j4                         |cddd       S # 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   lxY w# 1 sw Y   yxY w)ac  Check if the inputs perfectly match the OpSchema requirements.

        The definition of perfect match is that the input types are all in the type
        constraints and the number of inputs matches the number of inputs in the
        OpSchema.

        Checking steps:
        1. The function signature matches the inputs number, and attribute names.
        2. The input/attribute types are all in the type constraints.

        A function should at least pass the first step to be eligible for the
        nearest matching.

        Args:
            diagnostic: The diagnostic to use for logging detailed info.
            args: The input arguments organized in PyTorch inputs way.
            kwargs: The input keyword arguments organized in PyTorch inputs way.

        Returns:
            True if the inputs match the requirements, False otherwise.
        T)fill_defaultszChecking perfect match...z%szFailed: input number mismatch!zActual %d vs expected %dNz.The function is not a nearest match candidate.FzFailed: attribute mismatch!c                 L    dt                dt        j                         S )NzActual z vs expected )r   r   )function_attributesr   s   r   rM   z9_OnnxSchemaChecker.perfect_match_inputs.<locals>.<lambda>Z  s)    gc2E.F-G}UXY]YhYhUiTj$k r    c              3  F   K   | ]  }t        j                  |        y wrI   )rv   is_optional_onnx_dtype_str).0onnx_type_strs     r   	<genexpr>z:_OnnxSchemaChecker.perfect_match_inputs.<locals>.<genexpr>o  s#      % "<<]Ks   !z+Failed: input type mismatch for input '%s'!zActual %s vs
Expected %sz%Failed: attribute '%s' type mismatch!zmatch score: %d))_separate_input_attributes_from_argumentsr   log_sectionloggingINFOinfor   
LazyStringformat_argumentr   lenr   inputsr   r   zip_find_onnx_data_typer   type_strintersectionr5   r   rU   _match_onnx_attribute_typery   _record_matching_scorerT   )r   rD   r   r   function_inputsis_perfect_matchschema_inputtorch_inputtorch_input_compatible_typesallowed_typesattribute_name	attributer   s   `           @r   rS   z'_OnnxSchemaChecker.perfect_match_inputs  sF   F ::	 ; 
	
 ##GLL2MN Y	$OO&&{'B'BDDUDUV  $?#s4>>+@+@'AA++LL"B  OO2O,DNN112  PQ#( &'3t+??++LL"?  OO#..k  PQ#(  $OY	$ Y	$X .1%%. -)k 0DK/P, $ 5 5l6K6K L$110 )6  $//E$)) 	
 #78)	 (-$1-4 .A-F-F-H -)	66~yQ $//?& 	
 #7 O OON;@@	 (-$-" ''9LMOO-t/?/?@#sY	$ Y	$  D	 	 	 	UY	$ Y	$s   BM':L5AM''*MM'8AM'M''+M'M&4M'!M'<4M0;M'5L?	:M'M	M'MM'M$ M''M0c                   t        |t        t        t        t        f      r>t        j                  t        |      |      }|| j                  |   j                  k7  ryyt        |t        t        f      r|r| j                  ||d   d      S y)N)is_sequenceFr   T)rh   rt   ru   boolstrrv   'from_python_type_to_onnx_attribute_typery   r   listtupler   )r   r   r   r   attribute_onnx_types        r   r   z-_OnnxSchemaChecker._match_onnx_attribute_type  s     i#udC!89"/"W"WY[# #doon&E&J&JJ  	D%=1i22	!$ 3  
 r    c                   d| _         t        | j                  j                  |      D ]P  \  }}t	        |      }| j
                  |j                     }|j                  |      s<| xj                   dz  c_         R | j                  j                         D ]M  \  }}||   }	t        j                  t        |	            }
|
|j                  k7  s9| xj                   dz  c_         O y)ah  Calculate the inputs matching score of the OpSchema requirements to find the nearest match.

        Only the functions which have the same number of inputs and attributes as the
        OpSchema are eligible to be a nearest match candidate. Thus, we don't need to
        check the length of inputs and attributes here, and only check the types of
        inputs and attributes.

        How the matchsing score is calculated:
            score += 1 if one input/attribute type is in the type constraints.

        Limitations:
            None/NoeType/[] could result in zero matches, and the same score of overloads,
            which will be recorded in SARIF.

        Args:
            inputs: The input arguments.
            attributes: The input keyword arguments.

        Returns:
            True if the inputs match the requirements, False otherwise.
        r      N)r   r   r   r   r   r   r   r   r   rU   rv   r   ry   )r   r   r   r   r   r   r   r   attribute_protor   r   s              r   r   z)_OnnxSchemaChecker._record_matching_score  s    8  ! *-T^^-B-BF)K 	*%L++?+L( 11,2G2GHM))*FG $$)$	* 04/D/D/F 	*+NO">2I"/"W"WY# #o&:&:: $$)$	*r    c                ~   ddl }g }i }|j                         }t        |      D ]n  \  }	}
|
j                  r|j	                  ||	d        g }*|	t        |      k  r4|
j                  r|j                  ||	          Y||	   ||
j                  <   l|
j                  |v rc|
j                  r:|j                  ||
j                            |j                  |
j                         ||
j                     ||
j                  <   |
j                  rc| j                  |
j                     j                  j                  |j                  j                  k7  r|s1|
j                   ||
j                  <   L|
j                  sZ|s^|j                  d       q |j#                         D ]  \  }}||vs||||<    ||fS )a+  Separate Python args and kwargs into ONNX inputs and attributes.

        Extra_kwargs are ignored if their values are None. For example, if the
        OpSchema has an attribute "rounding_mode" and the caller provides
        "rounding_mode=None", the attribute "rounding_mode" will not be included
        in the returned attributes when the OnnxFunction signature doesn't have
        "rounding_mode" as an attribute.

        Args:
            param_schemas: The parameter schemas of an Op or a OnnxFunction.
            args: The Python positional arguments supplied by the caller.
            kwargs: The Python keyword arguments supplied by the caller.
            fill_defaults: Whether to fill the default values for attributes.

        Returns:
            A tuple of two elements:
            - A list of ONNX inputs.
            - An dictionary of ONNX attribute names and values.

        Raises:
            TypeError: When allow_extra_kwargs is False and there are unknown kwargs.
            TypeError: When a required input is not provided.
        r   N)onnxcopy	enumerateis_variadic_inputextendr   is_inputappendr   popis_attributer   default_valuery   AttributeProto	UNDEFINEDrn   rU   )r   r   r   r   r   r   onnx_inputsonnx_attributescopy_kwargsiparamrK   r\   s                r   r   z<_OnnxSchemaChecker._separate_input_attributes_from_arguments  s   F 	!#*,kkm!-0 	-HAu&&""48,3t9}>>&&tAw/26q'OEJJ/{*>>&&{5::'>?OOEJJ/2=ejj2IOEJJ/""OOEJJ/==BB&&001 !27--OEJJ/ &&t,;	-B  %%' 	'DAq'AM%&"	' O++r    N)r   r   )r   z
int | None)rD   zdiagnostics.Diagnosticr   r   r   r   r   r   )F)r   r   r   zDfx_type_utils.Argument | onnxscript_graph_building.TorchScriptTensorr   r   r   r   )r   r   r   r   )T)
r   z'Sequence[onnxscript.values.ParamSchema]r   r   r   r   r   r   r   z tuple[list[Any], dict[str, Any]])r   r   r   r   r(   propertyrT   rS   r   r   r   r   r    r   rR   rR     s    [z0M00 	$ 	$B$*B$
B$ 2B$ 
B$P "	 X 	
 
.0*
0*
 60*x #M,>M,
M, 2M, M, 
*M,r    rR   c                B   t        | t        j                  j                        rXd| j                  v rJt        | j                  d   t        j
                        r#t        j                  | j                  d         ryt        | t              r| D ]  }t        |      c S  y)z0Check if the node has complex dtype recursively.rd   TF)	rh   ri   rr   rs   rx   Tensorr6   r   r4   )r@   items     r   r4   r4   3  sx     	3&SXXsxx5SXXe_-	C	 	4D-d33	4r    c                   t        | t        j                        r+| j                  t        j                  | j                        S t        | t
        t        t        t        t        f      rt        j                  t        |             S t        | t        t        f      rH| rFt        d | D        d      }t        |      }t        d | D              r|D ch c]  }d| d
 c}S |S | >t        | t        j                        r| j                  t        | t        t        f      r| s
t!               S t#        d|        c c}w )zYConvert inputs data type from torch acceptable dtype to the compatible onnx dtype string.Nc              3  &   K   | ]	  }||  y wrI   r   )r   r   s     r   r   z'_find_onnx_data_type.<locals>.<genexpr>W  s     >dT-=T>s   c              3  P   K   | ]  }t        |t        j                           y wrI   )rh   rv   
TensorLike)r   inputs     r   r   z'_find_onnx_data_type.<locals>.<genexpr>Z  s     Tuz%!9!9:Ts   $&zseq()zUnknown input type from input: )rh   rv   r   dtype"from_torch_dtype_to_onnx_dtype_strrt   ru   r   r   complexry   r   r   nextr   r5   r   RuntimeError)r   the_first_non_none_item	set_dtyper   s       r   r   r   B  s    	; 8 89)??@Q@QRR+UD#w?@??[@QRR+e}-+"&>k>#
 ))@A	TTT1:;d5'O;; {M$<$<=!!){T5M2; u
8F
GG! <s   D?)r   r   r   r   r   r   r   r   )r   r   r   r   r   r   )r@   zfx_type_utils.Argumentr   r   )r   zSfx_type_utils.TensorLike | str | int | float | bool | list | tuple | complex | Noner   zset[str]) r   
__future__r   r   re   rp   typingr   r   r   ri   
torch._opstorch.fxtorch.onnx._internal.fxr   r   r	   rv   collections.abcr
   
onnxscript"onnxscript.function_libs.torch_libr   onnxscript_graph_building
torch.onnxr   r   r"   r$   rR   r4   r   r   r    r   <module>r      s    8 "    / /     ( (FF F #B	F 	F QQ Q 	QSA SAl
_, _,D*H*H *Hr    