Ë
    ÛÓ^jUœ  ã                  ón
  — U 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 ddl	m
Z
 ddl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 d
dlmZmZmZmZmZmZ  e«       rddlZddl m!Z! ddl"m#Z# ddl$m%Z%  e«       rddl&Z&ddl'm(Z( ddl)m*Z+ erddl,m-Z-  e«       r
ddl'm.Z.m/Z/m0Z0  ejb                  e2«      Z3 G d„ de«      Z4e
d„ «       Z5dYd„Z6 edd«      d„ «       Z7 eddd«      d„ «       Z8 edd«      d „ «       Z9 edd!«      d"„ «       Z: edd#«      d$„ «       Z; edd%«      d&„ «       Z< edd'«      d(„ «       Z=dZd)„Z> edd*d+«      d,„ «       Z? edd-d.«      d/„ «       Z@ edd0d1«      d2„ «       ZA edd3«      d4„ «       ZB edd5«      d6„ «       ZC edd7«      d8„ «       ZD edd9«      d:„ «       ZE edd;«      d<„ «       ZF edd=«      d>„ «       ZG edd?«      d@„ «       ZH eddA«      dB„ «       ZI eddC«      dD„ «       ZJ eKej˜                  ejš                  ejœ                  ejž                  ej                   ej¢                  h«      ZR ed«      d[dE„«       ZS ed«      d[dF„«       ZT ed«      d[dG„«       ZU ed«      d[dH„«       ZV eW«       ZX e«       rÞeXj³                  ej´                  j¶                  j¸                  jº                  ej´                  j¶                  j¸                  j¼                  ej´                  j¶                  j¾                  jº                  ej´                  j¶                  jÀ                  jº                  ej´                  j¶                  jÂ                  jº                  h«        ed«      d[dI„«       Zb ed«      d[dJ„«       Zc ed«      d[dK„«       Zd ed«      d[dL„«       Ze ed«      d[dM„«       Zfd\dN„Zg	 d]	 	 	 	 	 	 	 	 	 d^dO„Zhd_d`dP„ZidadbdQ„ZjdadR„ZkdS„ ZldT„ Zmi ZndUeodV<    e«       �rCenj³                  ej´                  j¶                  jà                  jº                  eiej´                  j¶                  jâ                  jº                  ehej´                  j¶                  jä                  jº                  ejej´                  jæ                  jè                  jº                  ejej´                  j¶                  jê                  jì                  ekej´                  j¶                  jî                  jð                  emej´                  j¶                  jî                  jò                  emejô                  eli«       dcdW„Z{e{gZ|dddX„Z}y)euX  ONNX exporter.

Extends `DynamoExporter` with five extra stages that convert an `ExportedProgram`
into an ONNX model via `torch.onnx.export`:

1. **Torch patches** (`_PATCHES["onnx"]` via `apply_patches("onnx")`): reversibly
   monkey-patch `torch` ops at tracing time so `torch.export` and `torch.onnx.export`
   emit ONNX-lowerable patterns. Reverted on exit.
2. **ONNX patches** (`_PATCHES["onnx"]` via `apply_patches("onnx")`): reversibly
   hook `torch.onnx` internals â€” specifically `_prepare_exported_program_for_export`,
   so the FX node fixes (stage 3) run again right after `run_decompositions`.
   Same registry as stage 1, installed by the same `apply_patches` call.
3. **FX node fixes** (`_FX_NODE_FIXES["onnx"]` via `apply_fx_node_fixes("onnx", gm)`):
   per-node in-place rewrites on the `GraphModule` to drop or replace nodes ONNX
   can't lower (alias, in-place ops, dead comparisons, `_assert_*`, â€¦). Triggered
   both directly after `torch.export` and indirectly via the stage 2 hook.
4. **ONNX translations** (`_ONNX_TRANSLATION_TABLE`): custom onnxscript functions
   passed as `custom_translation_table` that override the default torchlib
   lowering for specific aten ops where it's buggy or missing.
5. **ONNX IR fixes** (`_IR_FIXES` via `apply_onnx_ir_fixes`): post-export in-place
   fixes on the `ONNXProgram` IR for ORT compatibility.
é    )ÚannotationsN)ÚMutableMappingÚSequence)Úcontextmanager)ÚTYPE_CHECKINGÚAnyé   )Úlogging)Úis_onnxscript_availableÚis_torch_availableé   )Ú
OnnxConfig)ÚDynamoExporter)Úapply_fx_node_fixesÚapply_patchesÚduplicate_leaf_tensorsÚget_leaf_tensorsÚregister_fx_node_fixÚregister_patch)ÚExportedProgram)ÚONNXProgram)Úmasking_utils)Úaten_index_put)Úopset18)ÚPreTrainedModel)ÚBOOLÚINT64ÚTRealc                  óH   ‡ — e Zd ZdZg d¢ZddddœZ	 	 	 	 	 	 	 	 dˆ fd„Zˆ xZS )ÚOnnxExporteraÚ  Exporter that converts a [`PreTrainedModel`] to an ONNX `ONNXProgram`.

    Example:

    ```python
    >>> from transformers.exporters.exporter_onnx import OnnxExporter, OnnxConfig

    >>> exporter = OnnxExporter()
    >>> onnx_program = exporter.export(model, inputs, config=OnnxConfig(dynamic=True))
    >>> outputs = onnx_program(**inputs)  # run in-memory
    >>> exporter.export(model, inputs, config=OnnxConfig(output_path="model.onnx"))  # save to disk
    ```
    )ÚtorchÚonnxÚ
onnxscriptz2.12.0z1.21.0z0.7.0c                ó’  •— t        |t        «      rt        di |¤Ž}n(t        |«      t        urt	        dt        |«      › �«      ‚t        |«      5 \  }}t        d«      5  t        ‰| �!  |||¬«      }t        ||«      \  }}t        d|j                  «       t        j                  j                  |d|j                  ||t        j                   t        |«      «      t"        |j$                  |j&                  |j(                  |j*                  ¬«      }d d d «       d d d «       t-        «       |S # 1 sw Y   ŒxY w# 1 sw Y   Œ"xY w)Nz1Expected config to be an OnnxConfig or dict, got r"   )Úconfig© )
ÚargsÚfÚinput_namesÚoutput_namesÚkwargsÚcustom_translation_tableÚopset_versionÚexternal_dataÚexport_paramsÚoptimize)Ú
isinstanceÚdictr   ÚtypeÚ	TypeErrorÚpatch_model_outputsr   ÚsuperÚexportÚdisambiguate_io_namesr   Úgraph_moduler!   r"   Úoutput_pathÚcopyÚdeepcopyÚ_ONNX_TRANSLATION_TABLEr-   r.   r/   r0   Úapply_onnx_ir_fixes)	ÚselfÚmodelÚsample_inputsr%   Úinputs_namesÚoutputs_namesÚexported_programÚonnx_programÚ	__class__s	           €úo/var/www/ramen.bs-engineer-server.com/venv/lib/python3.12/site-packages/transformers/exporters/exporter_onnx.pyr7   zOnnxExporter.exporti   s/  ø€ ô �fœdÔ#ÜÑ) &Ñ)‰FÜ�&‹\¤Ñ+ÜÐOÔPTÐU[ÓP\È~Ð^Ó_Ð_ä  Ó'ð 	Ñ+H¨L¸-Ì-ÐX^ÓJ_ñ 	Ü05±±¸uÀmÐ\b°Ó0cÐÜ*?ÀÈmÓ*\Ñ'ˆL˜-Ü Ð(8×(EÑ(EÔFÜ(-¯
©
×(9Ñ(9Ø ØØ×$Ñ$Ø(Ø*Ü—}‘}¤T¨-Ó%8Ó9Ü)@Ø$×2Ñ2Ø$×2Ñ2Ø$×2Ñ2ØŸ™ð ):ó )ˆL÷		÷ 	ô$ 	˜LÔ)ØÐ÷'	ð 	ú÷ 	ð 	ús%   ÁD=Á B4D1ÄD=Ä1D:	Ä6D=Ä=E)r@   r   rA   zMutableMapping[str, Any]r%   zOnnxConfig | dict[str, Any]Úreturnr   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__Úrequired_packagesÚtested_versionsr7   Ú__classcell__)rF   s   @rG   r    r    W   sL   ø„ ñò 8ÐØ (°(È'ÑR€Oðàðð 0ðð ,ð	ð
 
÷ñ ó    r    c              #  ó²   ‡‡‡K  — g Šg Š| j                   Št        j                  ‰«      ˆˆˆfd„«       }	 || _         ‰‰f–— ‰| _         y# ‰| _         w xY w­w)z×Wrap `model.forward` to return a flat `dict[str, Tensor]` with duplicated outputs,
    and capture the input/output tensor names from the traced forward in the yielded
    `(inputs_names, outputs_names)` lists.
    c            	     óÊ   •— t        t         ‰| i |¤Ž«      «      }‰j                  t        |«      j                  «       «       ‰j                  |j                  «       «       |S ©N)r   r   ÚextendÚkeys)r'   r+   ÚoutputsrB   Úoriginal_forwardrC   s      €€€rG   Úpatched_forwardz,patch_model_outputs.<locals>.patched_forward™   sU   ø€ ä"Ô#9Ñ:JÈDÐ:[ÐTZÑ:[Ó#\Ó]ˆØ×ÑÔ,¨VÓ4×9Ñ9Ó;Ô<Ø×Ñ˜WŸ\™\›^Ô,ØˆrP   N)ÚforwardÚ	functoolsÚwraps)r@   rX   rB   rW   rC   s     @@@rG   r5   r5   Ž   s_   úè ø€ ð !€LØ!€MØ—}‘}Ðä‡_�_Ð%Ó&õó 'ðð)Ø'ˆŒØ˜MÐ)Ò)à(ˆ�øÐ(ˆ�üs   …0A¶A ÁAÁ	AÁAc                ó¶   — t        | «      j                  t        |«      «      D ]0  }d|› �| | j                  |«      <   d|› �||j                  |«      <   Œ2 | |fS )zEPrefix any name that appears in both lists with `input.` / `output.`.zinput.zoutput.)ÚsetÚintersectionÚindex)rB   rC   Únames      rG   r8   r8   §   sl   € ä�LÓ!×.Ñ.¬s°=Ó/AÓBò DˆØ39¸$¸°ˆ�\×'Ñ'¨Ó-Ñ.Ø5<¸T¸FÐ3Cˆ�m×)Ñ)¨$Ó/Ò0ðDð ˜Ð&Ð&rP   r"   ztorch.wherec                ó   ‡ — dˆ fd„	}|S )z,Normalize dtypes and scalars in torch.where.c                óž  •— t        |t        j                  «      rOt        |t        j                  «      r5|j                  |j                  k7  r|j	                  |j                  «      }nÃt        |t        j                  «      rHt        |t
        t        t        f«      r-t        j                  ||j                  |j                  ¬«      }nat        |t        j                  «      rGt        |t
        t        t        f«      r,t        j                  ||j                  |j                  ¬«      }|€
|€ ‰| «      S |€	 ‰| |«      S  ‰| ||«      S )N©ÚdtypeÚdevice)
r1   r!   ÚTensorrd   ÚtoÚintÚfloatÚboolÚtensorre   )Ú	conditionÚxÚyÚoriginals      €rG   Úpatchz_patch_where.<locals>.patch»   sæ   ø€ Ü�aœŸ™Ô&¬:°a¼¿¹Ô+FÈ1Ï7É7ÐVW×V]ÑV]ÒK]Ø—‘�Q—W‘W“‰AÜ˜œ5Ÿ<™<Ô(¬Z¸¼CÄÌÐ;MÔ-NÜ—‘˜Q a§g¡g°a·h±hÔ?‰AÜ˜œ5Ÿ<™<Ô(¬Z¸¼CÄÌÐ;MÔ-NÜ—‘˜Q a§g¡g°a·h±hÔ?ˆAØˆ9˜˜Ù˜IÓ&Ð&ØˆYÙ˜I qÓ)Ð)á˜I q¨!Ó,Ð,rP   ©NNr&   ©ro   rp   s   ` rG   Ú_patch_wherers   ·   s   ø€ õ-ð €LrP   ztorch.unsqueezeztorch.Tensor.unsqueezec                ó   ‡ — ˆ fd„}|S )z+Support complex tensors in torch.unsqueeze.c                ó¸   •— t        j                  | «      r< ‰| j                  |«      } ‰| j                  |«      }t        j                  ||«      S  ‰| |«      S rS   )r!   Ú
is_complexÚrealÚimagÚcomplex)Úself_or_inputÚdimrw   rx   ro   s       €rG   rp   z_patch_unsqueeze.<locals>.patchÐ   sS   ø€ Ü×Ñ˜MÔ*Ù˜M×.Ñ.°Ó4ˆDÙ˜M×.Ñ.°Ó4ˆDÜ—=‘=  tÓ,Ð,Ù˜ sÓ+Ð+rP   r&   rr   s   ` rG   Ú_patch_unsqueezer|   Ì   s   ø€ ô,ð €LrP   z/transformers.masking_utils._vmap_expansion_sdpac                ó   — d„ }|S )z;Replace vmap-based mask expansion with broadcast expansion.c                ó   ‡ — ˆ fd„}|S )Nc                óÎ   •— t        j                  | |||«      } ‰|Ž j                  | j                  d   |j                  d   |j                  d   |j                  d   «      }|S ©Nr   )r   Ú_non_vmap_expansion_sdpaÚexpandÚshape)Úbatch_arangeÚhead_arangeÚq_arangeÚ	kv_arangeÚ
brodcastedÚresultÚmask_functions         €rG   Ú	_expandedzA_patch_broadcast_mask_expansion.<locals>.patch.<locals>._expandedß   sl   ø€ Ü&×?Ñ?ÀÈkÐ[cÐenÓoˆJÙ" JÐ/×6Ñ6Ø×"Ñ" 1Ñ% {×'8Ñ'8¸Ñ';¸X¿^¹^ÈAÑ=NÐPY×P_ÑP_Ð`aÑPbóˆFð ˆMrP   r&   )rŠ   r‹   s   ` rG   rp   z._patch_broadcast_mask_expansion.<locals>.patchÞ   s   ø€ ô	ð ÐrP   r&   )Ú	_originalrp   s     rG   Ú_patch_broadcast_mask_expansionr�   Ú   s   € òð €LrP   ztorch.nn.RMSNorm.forwardc                ó   ‡ — ˆ fd„}|S )zAUse non-fused RMS normalization when elementwise_affine is False.c                ó(  •— | j                   s}|j                  t        j                  «      j	                  d«      j                  dd¬«      }|t        j                  || j                  z   «      z  j                  |j                  «      S  ‰| |«      S )Nr	   éÿÿÿÿT)Úkeepdim)	Úelementwise_affinerg   r!   Úfloat32ÚpowÚmeanÚrsqrtÚepsrd   )r?   rm   Úvariancero   s      €rG   rp   z&_patch_rms_norm_forward.<locals>.patchï   sr   ø€ Ø×&Ò&Ø—t‘tœEŸM™MÓ*×.Ñ.¨qÓ1×6Ñ6°rÀ4Ð6ÓHˆHØœŸ™ H¨t¯x©xÑ$7Ó8Ñ8×<Ñ<¸Q¿W¹WÓEÐEÙ˜˜aÓ Ð rP   r&   rr   s   ` rG   Ú_patch_rms_norm_forwardr™   ë   s   ø€ ô!ð €LrP   ztorch.randpermc                óR   — t         j                  t         j                  ddddœd„}|S )uT   Implement randperm via argsort(rand(n)) â€” no ONNX decomposition for aten.randperm.NF)rd   Úlayoutre   Ú
pin_memoryÚ	generatorc               ót   — t        j                  t        j                  | |¬«      «      j                  |«      S )N©re   )r!   ÚargsortÚrandrg   )Únrd   r›   re   rœ   r�   s         rG   rp   z_patch_randperm.<locals>.patchü   s'   € Ü�}‰}œUŸZ™Z¨°&Ô9Ó:×=Ñ=¸eÓDÐDrP   )r!   Úint64Ústridedrr   s     rG   Ú_patch_randpermr¥   ø   s&   € ô  Ÿ+™+¬e¯m©mÀDÐUZÐfjô Eð €LrP   ztorch.histcc                ó   — dddœd„}|S )u~  Replace `torch.histc` with a statically-shaped, deterministic equivalent.

    The default torchlib `aten_histc` translation rejects integer input (`torch.histc only
    works on float`), and the obvious workaround â€” casting to float â€” calls `_histc_cuda`
    which has no deterministic implementation on CUDA. `bincount`'s output is an unbacked
    SymInt under torch.export and trips downstream meta-shape guards (e.g. grouped_mm's
    `offs` size check). Pre-allocating `torch.zeros(bins)` + `scatter_add_` keeps the output
    shape pinned to `bins` (a Python int), and `scatter_add_` is deterministic on integer
    indices.
    N)Úoutc               óÌ  — | j                  d«      }||cxk(  rdk(  r@n n=|j                  «       j                  «       }|j                  «       j                  «       }nTt	        j
                  t        |«      |j                  ¬«      }t	        j
                  t        |«      |j                  ¬«      }||z
  |z  }|j                  «       |z
  |z  j                  «       j                  d|dz
  «      }	| j                  «       r| j                  nt        j                  }
t	        j                  ||
| j                  ¬«      }|j                  d|	t	        j                  |	|
¬«      «      S )Nr�   r   rŸ   r   rc   ©rd   )ÚreshapeÚminri   Úmaxr!   rk   re   ÚlongÚclamp_Úis_floating_pointrd   ÚzerosÚscatter_add_Ú	ones_like)ÚinputÚbinsr«   r¬   r§   ÚflatÚmin_valÚmax_valÚ	bin_widthÚidxÚ	out_dtypeÚcountss               rG   rp   z_patch_histc.<locals>.patch  s  € Ø�}‰}˜RÓ ˆØ�#Œ?˜�?Ø—h‘h“j×&Ñ&Ó(ˆGØ—h‘h“j×&Ñ&Ó(‰Gä—l‘l¤5¨£:°d·k±kÔBˆGÜ—l‘l¤5¨£:°d·k±kÔBˆGØ˜wÑ&¨$Ñ.ˆ	Ø—
‘
“˜wÑ&¨)Ñ3×9Ñ9Ó;×BÑBÀ1ÀdÈQÁhÓOˆØ#(×#:Ñ#:Ô#<�E—K’KÄ%Ç+Á+ˆ	Ü—‘˜T¨¸5¿<¹<ÔHˆØ×"Ñ" 1 c¬5¯?©?¸3ÀiÔ+PÓQÐQrP   )éd   r   r   r&   rr   s     rG   Ú_patch_histcr½     s   € ðR°Dô Rð €LrP   z4onnxscript.onnx_opset._impl.opset13.Opset13.Constantc                ó   ‡ — ˆ fd„}|S )u	  Substitute `op.Constant(value_ints=[])` with an explicit empty INT64 tensor.

    Upstream onnxscript's `aten_index_put` does `op.Constant(value_ints=none_indices)`
    where `none_indices` can be empty (when every input dim has an advanced index).
    `onnx_ir` then logs an ambiguous-type warning because an empty Python list has no
    derivable element type. Swap the empty-`value_ints` call for `value=ir.tensor([], INT64)`
    â€” semantically identical, no ambiguity. Drop once onnxscript fixes the call site.
    c                óÜ   •— |j                  d«      g k(  rL|j                  d«       t        j                  t	        j
                  g t        j                  ¬«      «      |d<    ‰| g|¢­i |¤ŽS )NÚ
value_intsr©   Úvalue)ÚgetÚpopÚonnx_irrk   ÚnpÚarrayr£   )r?   r'   r+   ro   s      €rG   rp   z&_patch_opset13_constant.<locals>.patch+  sV   ø€ Ø�:‰:�lÓ# rÒ)Ø�J‰J�|Ô$Ü%Ÿn™n¬R¯X©X°bÄÇÁÔ-IÓJˆF�7‰OÙ˜Ð.˜tÒ. vÑ.Ð.rP   r&   rr   s   ` rG   Ú_patch_opset13_constantrÇ      s   ø€ ô/ð €LrP   c               ó   ‡— ˆfd„}|S )zFDecompose cummax/cummin via triangular-mask reduction (O(N^2) memory).c                ó6  •— | j                   |   }| j                  |d«      } |j                  d«      j                  g |j                   d d ¢|‘|‘­Ž }t	        j
                  ||t        j                  | j                  ¬«      j                  «       }| j                  t        j                  k(  r‰
dk7  }n¿| j                  «       rX‰
dk(  r)t	        j                  | j                  «      j                  n(t	        j                  | j                  «      j                  }nW‰
dk(  r)t	        j                  | j                  «      j                  n(t	        j                  | j                  «      j                  }t	        j                  d|| j                  | j                  ¬«      }t	        j                   |||«      }‰
dk(  r|j                  d¬«      n|j                  d¬«      }	|	j"                  j                  d|«      |	j$                  j                  d|«      fS )Nr�   éþÿÿÿrc   r¬   r&   ©r{   )rƒ   ÚmovedimÚ	unsqueezer‚   r!   Úonesrj   re   Útrilrd   r¯   Úfinfor«   r¬   ÚiinfoÚfullÚwhereÚvaluesÚindices)r³   r{   r¢   rm   Úx_gridÚincludeÚfill_valÚfillÚmaskedr§   Úmodes             €rG   rp   z&_patch_cummax_or_cummin.<locals>.patch7  s†  ø€ Ø�K‰K˜ÑˆØ�M‰M˜#˜rÓ"ˆØ'�—‘˜R“×'Ñ'Ð<¨¯©°°"¨Ð<°qÐ<¸!Ò<ˆÜ—*‘*˜Q ¬¯©¸E¿L¹LÔI×NÑNÓPˆØ�;‰;œ%Ÿ*™*Ò$Ø˜u‘}‰HØ×$Ñ$Ô&Ø7;¸u²}”u—{‘{ 5§;¡;Ó/×3Ò3Ì%Ï+É+ÐV[×VaÑVaÓJb×JfÑJf‰Hà7;¸u²}”u—{‘{ 5§;¡;Ó/×3Ò3Ì%Ï+É+ÐV[×VaÑVaÓJb×JfÑJfˆHÜ�z‰z˜"˜h¨e¯k©kÀ%Ç,Á,ÔOˆÜ—‘˜W f¨dÓ3ˆØ$(¨E¢Mˆf�j‰j˜RˆjÔ °v·z±zÀb°zÓ7IˆØ�z‰z×!Ñ! " cÓ*¨C¯K©K×,?Ñ,?ÀÀCÓ,HÐHÐHrP   r&   )ro   rÛ   rp   s    ` rG   Ú_patch_cummax_or_cumminrÜ   4  s   ø€ ôIð  €LrP   ztorch.cummaxztorch.Tensor.cummaxc                ó   — t        | d¬«      S )Nr¬   ©rÛ   ©rÜ   ©ro   s    rG   Ú_patch_cummaxrá   J  ó   € ä" 8°%Ô8Ð8rP   ztorch.cumminztorch.Tensor.cumminc                ó   — t        | d¬«      S )Nr«   rÞ   rß   rà   s    rG   Ú_patch_cumminrä   O  râ   rP   z	torch.expztorch.Tensor.expc                ó   ‡ — ˆ fd„}|S )u�   Lower `exp` on complex tensors via Euler â€” onnxscript has no dispatch for `aten.exp` on
    complex inputs. Real inputs hit the original path.c                óú   •— t        j                  | «      r^ ‰| j                  «      }t        j                  || j                  j                  «       z  || j                  j                  «       z  «      S  ‰| «      S rS   )r!   rv   rw   ry   rx   ÚcosÚsin)r³   Ú	magnitudero   s     €rG   rp   z_patch_exp.<locals>.patchY  sZ   ø€ Ü×Ñ˜EÔ"Ù  §¡Ó,ˆIÜ—=‘= ¨U¯Z©Z¯^©^Ó-=Ñ!=¸yÈ5Ï:É:Ï>É>ÓK[Ñ?[Ó\Ð\Ù˜‹ÐrP   r&   rr   s   ` rG   Ú
_patch_exprê   T  s   ø€ ô
ð €LrP   ztorch.fft.irfftc                ó   — dd„}|S )uY  Replace `irfft` with `ifft` over the conjugate-mirrored input â€” ORT's `DFT` op rejects the
    `is_onesided=1`/`inverse=1` combination that torch's `irfft` lowers to. Mirroring restores the
    full spectrum so the inverse path uses two-sided DFT, which ORT accepts. Assumes even `n`
    (which is the common case for STFT-based audio codecs).c                ób  — |€d| j                   |   dz
  z  }t        d «      g| j                  z  }t        dd«      ||<   t        j                  | | t        |«         j                  |g¬«      j                  «       g|¬«      }t        j                  j                  ||||¬«      j                  S )Nr	   r   r�   )ÚdimsrË   )r¢   r{   Únorm)rƒ   ÚsliceÚndimr!   ÚcatÚtupleÚflipÚconjÚfftÚifftrw   )r³   r¢   r{   rî   ÚslcrÒ   s         rG   rp   z_patch_irfft.<locals>.patchi  s›   € Øˆ9Ø�U—[‘[ Ñ%¨Ñ)Ñ*ˆAÜ�T‹{ˆm˜eŸj™jÑ(ˆÜ˜˜B“<ˆˆC‰Ü�y‰y˜% ¤u¨S£zÑ!2×!7Ñ!7¸c¸UÐ!7Ó!C×!HÑ!HÓ!JÐKÐQTÔUˆÜ�y‰y�~‰~˜d a¨S°tˆ~Ó<×AÑAÐArP   )Nr�   Nr&   rr   s     rG   Ú_patch_irfftrø   b  s   € óBð €LrP   ztorch.bucketizec                ó   — dddœd„}|S )zUVectorized bucketize avoiding scalar-constant tensors that cause alias/detach issues.F)Ú	out_int32Úrightc               óv  — |j                  «       dk(  rHt        j                  | t        j                  ¬«      }|r|j	                  t        j
                  «      S |S |r|| j                  d«      k  }n|| j                  d«      k  }|j                  d«      }|r|j	                  t        j
                  «      S |S )Nr   r©   r�   )Únumelr!   Ú
zeros_liker£   rg   Úint32rÍ   Úsum)r³   Ú
boundariesrú   rû   r‰   Úmasks         rG   rp   z_patch_bucketize.<locals>.patchx  s“   € Ø×ÑÓ Ò"Ü×%Ñ% e´5·;±;Ô?ˆFÙ-6�6—9‘9œUŸ[™[Ó)ÐB¸FÐBÙØ §¡°Ó!4Ñ4‰Dà §¡°Ó 3Ñ3ˆDØ—‘˜"“ˆÙ)2ˆv�y‰yœŸ™Ó%Ð>¸Ð>rP   r&   rr   s     rG   Ú_patch_bucketizer  t  s   € ð /4¸5ô 	?ð €LrP   ztorch.searchsortedc                ó   — ddddddœd„}|S )uG  Decompose searchsorted via broadcast comparison + sum â€” no ONNX op for searchsorted.

    For sorted inputs the insertion index equals the count of elements satisfying
    the comparison (< for left, <= for right). This is O(N*M) instead of the
    real binary-search O(M log N) but only uses ops with ONNX translations.
    FN)rú   rû   Úsider§   Úsorterc               ó
  — |�|dk(  }|r$| j                  d«      |j                  d«      k  }n#| j                  d«      |j                  d«      k  }|j                  d«      }|r|j                  t        j                  «      S |S )Nrû   r�   rÊ   )rÍ   r   rg   r!   rÿ   )	Úsorted_sequencerÔ   rú   rû   r  r§   r  r  r‰   s	            rG   rp   z"_patch_searchsorted.<locals>.patch�  s{   € ØÐØ˜G‘OˆEÙØ"×,Ñ,¨RÓ0°F×4DÑ4DÀRÓ4HÑH‰Dà"×,Ñ,¨RÓ0°6×3CÑ3CÀBÓ3GÑGˆDØ—‘˜"“ˆÙ)2ˆv�y‰yœŸ™Ó%Ð>¸Ð>rP   r&   rr   s     rG   Ú_patch_searchsortedr	  †  s   € ð 5:ÀÈTÐW[Ðdhô ?ð €LrP   z
torch.fullc                ó   ‡ — ddœˆ fd„
}|S )z`Force dtype=torch.long when fill_value is int and no dtype specified (ONNX defaults to float32).Nr©   c                ó¦   •— | €E|j                  dt        |«      dkD  r|d   nd «      }t        |t        «      rt        j
                  }  ‰|d| i|¤ŽS )NÚ
fill_valuer   rd   )rÂ   Úlenr1   rh   r!   r­   )rd   r'   r+   r  ro   s       €rG   rp   z_patch_full.<locals>.patch   sQ   ø€ Øˆ=àŸ™ L¼SÀ»YÈº]°$°q²'ÐPTÓUˆJÜ˜*¤cÔ*ÜŸ
™
�Ù˜Ð5 UÐ5¨fÑ5Ð5rP   r&   rr   s   ` rG   Ú_patch_fullr  œ  s   ø€ ð  ö 6ð €LrP   ztorch.masked.meanc                ó   — ddddœd„}|S )zCManual masked mean: avoids sum/int_count Div type mismatch in ONNX.NF)r{   r‘   rd   c               óè   — |j                  «       }|j                  |d¬«      j                  d¬«      }| |z  j                  ||¬«      |r|n|j                  «       z  }|�|j	                  |«      S |S )NT©r{   r‘   ç      ð?©r«   )ri   r   ÚclampÚsqueezerg   )r³   r  r{   r‘   rd   Ú
mask_floatr¢   r‰   s           rG   rp   z!_patch_masked_mean.<locals>.patch¯  ss   € Ø—Z‘Z“\ˆ
Ø�N‰N˜s¨DˆNÓ1×7Ñ7¸CÐ7Ó@ˆØ˜*Ñ$×)Ñ)¨c¸7Ð)ÓCÉGÁqÐYZ×YbÑYbÓYdÑeˆØ#(Ð#4ˆv�y‰y˜ÓÐ@¸&Ð@rP   r&   rr   s     rG   Ú_patch_masked_meanr  «  s   € ð #'°¸Tô Að €LrP   ztorch.masked.varc                ó   — ddddœd„}|S )zBManual masked var: avoids sum/int_count Div type mismatch in ONNX.NFT)r{   r‘   Úunbiasedc               óJ  — |j                  «       }|j                  |d¬«      j                  d¬«      }| |z  j                  |d¬«      |z  }| |z
  j                  d«      |z  j                  ||¬«      }|r|dz
  n|}	|s|	j	                  «       }	||	j                  d¬«      z  S )NTr  r  r  r	   )ri   r   r  r”   r  )
r³   r  r{   r‘   r  r  r¢   r•   ÚvarÚdenoms
             rG   rp   z _patch_masked_var.<locals>.patch¼  s¦   € Ø—Z‘Z“\ˆ
Ø�N‰N˜s¨DˆNÓ1×7Ñ7¸CÐ7Ó@ˆØ˜
Ñ"×'Ñ'¨C¸Ð'Ó>ÀÑBˆØ˜‘×!Ñ! !Ó$ zÑ1×6Ñ6¸3ÈÐ6ÓPˆÙ%��S’¨1ˆÙØ—M‘M“OˆEØ�U—[‘[ S�[Ó)Ñ)Ð)rP   r&   rr   s     rG   Ú_patch_masked_varr  ¸  s   € ð #'°Àô *ð €LrP   ztorch.Tensor.masked_scatterc                ó   — d„ }|S )zPCumsum-gather-where strategy for masked_scatter (avoids ScatterND ORT failures).c                ón  — |j                  | «      }|j                  d«      }|j                  t        j                  «      j                  d«      dz
  j                  d¬«      }|j                  d«      |   }t        j                  ||| j                  d«      «      j                  | j                  «      S )Nr�   r   r   r  )	Ú	expand_asrª   rg   r!   r£   Úcumsumr  rÓ   rƒ   )r?   r  ÚsourceÚ	flat_maskÚ	positionsÚgathereds         rG   rp   z$_patch_masked_scatter.<locals>.patchÍ  sŒ   € Ø�~‰~˜dÓ#ˆØ—L‘L Ó$ˆ	Ø—\‘\¤%§+¡+Ó.×5Ñ5°aÓ8¸1Ñ<×CÑCÈÐCÓJˆ	Ø—>‘> "Ó% iÑ0ˆÜ�{‰{˜9 h°·±¸RÓ0@ÓA×IÑIÈ$Ï*É*ÓUÐUrP   r&   rr   s     rG   Ú_patch_masked_scatterr&  É  s   € òVð €LrP   z
torch.rollc                ó   ‡ — dˆ fd„	}|S )a  Replace `torch.roll(input, shifts, dims)` with explicit `narrow + cat` shifts.

    `torch.roll`'s torch.export lowering emits a `Shape(start, end)` op that can resolve to an
    empty INT64 result; the downstream `Slice` then has mismatched `axes` and `ends` lengths
    and ORT rejects the graph with `ShapeInferenceError` (seen in Gemma4-Unified Vision2Text,
    where roll is composed with an in-place scatter `[..., 0] = value`). The explicit form is
    bit-exact and traces to plain Slice + Concat nodes.
    c                óì  •— t        |t        «      rt        |t        «      r|f}|f}nMt        |t        t        f«      r-t        |t        t        f«      rt	        |«      t	        |«      k(  s
 ‰	| ||«      S | }t        ||«      D ]m  \  }}|j                  |«      }|dkD  r||z  nd}|dk(  rŒ)|j                  |||z
  |«      }|j                  |d||z
  «      }t        j                  ||g|¬«      }Œo |S )Nr   rË   )
r1   rh   rò   Úlistr  ÚzipÚsizeÚnarrowr!   rñ   )
r³   Úshiftsrí   r§   Úshiftr{   ÚlengthÚfrontÚbackro   s
            €rG   rp   z_patch_roll.<locals>.patchâ  sò   ø€ Ü�fœcÔ"¤z°$¼Ô'<Ø�YˆFØ�7‰DÜ˜V¤e¬T ]Ô3¼
À4Ì%ÔQUÈÔ8WÔ\_Ð`fÓ\gÔknÐosÓktÒ\tÙ˜E 6¨4Ó0Ð0àˆÜ˜f dÓ+ò 	4‰JˆE�3Ø—X‘X˜c“]ˆFØ&,¨q¢j�E˜F’N°aˆEØ˜ŠzØØ—J‘J˜s F¨U¡N°EÓ:ˆEØ—:‘:˜c 1 f¨u¡nÓ5ˆDÜ—)‘)˜U D˜M¨sÔ3‰Cð	4ð ˆ
rP   rS   r&   rr   s   ` rG   Ú_patch_rollr2  ×  s   ø€ õð$ €LrP   zHtorch.onnx._internal.exporter._core._prepare_exported_program_for_exportc                ó   ‡ — ˆ fd„}|S )aò  Run the FX node fixes immediately after the ONNX internal decomposition step.

    `torch.onnx.export` internally calls `run_decompositions` with the ONNX
    decomposition table, which can introduce new symbolic-guard nodes (e.g.
    `operator.le(sym_size, int_oo)`). These overflow during ONNX translation.
    Wrapping the prepare step lets us apply our FX fixes immediately after.

    <Tip warning={true}>

    This hooks `torch.onnx._internal.exporter._core._prepare_exported_program_for_export`,
    a private PyTorch API. It may break on PyTorch version upgrades. If it does,
    find the new entry point in `torch/onnx/_internal/exporter/_core.py`
    where `ExportedProgram.run_decompositions` is called and hook there instead.

    </Tip>
    c               óH   •—  ‰| |¬«      }t        d|j                  «       |S )N)Úregistryr"   )r   r9   )Úepr5  r‰   ro   s      €rG   rp   z(_patch_prepare_for_export.<locals>.patch  s$   ø€ Ù˜" xÔ0ˆÜ˜F F×$7Ñ$7Ô8ØˆrP   r&   rr   s   ` rG   Ú_patch_prepare_for_exportr7  ÿ  s   ø€ ô&ð
 €LrP   c                óv  — |j                   t        vryt        |j                  «      dk(  r| j                  j                  |«       yt        d„ |j                  D «       «      rG	  |j                   |j                  Ž }|j                  |«       | j                  j                  |«       yy# t        $ r Y yw xY w)u.  Erase or constant-fold comparison nodes involving symbolic infinities.

    torch.export emits guards like ``%le_3 = operator.le(sym_size, int_oo)`` where
    ``int_oo`` is a sympy ``IntInfinity`` object.  The ONNX translator tries to lower it
    to a C long and overflows.  Two cases handled:

    * No users â†’ erase the node outright (PyTorch DCE skips Python callables).
    * Any arg is a non-FX-Node constant (e.g. ``int_oo``) â†’ evaluate the comparison at
      graph-construction time, replace all uses with the Python bool result, and erase.
    Fr   Tc              3  óf   K  — | ])  }t        |t        j                  j                  «       –— Œ+ y ­wrS   )r1   r!   ÚfxÚNode)Ú.0Úas     rG   ú	<genexpr>z'_fix_dead_comparison.<locals>.<genexpr>6  s"   è ø€ Ò
?°Œz˜!œUŸX™XŸ]™]Ó+Ô+Ñ
?ùs   ‚/1)
ÚtargetÚ_COMPARISON_OPSr  ÚusersÚgraphÚ
erase_nodeÚanyr'   Ú	ExceptionÚreplace_all_uses_with)ÚgmÚnoder‰   s      rG   Ú_fix_dead_comparisonrI  $  sŸ   € ð ‡{�{œ/Ñ)ØÜ
ˆ4�:‰:ƒ˜!ÒØ
�‰×Ñ˜DÔ!Øä
Ñ
?°T·Y±YÔ
?Ô?ð	Ø �T—[‘[ $§)¡)Ð,ˆFð 	×"Ñ" 6Ô*Ø
�‰×Ñ˜DÔ!ØØøô ò 	Ùð	ús   Á%B, Â,	B8Â7B8c                óì   — |j                   t        j                  j                  j                  j
                  ury|j                  |j                  d   «       | j                  j                  |«       y)zHReplace alias(x) -> x to break the alias -> detach_ -> index_put_ chain.Fr   T)
r?  r!   ÚopsÚatenÚaliasÚdefaultrF  r'   rB  rC  ©rG  rH  s     rG   Ú
_fix_aliasrP  A  sR   € ð ‡{�{œ%Ÿ)™)Ÿ.™.×.Ñ.×6Ñ6Ñ6ØØ×Ñ˜tŸy™y¨™|Ô,Ø‡H�H×Ñ˜ÔØrP   c                óî  — |j                   t        j                  j                  j                  j
                  ury| j                  j                  |«      5  | j                  j                  t        j                  j                  j                  j
                  |j                  |j                  ¬«      }ddd«       |j                  «       | j                  j                  |«       y# 1 sw Y   Œ6xY w)z2Replace in-place detach_ with out-of-place detach.F©r'   r+   NT)r?  r!   rK  rL  Údetach_rN  rB  Úinserting_beforeÚcall_functionÚdetachr'   r+   rF  rC  ©rG  rH  Únews      rG   Ú_fix_detach_inplacerY  K  s¯   € ð ‡{�{œ%Ÿ)™)Ÿ.™.×0Ñ0×8Ñ8Ñ8ØØ	�‰×	"Ñ	" 4Ó	(ñ hØ�h‰h×$Ñ$¤U§Y¡Y§^¡^×%:Ñ%:×%BÑ%BÈÏÉÐ[_×[fÑ[fÐ$Ógˆ÷hà×Ñ˜sÔ#Ø‡H�H×Ñ˜ÔØ÷	hð húó   ÁAC+Ã+C4c                óî  — |j                   t        j                  j                  j                  j
                  ury| j                  j                  |«      5  | j                  j                  t        j                  j                  j                  j
                  |j                  |j                  ¬«      }ddd«       |j                  «       | j                  j                  |«       y# 1 sw Y   Œ6xY w)z8Replace in-place index_put_ with out-of-place index_put.FrR  NT)r?  r!   rK  rL  Ú
index_put_rN  rB  rT  rU  Ú	index_putr'   r+   rF  rC  rW  s      rG   Ú_fix_index_put_inplacer^  W  s¯   € ð ‡{�{œ%Ÿ)™)Ÿ.™.×3Ñ3×;Ñ;Ñ;ØØ	�‰×	"Ñ	" 4Ó	(ñ kØ�h‰h×$Ñ$¤U§Y¡Y§^¡^×%=Ñ%=×%EÑ%EÈDÏIÉIÐ^b×^iÑ^iÐ$Ójˆ÷kà×Ñ˜sÔ#Ø‡H�H×Ñ˜ÔØ÷	kð kúrZ  c                ó`   — |j                   t        vry| j                  j                  |«       y)zFErase assertion / shape-constraint nodes that have no ONNX equivalent.FT)r?  Ú_ASSERTION_OPSrB  rC  rO  s     rG   Ú_fix_assertionra  p  s(   € ð ‡{�{œ.Ñ(ØØ‡H�H×Ñ˜ÔØrP   c                ó  — |j                   t        j                  j                  j                  j
                  ury| j                  j                  |«      5  |j                  d   }|j                  d   }| j                  j                  t        j                  j                  j                  j                  |df¬«      }| j                  j                  t        j                  j                  j                  j                  |df¬«      }| j                  j                  t        j                  j                  j                  j
                  ||f¬«      }| j                  j                  t        j                  j                  j                  j                  |t        j                  f¬«      }| j                  j                  t        j                  j                  j                   j
                  ||f¬«      }| j                  j                  t        j                  j                  j"                  j$                  |||f¬«      }	ddd«       |j'                  	«       | j                  j)                  |«       y# 1 sw Y   Œ6xY w)z=Replace in-place fill_diagonal_ with out-of-place equivalent.Fr   r   ©r'   NT)r?  r!   rK  rL  Úfill_diagonal_rN  rB  rT  r'   rU  Úsym_sizerh   Úeyerg   rd   rj   Ú	full_likerÓ   r?   rF  rC  )
rG  rH  Ú
tensor_argr  ÚrowsÚcolsrf  Úeye_boolÚfill_tensorrX  s
             rG   Ú_fix_fill_diagonal_inplacerm  y  sÆ  € ð ‡{�{œ%Ÿ)™)Ÿ.™.×7Ñ7×?Ñ?Ñ?ØØ	�‰×	"Ñ	" 4Ó	(ñ 	jØ—Y‘Y˜q‘\ˆ
Ø—Y‘Y˜q‘\ˆ
à�x‰x×%Ñ%¤e§i¡i§n¡n×&=Ñ&=×&AÑ&AÈÐUVÈÐ%ÓXˆØ�x‰x×%Ñ%¤e§i¡i§n¡n×&=Ñ&=×&AÑ&AÈÐUVÈÐ%ÓXˆØ�h‰h×$Ñ$¤U§Y¡Y§^¡^×%7Ñ%7×%?Ñ%?ÀtÈTÀlÐ$ÓSˆØ—8‘8×)Ñ)¬%¯)©)¯.©.×*;Ñ*;×*AÑ*AÈÌeÏjÉjÐHYÐ)ÓZˆØ—h‘h×,Ñ,¬U¯Y©Y¯^©^×-EÑ-E×-MÑ-MÐU_ÐakÐTlÐ,ÓmˆØ�h‰h×$Ñ$¤U§Y¡Y§^¡^×%9Ñ%9×%>Ñ%>ÀhÐP[Ð]gÐEhÐ$Óiˆ÷	jð 	×Ñ˜sÔ#Ø‡H�H×Ñ˜ÔØ÷	jð 	jús   ÁG0I<É<Jc                óî  — |j                   t        j                  j                  j                  j
                  ury| j                  j                  |«      5  | j                  j                  t        j                  j                  j                  j
                  |j                  |j                  ¬«      }ddd«       |j                  «       | j                  j                  |«       y# 1 sw Y   Œ6xY w)z.Replace in-place triu_ with out-of-place triu.FrR  NT)r?  r!   rK  rL  Útriu_rN  rB  rT  rU  Útriur'   r+   rF  rC  rW  s      rG   Ú_fix_triu_inplacerq  �  s¯   € ð ‡{�{œ%Ÿ)™)Ÿ.™.×.Ñ.×6Ñ6Ñ6ØØ	�‰×	"Ñ	" 4Ó	(ñ fØ�h‰h×$Ñ$¤U§Y¡Y§^¡^×%8Ñ%8×%@Ñ%@ÀtÇyÁyÐY]×YdÑYdÐ$Óeˆ÷fà×Ñ˜sÔ#Ø‡H�H×Ñ˜ÔØ÷	fð fúrZ  c                óŒ  — |j                   t        j                  j                  j                  j
                  ury|j                  d   }t        |j                  «      dkD  r|j                  d   nd}t        |j                  «      dkD  r|j                  d   nd}| j                  j                  |«      5  | j                  j                  t        j                  j                  j                  j                  |||f¬«      }ddd«       |j                  «       | j                  j                  |«       y# 1 sw Y   Œ6xY w)	zMReplace aten.sort.stable with aten.sort.default (which has ONNX translation).Fr   r	   r�   é   rc  NT)r?  r!   rK  rL  ÚsortÚstabler'   r  rB  rT  rU  rN  rF  rC  )rG  rH  Úself_argr{   Ú
descendingrX  s         rG   Ú_fix_sort_stablerx  ™  sô   € ð ‡{�{œ%Ÿ)™)Ÿ.™.×-Ñ-×4Ñ4Ñ4ØØ�y‰y˜‰|€HÜ˜dŸi™i›.¨1Ò,ˆ$�)‰)�AŠ,°"€CÜ!$ T§Y¡Y£°!Ò!3�—‘˜1’¸€JØ	�‰×	"Ñ	" 4Ó	(ñ dØ�h‰h×$Ñ$¤U§Y¡Y§^¡^×%8Ñ%8×%@Ñ%@ÈÐRUÐWaÐGbÐ$Ócˆ÷dà×Ñ˜sÔ#Ø‡H�H×Ñ˜ÔØ÷	dð dús   Â8AD:Ä:Ec                ól  — |j                   t        j                  j                  j                  j
                  uryt        |j                  «      dk  s1t        |j                  d   t        j                  j                  «      sy| j                  j                  |«      5  | j                  j                  t        j                  j                  j                  j                  |j                  ¬«      }ddd«       |j                  «       | j                  j!                  |«       y# 1 sw Y   Œ6xY w)aµ  Rewrite remainder.Scalar to remainder.Tensor when the 'scalar' arg is actually a tensor.

    After decomposition the second operand of ``aten.remainder.Scalar`` can be a graph
    node (SymbolicTensor) rather than a Python scalar.  The ONNX torchlib translation for
    ``remainder.Scalar`` calls ``int()`` on it and crashes.  Rewriting to
    ``remainder.Tensor`` uses the two-tensor ONNX translation which handles this correctly.
    Fr	   r   rc  NT)r?  r!   rK  rL  Ú	remainderÚScalarr  r'   r1   r:  r;  rB  rT  rU  rf   rF  rC  rW  s      rG   Ú_fix_remainder_scalarr|  ¨  sÒ   € ð ‡{�{œ%Ÿ)™)Ÿ.™.×2Ñ2×9Ñ9Ñ9ØÜ
ˆ4�9‰9ƒ~˜Ò¤¨D¯I©I°a©L¼%¿(¹(¿-¹-Ô!HØØ	�‰×	"Ñ	" 4Ó	(ñ VØ�h‰h×$Ñ$¤U§Y¡Y§^¡^×%=Ñ%=×%DÑ%DÈ4Ï9É9Ð$ÓUˆ÷Và×Ñ˜sÔ#Ø‡H�H×Ñ˜ÔØ÷	Vð Vús   Â!AD*Ä*D3c                ó¬  — | j                   �7|j                   �+t        | j                   «      t        |j                   «      kD  ryt        |j                   «      t        | j                   «      z
  }t        | j                   |j                   |d «      D ])  \  }}	 t        |«      t        |«      }}|dk7  sŒ#||k7  sŒ) y y# t        t
        f$ r Y  yw xY w)u™  Static-shape check: does ``values.shape`` broadcast against ``self.shape``?

    Returns ``True`` only when every dim of ``values`` is statically known and either
    equals the corresponding (right-aligned) dim of ``self`` or is ``1``. Used to dispatch
    `_aten_index_put` between the broadcast and flat-gather paths â€” bailing on dynamic /
    unknown dims keeps us on the safe flat-gather fallback.
    NFr   T)rƒ   r  r*  rh   r4   Ú
ValueError)rÔ   r?   ÚoffsetÚv_dimÚs_dims        rG   Ú_values_broadcast_to_selfr‚  Â  s¼   € ð ‡|�|Ð˜tŸz™zÐ1´S¸¿¹Ó5FÌÈTÏZÉZËÒ5XØÜ�—‘‹_œs 6§<¡<Ó0Ñ0€FÜ˜FŸL™L¨$¯*©*°V°WÐ*=Ó>ò ‰ˆˆuð	Ü˜u›:¤s¨5£z�5ˆEð �A‹:˜% 5›.Ùðð øô	 œ:Ð&ò 	Úð	ús   ÂC Ã CÃCc                ó*  — |d   }|duxr3 t        t        |dd«      dd«      t        j                  j                  k(  }|st	        | |||«      S t        t        | j                  «      t        |j                  «      z
  «      D ]-  }t        j                  |t        j                  dg¬«      «      }Œ/ t        j                  |t        j                  | «      «      }t        || «      r@t        j                  |t        j                  | «      «      }t        j                  ||| «      S t        j                  |t        j                  dg¬«      «      }	t        j                   |	d¬«      }
t        j"                  |
t        j                  dg¬«      «      }t        j$                  t        j&                  |t        j                  d	g¬«      «      t        j                  dg¬«      «      }t        j                  |t        j                  dg¬«      «      }t        j(                  ||«      }t        j                  | t        j                  dg¬«      «      }t        j                  |	||«      }t        j                  |t        j                  | «      «      S )
uä  Bool-mask index_put with two paths; delegates non-bool-mask cases to torchlib.

    For `self[bool_mask] = values`, PyTorch supports two distinct shapes for ``values``:
    1. Broadcasts against ``self.shape`` (e.g. scalar `tensor[~mask] = 0`) â€” handled by
       `Expand(values, Shape(self)) + Where(mask, expanded, self)`.
    2. Equals ``bool_mask.sum()`` along its first dim, with remaining dims matching
       ``self`` (e.g. `inputs_embeds[image_mask] = image_features_flat`) â€” handled by
       the flat cumulative-count-Gather + Where trick.

    Path 1 is correct only when broadcast-compatibility can be statically verified â€” for
    dynamic shapes we fall through to path 2, which is also torchlib's default behaviour.
    r   Nr3   rd   r�   ©rÀ   é   ©rg   r   )ÚgetattrrÄ   ÚDataTyper   r   Úranger  rƒ   ÚopÚ	UnsqueezeÚConstantÚExpandÚShaper‚  ÚWhereÚReshapeÚCastÚCumSumÚClipÚSubÚGather)r?   rÕ   rÔ   Ú
accumulateÚ	bool_maskÚis_boolÚ_Úexpanded_maskÚexpanded_valuesr#  Úflat_mask_intÚcsr$  Úflat_valuesr%  Ú	flat_selfr‰   s                    rG   Ú_aten_index_putr   ×  sØ  € ð$ ˜‘
€Ià˜ÐÒs¤'¬'°)¸VÀTÓ*JÈGÐUYÓ"ZÔ^e×^nÑ^n×^sÑ^sÑ"sð ñ Ü˜d G¨V°ZÓ@Ð@Ü”3�t—z‘z“?¤S¨¯©Ó%9Ñ9Ó:ò JˆÜ—L‘L ¬B¯K©KÀBÀ4Ô,HÓI‰	ðJä—I‘I˜i¬¯©°$«Ó8€MÜ  ¨Ô.ÜŸ)™) F¬B¯H©H°T«NÓ;ˆÜ�x‰x˜ ¸Ó=Ð=Ü—
‘
˜=¬"¯+©+À"ÀÔ*FÓG€IÜ—G‘G˜I¨!Ô,€MÜ	�‰�=¤"§+¡+¸!¸Ô"=Ó	>€BÜ—‘œŸ™˜r¤2§;¡;¸1¸#Ô#>Ó?ÄÇÁÐYZÐX[ÔA\Ó]€IÜ—*‘*˜V¤R§[¡[¸R¸DÔ%AÓB€KÜ�y‰y˜ iÓ0€HÜ—
‘
˜4¤§¡¸¸Ô!=Ó>€IÜ�X‰X�i ¨9Ó5€FÜ�:‰:�fœbŸh™h t›nÓ-Ð-rP   c                óô  — t        j                  dg¬«      }t        j                  t        j                  | d¬«      t        j                  dg¬«      «      }t        j                  ||«      }|dkD  r+t        j
                  |t        j                  |g¬«      «      }t        j                  | |t        j                  ddg¬«      d¬«      }t        j                  |t        j                  dg¬«      d¬«      S )a  ONNX implementation of `torch.bincount`: count occurrences of non-negative ints.

    No native ONNX op. We use `OneHot(self, depth=max+1, values=[0,1])` then `ReduceSum`
    along the input axis. Weights are unused (splinter's only caller passes none).
    r   r„  r   )Úkeepdimsr�   ©Úaxis)rŠ  rŒ  r‹  Ú	ReduceMaxÚAddÚMaxÚOneHotÚ	ReduceSum)r?   ÚweightsÚ	minlengthÚoner·   ÚdepthÚone_hots          rG   Ú_aten_bincountr¯     s­   € ô �+‰+ ! Ô
%€CÜ�l‰lœ2Ÿ<™<¨°qÔ9¼2¿;¹;ÐSTÐRUÔ;VÓW€GÜ�F‰F�7˜CÓ €EØ�1‚}Ü—‘�uœbŸk™k°i°[ÔAÓBˆÜ�i‰i˜˜e¤R§[¡[¸QÀ¸FÔ%CÈ"ÔM€GÜ�<‰<˜¤§¡¸¸Ô!<ÀqÔIÐIrP   c           	     óš  — |j                   d   }t        |t        «      st        d«      ‚t	        j
                  |d¬«      }t	        j                  dg¬«      }t	        j                  dg¬«      }g }	|}
t        |«      D ]¶  }t	        j                  |g¬«      }t	        j                  |dz   g¬«      }t	        j                  ||||«      }t	        j                  | |
||«      }t	        j                  t	        j                  ||||«      |«      }|	j                  t	        j                  ||«      «       |}
Œ¸ t	        j                  |	ddiŽS )uZ  ONNX implementation of `aten._grouped_mm.default`.

    `_grouped_mm(mat_a: (M, K), mat_b: (G, K, N), offs: (G,))` computes `out[r] =
    mat_a[r] @ mat_b[group(r)]` where rows are sorted by group and `offs` holds the
    cumulative end index per group.

    Per-group `Slice + MatMul + Concat`. `G` (number of experts) is static for any
    concrete model, so unroll at translation time: emit one `Slice + MatMul` triple
    per group and a final `Concat`. Avoids the `(M, K, N)` materialisation a naive
    `weight[group_idx]` gather would emit â€” peak memory is `O(MÂ·N + max(n_g)Â·K + KÂ·N)`.
    r   zW_aten_grouped_mm: number of experts (mat_b.shape[0]) must be static at translation timer…  r†  r„  r   r¤  )rƒ   r1   rh   r~  rŠ  r‘  rŒ  r‰  ÚSliceÚSqueezeÚappendÚMatMulÚConcat)Úmat_aÚmat_bÚoffsÚbiasrº   ÚGÚoffs_i64Úaxes_0Úzero_1drV   Úprev_endÚgÚg_loÚg_hiÚendÚa_gÚw_gs                    rG   Ú_aten_grouped_mmrÅ    s  € ð 	�‰�A‰€AÜ�aœÔÜÐrÓsÐsä�w‰w�t Ô"€HÜ�[‰[ Q CÔ(€FÜ�k‰k a SÔ)€Gà€GØ€HÜ�1‹Xò ˆÜ�{‰{ q cÔ*ˆÜ�{‰{ q¨1¡u gÔ.ˆÜ�h‰h�x  t¨VÓ4ˆÜ�h‰h�u˜h¨¨VÓ4ˆÜ�j‰jœŸ™ %¨¨t°VÓ<¸fÓEˆØ�‰”r—y‘y  cÓ*Ô+Ø‰ðô �9‰9�gÐ& AÑ&Ð&rP   c           	     ó˜  — |�€+t        j                  | t        j                  dg¬«      «      }t        j                  |t        j                  dg¬«      «      }t	        |t
        «      rt        j                  d|g¬«      }nmt        j                  t        j                  |d¬«      t        j                  dg¬«      «      }t        j                  t        j                  dg¬«      |d¬«      }t        j                  t        j                  ||«      t        j                  dg¬«      «      S t        | j                  «      }||z   |z  }	t        j                  | t        j                  |	dz   g¬«      «      }t	        |t
        «      r(dg|dz   z  }
||
|	dz   <   t        j                  |
¬«      }n’t        j                  t        j                  |d¬«      t        j                  dg¬«      «      }t        j                  t        j                  dg|	dz   z  ¬«      |t        j                  dg||	z
  dz
  z  ¬«      d¬«      }t        j                  ||«      }t        j                  t        j                  | d|	¬«      t        j                  dg¬«      t        j                  | |	dz   ¬	«      d¬«      }t        j                  ||«      S )
a‰  ONNX implementation of `aten.repeat_interleave.self_int`.

    Torchlib's translation raises on `dim is None` and broadcasts incorrectly for the
    1-D + symbolic-repeats case (its tile shape is `[r, 1]` instead of `[1, r]`). We
    always rewrite: flatten when `dim is None`, then `Unsqueeze + Tile + Reshape` along
    the chosen axis. Handles both Python-int and 0-D-tensor `repeats`.
    r�   r„  r   r…  r†  r   r£  )ÚstartrÂ  )rÇ  )rŠ  r�  rŒ  r‹  r1   rh   r‘  rµ  ÚTiler  rƒ   rŽ  )r?   Úrepeatsr{   Úoutput_sizerµ   ÚunsqÚ
tile_shapeÚrÚ	self_rankÚpos_dimÚtilesÚtiledÚfinal_shapes                rG   Ú _aten_repeat_interleave_self_intrÓ  1  s	  € ð �{Ü�z‰z˜$¤§¡¸°tÔ <Ó=ˆÜ�|‰|˜D¤"§+¡+¸!¸Ô"=Ó>ˆÜ�gœsÔ#ÜŸ™°°G°Ô=‰Jä—
‘
œ2Ÿ7™7 7¨qÔ1´2·;±;È2È$Ô3OÓPˆAÜŸ™¤2§;¡;¸1¸#Ô#>ÀÈÔJˆJÜ�z‰zœ"Ÿ'™' $¨
Ó3´R·[±[ÈRÈDÔ5QÓRÐRä�D—J‘J“€IØ�Y‰ )Ñ+€GÜ�<‰<˜œbŸk™k°gÀ±k°]ÔCÓD€DÜ�'œ3ÔØ��y 1‘}Ñ%ˆØ$ˆˆg˜‰kÑÜ—[‘[¨EÔ2‰
ä�J‰J”r—w‘w˜w¨1Ô-¬r¯{©{ÀrÀdÔ/KÓLˆÜ—Y‘YÜ�K‰K A 3¨'°A©+Ñ#6Ô7ØÜ�K‰K A 3¨)°gÑ*=ÀÑ*AÑ#BÔCØô	
ˆ
ô �G‰G�D˜*Ó%€EÜ—)‘)Ü
�‰�˜Q GÔ,Ü
�‰ ˜tÔ$Ü
�‰�˜W q™[Ô)Øô	€Kô �:‰:�e˜[Ó)Ð)rP   c           
     óL  — t        j                  t        j                  t        j                  t        j                  | «      t        j                  |«      «      «      t        j
                  t        j                  | |«      t        j                  j                  j                  ¬«      «      }t        | d«      r| j                  j                  n|j                  j                  }t        j                  t        j                  | |«      t        j
                  ||¬«      «      S )u2  Correct floor division (toward -inf) for signed integer SymInts.

    Torchlib's `operator_floordiv` translation only handles positive operands (plain `Div`,
    which truncates). For signed ints â€” including SymInt shape arithmetic â€” apply the
    offset correction `floor(a/b) = trunc(a/b) - (sign(a) != sign(b) AND a mod b != 0)`,
    matching `aten_floor_divide`. Without this, the Python ceil-div idiom `-(-x // y)`
    produces `1 + trunc((y - 1 - x) / y)` instead of `ceil(x / y)`, which silently breaks
    any shape arithmetic that crosses zero.
    r†  rd   )rŠ  ÚAndÚNotÚEqualÚSignr‘  ÚModrÄ   rˆ  r   rÁ   Úhasattrrd   r”  ÚDiv)r?   Úotherr  rd   s       rG   Ú_operator_floordivrÝ  \  s±   € ô �V‰VÜ
�‰Œr�x‰xœŸ™ ›¤r§w¡w¨u£~Ó6Ó7Ü
�‰”—‘�t˜UÓ#¬×(8Ñ(8×(=Ñ(=×(CÑ(CÔDó€Fô !(¨¨gÔ 6ˆD�J‰J×Ò¸E¿K¹K×<MÑ<M€EÜ�6‰6”"—&‘&˜˜uÓ%¤r§w¡w¨v¸%Ô'@ÓAÐArP   c                ó¾  — | j                   t        j                  j                  k(  rŠt	        |t
        t        t        f«      rt        |«      n"t        |j                  j                  «       «      }|rt        j                  | |«      S t        j                  | t        j                  |«      «      S t        j                  || «      }t        j                  ||| «      S )u“  ONNX implementation of `aten.masked_fill.{Scalar,Tensor}`.

    Upstream torchlib lowers this to `Where(mask, value, self)`. ORT's CPU EP has no
    `Where(16)` kernel for BOOL inputs, so when `self` is BOOL we rewrite the op using
    boolean primitives: `masked_fill(self, mask, True)` â†’ `self | mask`,
    `masked_fill(self, mask, False)` â†’ `self & ~mask`. Non-bool `self` keeps the default.
    )rd   rÄ   rˆ  r   r1   rj   rh   ri   Úconst_valueÚnumpyrŠ  ÚOrrÕ  rÖ  ÚCastLiker�  )r?   r  rÁ   Ú	fill_trueÚ
value_casts        rG   Ú_aten_masked_fillrå  n  sœ   € ð ‡z�z”W×%Ñ%×*Ñ*Ò*Ü#-¨e´d¼CÄÐ5GÔ#H”D˜”KÌdÐSX×SdÑSd×SjÑSjÓSlÓNmˆ	ÙÜ—5‘5˜˜tÓ$Ð$Ü�v‰v�dœBŸF™F 4›LÓ)Ð)Ü—‘˜U DÓ)€JÜ�8‰8�D˜* dÓ+Ð+rP   zdict[Any, Any]r=   c                óØ   — t        | j                  «       «      D ]N  }|j                  dk(  sŒt        j                  dt        j
                  j                  d«      |j                  d<   ŒP y)zASet sorted=1 on TopK nodes (ORT CUDA EP rejects TopK without it).ÚTopKÚsortedr   N)r)  Ú	all_nodesÚop_typerÄ   ÚAttrÚAttributeTypeÚINTÚ
attributes)Ú
graph_likeÚir_nodes     rG   Ú_fix_ir_topk_sortedrñ  ›  sW   € ä˜
×,Ñ,Ó.Ó/ò `ˆØ�?‰?˜fÓ$Ü+2¯<©<¸Ä'×BWÑBW×B[ÑB[Ð]^Ó+_ˆG×Ñ˜xÒ(ñ`rP   c                ó®   — | j                   j                  g| j                   j                  j                  «       ¢}t        D ]  }|D ]
  } ||«       Œ Œ y)zNApply each `(graph_like) -> None` IR fix to the main graph and every function.N)r@   rB  Ú	functionsrÔ   Ú	_IR_FIXES)rE   ÚgraphsÚfixrB  s       rG   r>   r>   §  sU   € à× Ñ ×&Ñ&ÐO¨×);Ñ);×)EÑ)E×)LÑ)LÓ)NÐO€FÜò ˆØò 	ˆEÙ��Jñ	ñrP   )rB   ú	list[str]rC   r÷  rH   ztuple[list[str], list[str]])rÛ   Ústr)rG  ztorch.fx.GraphModulerH  ztorch.fx.NoderH   rj   )rÔ   r   r?   r   rH   rj   )F)
r?   r   rÕ   zSequence[INT64 | BOOL | None]rÔ   r   r–  rj   rH   r   r€   )r?   r   r«  rh   rH   r   rq   )r¶  r   r·  r   r¸  r   rH   r   )rï  zonnx_ir.GraphrH   ÚNone)rE   r   rH   rù  )~rL   Ú
__future__r   r;   rZ   ÚoperatorÚcollections.abcr   r   Ú
contextlibr   Útypingr   r   rà  rÅ   Úutilsr
   Úutils.import_utilsr   r   Úconfigsr   Úexporter_dynamor   r   r   r   r   r   r   r!   Útorch.exportr   Ú
torch.onnxr   Ú r   rÄ   Ú+onnxscript.function_libs.torch_lib.ops.corer   Úonnxscript.onnx_opsetr   rŠ  Úmodeling_utilsr   r   r   r   Ú
get_loggerÚ__file__Úloggerr    r5   r8   rs   r|   r�   r™   r¥   r½   rÇ   rÜ   rá   rä   rê   rø   r  r	  r  r  r  r&  r2  r7  Ú	frozensetÚleÚltÚgeÚgtÚeqÚner@  rI  rP  rY  r^  r]   r`  ÚupdaterK  rL  Ú_assert_asyncrN  ÚmsgÚ_assert_scalarÚ_assert_tensor_metadataÚsym_constrain_range_for_sizera  rm  rq  rx  r|  r‚  r   r¯  rÅ  rÓ  rÝ  rå  r=   Ú__annotations__Úbincountr]  Ú_grouped_mmÚtransformersÚgrouped_mm_fallbackÚrepeat_interleaveÚself_intÚmasked_fillr{  rf   Úfloordivrñ  rô  r>   r&   rP   rG   ú<module>r"     sÖ  ðò õ. #ã Û Û ß 4Ý %ß %ã å ß LÝ Ý +÷÷ ñ ÔÛÝ,Ý&å ñ ÔÛÝJÝ3áÝ0áÔ ßRÑRð 
ˆ×	Ñ	˜HÓ	%€ô0�>ô 0ðn ñ)ó ð)ó0'ñ  �˜Ó&ñó 'ðñ( �Ð)Ð+CÓDñ
ó Eð
ñ �ÐIÓJñó Kðñ  �Ð2Ó3ñ	ó 4ð	ñ �Ð(Ó)ñó *ðñ �˜Ó&ñó 'ðñ: �ÐNÓOñó Pðó&ñ, �˜Ð(=Ó>ñ9ó ?ð9ñ �˜Ð(=Ó>ñ9ó ?ð9ñ �˜Ð%7Ó8ñ
ó 9ð
ñ �Ð)Ó*ñó +ðñ" �Ð)Ó*ñó +ðñ" �Ð,Ó-ñó .ðñ* �˜Ó%ñó &ðñ �Ð+Ó,ñ	ó -ð	ñ �Ð*Ó+ñó ,ðñ  �Ð5Ó6ñ
ó 7ð
ñ �˜Ó%ñó &ðñN �ÐbÓcñó dðñB ˜XŸ[™[¨(¯+©+°x·{±{ÀHÇKÁKÐQY×Q\ÑQ\Ð^f×^iÑ^iÐjÓk€ñ �fÓòó ðñ8 �fÓòó ðñ �fÓòó ðñ �fÓòó ðñ “€ÙÔØ×Ñà�I‰I�N‰N×(Ñ(×0Ñ0Ø�I‰I�N‰N×(Ñ(×,Ñ,Ø�I‰I�N‰N×)Ñ)×1Ñ1Ø�I‰I�N‰N×2Ñ2×:Ñ:Ø�I‰I�N‰N×7Ñ7×?Ñ?ð	
ôñ �fÓòó ðñ �fÓòó ðñ& �fÓòó ðñ �fÓòó ðñ �fÓòó ðó2ð2 ð	&.Ø
ð&.à*ð&.ð ð&.ð ð	&.ð
 ó&.ôRJô'óD(*òVBò$,ð" +-Ð ˜Ó ,ÙÕØ×"Ñ"à�I‰I�N‰N×#Ñ#×+Ñ+¨^Ø�I‰I�N‰N×$Ñ$×,Ñ,¨oØ�I‰I�N‰N×&Ñ&×.Ñ.Ð0@Ø�I‰I×"Ñ"×6Ñ6×>Ñ>Ð@PØ�I‰I�N‰N×,Ñ,×5Ñ5Ð7WØ�I‰I�N‰N×&Ñ&×-Ñ-Ð/@Ø�I‰I�N‰N×&Ñ&×-Ñ-Ð/@Ø×ÑÐ1ð		
ôó4`ð ð€	ô
rP   