+
    UV-j+P  ã                   ó†   € ^ RI Ht ]P                  P	                  4       tR tR
R ltRR ltRR lt	RR lt
R tR tR	 tR# )é    Nc                óZ  € V P                   w  r4rV\        P                  ! \        P                  ! V\        P                  R7      WQ,          ,          4      P                  \        P                  4      p\        P                  ! \        P                  ! V\        P                  R7      Wb,          ,          4      P                  \        P                  4      p\        P                  ! V^ V^,
          4      p\        P                  ! V^ V^,
          4      pV RRV3,          RRRV3,          # )z:Pure-MLX nearest-neighbor interpolation (no Metal kernel).©ÚdtypeºNNN)ÚshapeÚmxÚfloorÚarangeÚfloat32ÚastypeÚint32Úclip)	ÚxÚout_hÚout_wÚ
batch_sizeÚchannelsÚin_hÚin_wÚy_idxÚx_idxs	   &&&      Úg/Volumes/fast/ai/experiments/ui-tars-smoke/.venv/lib/python3.14/site-packages/mlx_vlm/models/kernels.pyÚ_nearest_interpolate_mlxr      sË   € à'(§w¡wÑ$€J˜$ô �HŠH”R—Y’Y˜u¬B¯J©JÔ7¸4½<ÕHÓI×PÑPÜ
�‰ó€Eô �HŠH”R—Y’Y˜u¬B¯J©JÔ7¸4½<ÕHÓI×PÑPÜ
�‰ó€Eô �GŠG�E˜1˜d Q�hÓ'€EÜ�GŠG�E˜1˜d Q�hÓ'€EàˆQ��5ˆ[�>˜!˜Q  5˜.Õ)Ð)ó    c                ó^  € V P                   w  r4rVVe   Vw  rxMUVeG   \        V\        \        34      '       d   T;ršMVw  rš\        WY,          4      \        Wj,          4      r‡M\	        R4      h\
        '       g   \        WV4      # \        P                  ! W4WVWx.\        P                  R7      pV P                  R
4      pV P                  pV\        P                  8w  d    VP                  \        P                  4      pRp\        P                  P                  RRR.R.VR7      p\!        W‡4      pV! WË.W‡W4,          3VW4,          V,          V,          3.\        P                  .R	7      pV^ ,          P                  W4Wx4      pV\        P                  8w  d   VP                  V4      pV# )zI
Nearest neighbor interpolation that exactly matches PyTorch's behavior.
ú-Either size or scale_factor must be specifiedr   a  
        uint x_out = thread_position_in_grid.x;
        uint y_out = thread_position_in_grid.y;
        uint bc_idx = thread_position_in_grid.z;

        int batch_size = dims[0];
        int channels = dims[1];
        int in_h = dims[2];
        int in_w = dims[3];
        int out_h = dims[4];
        int out_w = dims[5];

        if (x_out >= (uint)out_w || y_out >= (uint)out_h || bc_idx >= (uint)(batch_size * channels))
            return;

        int c = bc_idx % channels;
        int b = bc_idx / channels;

        // PyTorch's coordinate calculation for nearest neighbor
        // This matches: torch.nn.functional.interpolate(..., mode='nearest')
        float scale_h = float(in_h) / float(out_h);
        float scale_w = float(in_w) / float(out_w);

        // PyTorch uses floor for nearest neighbor coordinate mapping
        int y_in = int(floor(float(y_out) * scale_h));
        int x_in = int(floor(float(x_out) * scale_w));

        // Clamp to bounds
        y_in = max(0, min(y_in, in_h - 1));
        x_in = max(0, min(x_in, in_w - 1));

        int input_offset = ((b * channels + c) * in_h + y_in) * in_w + x_in;
        int output_offset = ((b * channels + c) * out_h + y_out) * out_w + x_out;

        output[output_offset] = input[input_offset];
    Únearest_interpolationÚinputÚdimsÚoutput©ÚnameÚinput_namesÚoutput_namesÚsource©ÚinputsÚgridÚthreadgroupÚoutput_shapesÚoutput_dtypeséÿÿÿÿ)r   Ú
isinstanceÚintÚfloatÚ
ValueErrorÚ
_HAS_METALr   r   Úarrayr   Úreshaper   r   r   ÚfastÚmetal_kernelÚget_optimal_threadgroup)r   ÚsizeÚscale_factorr   r   r   r   r   r   Úscale_hÚscale_wr   Úx_flatÚinput_dtyper%   Úkernelr)   ÚoutputsÚresults   &&&                r   Únearest_interpolater@      s…  € ð ()§w¡wÑ$€J˜$àÒØ‰ˆˆuØ	Ò	!Ü�l¤S¬% L×1Ò1Ø ,Ð,ˆG�gà+ÑˆGÜ˜4�>Ó*¬C°µÓ,?‰uäÐHÓIÐIç‹:Ü'¨°%Ó8Ð8ô �8Š8�Z¨4°uÐDÌBÏHÉHÔU€Dð �Y‰Y�r‹]€FØ—'‘'€KØ”b—j‘jÔ Ø—‘œrŸz™zÓ*ˆð#€FôJ �W‰W×!Ñ!Ø$Ø˜fÐ%Ø�ZØð	 "ó €Fô *¨%Ó7€KÙØˆ~Ø˜JÕ1Ð2ØØ"Õ-°Õ5¸Õ=Ð?Ð@Ü—z‘z�lô€Gð �Q�Z×Ñ 
°eÓC€FØ”b—j‘jÔ Ø—‘˜{Ó+ˆà€Mr   c                ó¶  € \         P                  ! V 4      pW",          pW2,          pVR,           V,          VR,           V,          ,
          R,           pW,          RV,          V,          ,
          RV,          V,          ,           RV,          ,
          p\         P                  ! VR8*  V\         P                  ! VR8  V\         P                  ! V 4      4      4      # )a7  Cubic convolution kernel.

PyTorch's ``F.interpolate(mode="bicubic")`` uses ``a=-0.75`` (ATen
``upsample_bicubic2d``) for the non-antialiased path, but its antialiased
path matches Pillow, which uses ``a=-0.5`` (Keys' cubic). The caller selects
the coefficient per axis based on whether antialiasing is active.
ç       @g      @ç      ð?g      @g       @g      @)r   ÚabsÚwhereÚ
zeros_like)ÚtÚaÚatÚat2Úat3Úw1Úw2s   &&     r   Ú_cubic_weightrN   q   s™   € ô 
�Š�‹€BØ
�'€CØ
�(€CØ
ˆc�'�S�˜A �G s�?Õ	*¨SÕ	0€BØ	
��3˜•7˜S•=Õ	  3¨¥7¨R¥<Õ	/°#¸µ'Õ	9€BÜ�8Š8�B˜#‘I˜r¤2§8¢8¨B°©H°b¼"¿-º-ÈÓ:JÓ#KÓLÐLr   c                ó”  a€ V P                   w  rVrxV P                  p	V P                  \        P                  4      p W,          p
W(,          pV'       d”   V^8”  d�   V^8”  d†   \        P
                  ! V\        P                  R7      V^,
          ,          V^,
          ,          p\        P
                  ! V\        P                  R7      V^,
          ,          V^,
          ,          pM„\        P
                  ! V\        P                  R7      R,           V,          V,          R,
          p\        P
                  ! V\        P                  R7      R,           V,          V,          R,
          pS'       d   V
R8  d
   RV
,          MRpS'       d   VR8  d
   RV,          MRpRV,          pRV,          pV3R lpV! WÇVV4      w  ppV! WØVV4      w  ppV RRVP                  R4      R3,          pVP                   ^,          pVP                   ^,          pVP                  WVVVV4      p\        P                  ! VVR	,          ,          ^R7      pVRRRVP                  R4      3,          pVP                  WVWV4      p\        P                  ! VVR
,          ,          ^R7      pV	\        P                  8w  d   VP                  V	4      pV# )z1Pure-MLX bicubic interpolation (no Metal kernel).r   g      à?rC   rB   c                 ó€  <€ \         P                  ! W,
          4      P                  \         P                  4      ^,           p\	        ^V,          ^,           4      p\         P
                  ! V\         P                  R7      pVR,          VR,          ,           pV R,          VP                  \         P                  4      ,
          p\        W‚,          S'       d   RMR4      p	V^ 8¬  Wq8  ,          p
Wš,          p	\         P                  ! V^ V^,
          4      pV	\         P                  ! V	R	RR7      R,           ,          p	Wy3# )
é   r   T)ÚaxisÚkeepdimsg:Œ0âŽyE>©r   N)Nr   g      à¿ç      è¿r,   )
r   r	   r   r   r.   r
   r   rN   r   Úsum)ÚcoordsÚin_sizeÚfsÚsupportÚstartÚn_tapsÚoffsetsÚpixÚdistÚwÚmaskÚ	antialiass   &&&&       €r   Ú_weights_1dÚ-_bicubic_interpolate_mlx.<locals>._weights_1d™   sà   ø€ Ü—’˜Õ)Ó*×1Ñ1´"·(±(Ó;¸aÕ?ˆÜ�Q˜•[ 1•_Ó%ˆÜ—)’)˜F¬"¯(©(Ô3ˆØ�G�n˜w wÕ/Õ/ˆØ�g� §¡¬B¯J©JÓ!7Õ7ˆô ˜$�)¯Y¡T¸EÓBˆà�q‘˜S™]Õ+ˆØ�HˆÜ�gŠg�c˜1˜g¨�kÓ*ˆà”—’˜ ¨TÔ2°TÕ9Õ:ˆØˆvˆr   r   )rR   r,   )NNr   r   N)NNNr   r   )r   r   r   r   r   r
   r3   rV   )r   r   r   Úalign_cornersrb   ÚBÚCr   r   r<   r9   r:   Úy_outÚx_outÚfs_hÚfs_wÚ	support_hÚ	support_wrc   Úpix_yÚwyÚpix_xÚwxÚ
gathered_yÚthÚtwÚtmpÚ
gathered_xr?   s   &&&&f                        r   Ú_bicubic_interpolate_mlxrw   �   s!  ø€ à—w‘wÑ€Aˆ$Ø—'‘'€KØ	�‰”—‘Ó€Aà�l€GØ�l€G÷ ˜ œ u¨q¤yÜ—	’	˜%¤r§z¡zÔ2°d¸QµhÕ?À5È1Å9ÕMˆÜ—	’	˜%¤r§z¡zÔ2°d¸QµhÕ?À5È1Å9ÕM‰ä—’˜5¬¯
©
Ô3°cÕ9¸UÕBÀTÕIÈCÕOˆÜ—’˜5¬¯
©
Ô3°cÕ9¸UÕBÀTÕIÈCÕOˆ÷  )¨W°s¬]ˆC�'ŽMÀ€Dß(¨W°s¬]ˆC�'ŽMÀ€DØ�d•
€IØ�d•
€Iõñ" ˜E¨¨yÓ9�I€Eˆ2Ù˜E¨¨yÓ9�I€Eˆ2ð �1�a˜Ÿ™ rÓ*¨AÐ-Õ.€JØ	�‰�Q�€BØ	�‰�Q�€BØ×#Ñ# A¨%°°TÓ:€Jä
�&Š&�˜bÐ!7Õ8Õ8¸qÔ
A€Cð �Q˜˜1˜eŸm™m¨BÓ/Ð/Õ0€JØ×#Ñ# A¨%¸Ó;€JÜ�VŠV�J Ð$:Õ!;Õ;À!ÔD€Fà”b—j‘jÔ Ø—‘˜{Ó+ˆØ€Mr   c           	     ó~  € V P                   w  rVrxVe   Vw  ršW—,          W¨,          rËMUVeG   \        V\        \        34      '       d   T;r¼MVw  r¼\        W{,          4      \        WŒ,          4      r©M\	        R4      h\
        '       g   \        W	W£V4      # RpV'       d   RMRpV'       d   VR8  d   RV,          pMRpV'       d   VR8  d   RV,          pMRp\        P                  ! TTV'       d   RMRVVVV.\        P                  R7      p\        P                  ! WVWxWš.\        P                  R7      pV P                  R4      pV P                  pV\        P                  8w  d    VP                  \        P                  4      pRpRp\        P                  P                  R. ROR	.VVR
7      p\!        W©4      pV! VVV.W©WV,          3VWV,          V	,          V
,          3.\        P                  .R7      pV^ ,          P                  WVWš4      pV\        P                  8w  d   VP                  V4      pV# )aY  
Bicubic interpolation using MLX's built-in interpolate function.

Args:
    x: MLX tensor of shape [B, C, H, W]
    size: Tuple of (out_h, out_w) or None
    scale_factor: Float or tuple of (scale_h, scale_w) or None
    align_corners: Whether to align corners
    antialias: Whether to apply antialiasing

Returns:
    Interpolated MLX tensor
r   rB   rC   g        r   aó  
        // Cubic convolution kernel. PyTorch's non-antialiased bicubic uses
        // a=-0.75 (ATen upsample_bicubic2d); its antialiased path matches
        // Pillow, which uses a=-0.5 (Keys' cubic).
        float cubic_kernel_a(float x, float a) {
            float absx = fabs(x);
            float absx2 = absx * absx;
            float absx3 = absx2 * absx;
            if (absx <= 1.0f) {
                return (a + 2.0f) * absx3 - (a + 3.0f) * absx2 + 1.0f;
            } else if (absx < 2.0f) {
                return a * absx3 - 5.0f * a * absx2 + 8.0f * a * absx - 4.0f * a;
            }
            return 0.0f;
        }

        float cubic_kernel(float x) {
            return cubic_kernel_a(x, -0.75f);
        }

        // Antialiased bicubic kernel - widens the support for downsampling and
        // uses Pillow's a=-0.5 to match PyTorch's antialiased path.
        float cubic_kernel_antialias(float x, float scale) {
            return cubic_kernel_a(x / scale, -0.5f);
        }
    aH  
        // Get thread position
        uint x_out = thread_position_in_grid.x;
        uint y_out = thread_position_in_grid.y;
        uint bc_idx = thread_position_in_grid.z;

        // Extract dimensions
        int batch_size = dims[0];
        int channels = dims[1];
        int in_h = dims[2];
        int in_w = dims[3];
        int out_h = dims[4];
        int out_w = dims[5];

        // Extract parameters
        float scale_h = params[0];
        float scale_w = params[1];
        bool align_corners = params[2] > 0.5f;
        bool use_antialias = params[3] > 0.5f;
        float filter_scale_h = params[4];
        float filter_scale_w = params[5];
        float support = params[6];

        // Check bounds
        if (x_out >= (uint)out_w || y_out >= (uint)out_h || bc_idx >= (uint)(batch_size * channels))
            return;

        // Calculate batch and channel indices
        int c = bc_idx % channels;
        int b = bc_idx / channels;

        // Calculate input coordinates
        float x_in, y_in;

        if (align_corners && out_w > 1 && out_h > 1) {
            x_in = float(x_out) * (in_w - 1) / (out_w - 1);
            y_in = float(y_out) * (in_h - 1) / (out_h - 1);
        } else {
            // PyTorch's default coordinate mapping
            x_in = ((float(x_out) + 0.5f) / float(out_w)) * float(in_w) - 0.5f;
            y_in = ((float(y_out) + 0.5f) / float(out_h)) * float(in_h) - 0.5f;
        }

        // Calculate the support region based on antialiasing
        float support_h = use_antialias ? support * filter_scale_h : support;
        float support_w = use_antialias ? support * filter_scale_w : support;

        // Calculate the range of input pixels to sample
        int y_start = int(floor(y_in - support_h)) + 1;
        int y_end = int(floor(y_in + support_h)) + 1;
        int x_start = int(floor(x_in - support_w)) + 1;
        int x_end = int(floor(x_in + support_w)) + 1;

        // Clamp to valid range
        y_start = max(0, y_start);
        y_end = min(in_h, y_end);
        x_start = max(0, x_start);
        x_end = min(in_w, x_end);

        // Perform bicubic interpolation with antialiasing
        float result = 0.0f;
        float weight_sum = 0.0f;

        for (int y_pos = y_start; y_pos < y_end; y_pos++) {
            float dy = float(y_pos) - y_in;
            float wy = use_antialias ?
                cubic_kernel_antialias(dy, filter_scale_h) :
                cubic_kernel(dy);

            for (int x_pos = x_start; x_pos < x_end; x_pos++) {
                float dx = float(x_pos) - x_in;
                float wx = use_antialias ?
                    cubic_kernel_antialias(dx, filter_scale_w) :
                    cubic_kernel(dx);

                float weight = wy * wx;

                // Calculate input tensor offset
                int input_offset = ((b * channels + c) * in_h + y_pos) * in_w + x_pos;

                // Add weighted contribution
                result += input[input_offset] * weight;
                weight_sum += weight;
            }
        }

        // Normalize by weight sum
        if (weight_sum > 1e-8f) {
            result /= weight_sum;
        }

        // Calculate output tensor offset
        int output_offset = ((b * channels + c) * out_h + y_out) * out_w + x_out;

        // Assign the result to output
        output[output_offset] = result;
    Úbicubic_interpolation_antialiasr    )r"   r#   r$   r%   Úheaderr&   r,   )r   r   Úparams)r   r-   r.   r/   r0   r1   rw   r   r2   r   r   r3   r   r   r4   r5   r6   )r   r7   r8   re   rb   r   r   r   r   r   r   r9   r:   rZ   Úantialias_flagÚfilter_scale_hÚfilter_scale_wr{   r   r;   r<   rz   r%   r=   r)   r>   r?   s   &&&&&                      r   Úbicubic_interpolater   À   s  € ð" ()§w¡wÑ$€J˜$ð ÒØ‰ˆØ �<¨­‘Ø	Ò	!Ü�l¤S¬% L×1Ò1Ø ,Ð,ˆG�gà+ÑˆGÜ˜4�>Ó*¬C°µÓ,?‰uäÐHÓIÐIç‹:Ü'¨°%È	ÓRÐRð €G÷
 &‘S¨3€N÷ �W˜s”]Ø˜w�‰àˆç�W˜s”]Ø˜w�‰àˆô �XŠXàØß ‰C cØØØØð	
ô �j‰jô€Fô �8Š8�Z¨4°uÐDÌBÏHÉHÔU€Dð �Y‰Y�r‹]€Fð —'‘'€KØ”b—j‘jÔ Ø—‘œrŸz™zÓ*ˆð€Fð8`€FôF �W‰W×!Ñ!Ø.Ú/Ø�ZØØð "ó €Fô *¨%Ó7€KÙØ˜˜fÐ%Ø˜JÕ1Ð2ØØ"Õ-°Õ5¸Õ=Ð?Ð@Ü—z‘z�lô€Gð �Q�Z×Ñ 
°eÓC€FØ”b—j‘jÔ Ø—‘˜{Ó+ˆà€Mr   c                ó:  a aaaaaa€ S P                   w  ooooVP                   w  poopVR,          ^,           S,          ^,
          ^,          pVR,          ^,           S,          ^,
          ^,          p\        P                  ! V4      P                  \        P                  4      p\        P                  ! V4      P                  \        P                  4      pV^,           pV^,           pVP                  \        P
                  4      V,
          VP                  \        P
                  4      V,
          ,          R,          p	W5P                  \        P
                  4      ,
          VP                  \        P
                  4      V,
          ,          R,          p
VP                  \        P
                  4      V,
          WFP                  \        P
                  4      ,
          ,          R,          pW5P                  \        P
                  4      ,
          WFP                  \        P
                  4      ,
          ,          R,          pVVVVVVV 3R lpW�! We4      ,          W­! Wg4      ,          ,           W½! W…4      ,          ,           WÍ! W‡4      ,          ,           pV# )u€   Pure-MLX bilinear grid sample (no Metal kernel).

x: (B, H, W, C)  â€” channel-last
grid: (B, gN, gM, 2) â€” normalised [-1, 1]
c                 óÎ  <€ V ^ 8¬  V S8  ,          V^ 8¬  ,          VS8  ,          p\         P                  ! V ^ S^,
          4      p\         P                  ! V^ S^,
          4      pVS,          V,           P                  S	R4      pSP                  S	SS,          S
4      p\         P                  ! S	4      R,          pWgV3,          pVP                  S	SSS
4      pW‚R,          ,          # )r   r,   rT   ©.N)r   r   r3   r
   )ÚyyÚxxÚvalidÚyy_cÚxx_cÚidxr;   Úb_idxÚvalsrf   rg   ÚHÚWÚgMÚgNr   s   &&       €€€€€€€r   Ú_gatherÚ!_grid_sample_mlx.<locals>._gatherÁ  sÃ   ø€ Ø�q‘˜R !™VÕ$¨¨a©Õ0°B¸±FÕ;ˆÜ�wŠw�r˜1˜a !�eÓ$ˆÜ�wŠw�r˜1˜a !�eÓ$ˆà�a�x˜$�×'Ñ'¨¨2Ó.ˆØ—‘˜1˜a !�e QÓ'ˆä—	’	˜!“˜WÕ%ˆØ˜S�jÕ!ˆØ�|‰|˜A˜r 2 qÓ)ˆØ˜IÕ&Õ&Ð&r   ).r   ).rQ   r‚   )r   r   r	   r   r   r   )r   r(   Ú_ÚixÚiyÚix0Úiy0Úix1Úiy1ÚwaÚwbÚwcÚwdr�   Úoutrf   rg   r‹   rŒ   r�   rŽ   s   f&             @@@@@@r   Ú_grid_sample_mlxr�   ©  sÐ  þ€ ð —‘�J€A€qˆ!ˆQØ—:‘:�L€A€rˆ2ˆqð ��<˜!Õ˜qÕ
  1Õ
$¨Õ	)€BØ��<˜!Õ˜qÕ
  1Õ
$¨Õ	)€Bä
�(Š(�2‹,×
Ñ
œbŸh™hÓ
'€CÜ
�(Š(�2‹,×
Ñ
œbŸh™hÓ
'€CØ
��'€CØ
��'€Cð �:‰:”b—j‘jÓ! BÕ&¨3¯:©:´b·j±jÓ+AÀBÕ+FÕ
GÈÕ	S€BØ—
‘
œ2Ÿ:™:Ó&Õ&¨3¯:©:´b·j±jÓ+AÀBÕ+FÕ
GÈÕ	S€BØ�:‰:”b—j‘jÓ! BÕ&¨2·
±
¼2¿:¹:Ó0FÕ+FÕ
GÈÕ	S€BØ—
‘
œ2Ÿ:™:Ó&Õ&¨2·
±
¼2¿:¹:Ó0FÕ+FÕ
GÈÕ	S€B÷'ó 'ð 	ˆW�SÓÕØ
ˆw�sÓ Õ
 õ	!à
ˆw�sÓ Õ
 õ	!ð ˆw�sÓ Õ
 õ	!ð ð €Jr   c                óú  € V P                   ^8X  g   Q R4       hVP                   ^8X  g   Q R4       hV P                  w  p r4VP                  w  r5rgW%Wd3pV^8X  g   Q R4       h\        '       g   \        W4      # Rp	\        P
                  P                  RRR.R.V	R	7      p
V
! W.R
V P                  3.V.V P                  .\        P                  ! \        P                  ! V4      4      ^^3RR7      pV^ ,          # )z¹
Grid sample using MLX's built-in interpolate function.
Args:
    x: MLX tensor of shape [B, C, H, W]
    grid: MLX tensor of shape [B, gN, gM, 2]

Returns:
    Interpolated MLX tensor
z`x` must be 4D.z`grid` must be 4D.z"Last dim of `grid` must be size 2.a¿  
        uint elem = thread_position_in_grid.x;
        int H = x_shape[1];
        int W = x_shape[2];
        int C = x_shape[3];
        int gH = grid_shape[1];
        int gW = grid_shape[2];

        int w_stride = C;
        int h_stride = W * w_stride;
        int b_stride = H * h_stride;

        uint grid_idx = elem / C * 2;
        float ix = ((grid[grid_idx] + 1) * W - 1) / 2;
        float iy = ((grid[grid_idx + 1] + 1) * H - 1) / 2;

        int ix_nw = floor(ix);
        int iy_nw = floor(iy);

        int ix_ne = ix_nw + 1;
        int iy_ne = iy_nw;

        int ix_sw = ix_nw;
        int iy_sw = iy_nw + 1;

        int ix_se = ix_nw + 1;
        int iy_se = iy_nw + 1;

        T nw = (ix_se - ix)    * (iy_se - iy);
        T ne = (ix    - ix_sw) * (iy_sw - iy);
        T sw = (ix_ne - ix)    * (iy    - iy_ne);
        T se = (ix    - ix_nw) * (iy    - iy_nw);

        int batch_idx = elem / C / gH / gW * b_stride;
        int channel_idx = elem % C;
        int base_idx = batch_idx + channel_idx;

        T I_nw = x[base_idx + iy_nw * h_stride + ix_nw * w_stride];
        T I_ne = x[base_idx + iy_ne * h_stride + ix_ne * w_stride];
        T I_sw = x[base_idx + iy_sw * h_stride + ix_sw * w_stride];
        T I_se = x[base_idx + iy_se * h_stride + ix_se * w_stride];

        I_nw = iy_nw >= 0 && iy_nw <= H - 1 && ix_nw >= 0 && ix_nw <= W - 1 ? I_nw : 0;
        I_ne = iy_ne >= 0 && iy_ne <= H - 1 && ix_ne >= 0 && ix_ne <= W - 1 ? I_ne : 0;
        I_sw = iy_sw >= 0 && iy_sw <= H - 1 && ix_sw >= 0 && ix_sw <= W - 1 ? I_sw : 0;
        I_se = iy_se >= 0 && iy_se <= H - 1 && ix_se >= 0 && ix_se <= W - 1 ? I_se : 0;

        out[elem] = nw * I_nw + ne * I_ne + sw * I_sw + se * I_se;
    Úgrid_sampler   r(   rœ   r!   ÚT)r'   Útemplater*   r+   r(   r)   )é   rQ   rQ   )
Úndimr   r1   r�   r   r4   r5   r   Úprodr2   )r   r(   rf   r‘   rg   rŽ   r�   ÚDÚ	out_shaper%   r=   r>   s   &&          r   rŸ   rŸ   ×  s  € ð �6‰6�QŒ;Ð)Ð)Ó)ˆ;Ø�9‰9˜Œ>Ð/Ð/Ó/ˆ>à—‘�J€A€qˆ!Ø—:‘:�L€Aˆ2Ø˜�€Ià�Œ6Ð7Ð7Ó7ˆ6ç‹:Ü Ó(Ð(ð0€Fôd �W‰W×!Ñ!ØØ˜&�MØ�WØð	 "ó €Fñ ØˆyØ˜Ÿ™�.Ð!Ø �kØ—w‘w�iÜ�gŠg”b—h’h˜yÓ)Ó*¨A¨qÐ1Øô€Gð �1�:Ðr   c                 ó   € R pR pRp \        W04      p\        W14      p^VP                  4       ^,
          ,          pWu8”  d
   V^,          p^VP                  4       ^,
          ,          pW†8”  d
   V^,          pWx,          V8”  d   Wx8¼  d   V^,          pK  V^,          pK)  \        ^V4      p\        ^V4      pWx^3#   \         d    Tu # i ; i)i   )é    r¨   rQ   )ÚminÚ
bit_lengthÚmaxÚ	Exception)	r   r   ÚMAX_THREADS_PER_GROUPÚMAX_THREADS_PER_DIMÚdefault_threadgroupÚ	max_widthÚ
max_heightÚwidthÚheights	   &&       r   r6   r6   2  sß   € ð
 !ÐØÐð &Ðð#äÐ+Ó3ˆ	ÜÐ,Ó4ˆ
ð �i×*Ñ*Ó,¨qÕ0Õ1ˆØÔØ˜Q•JˆEà�z×,Ñ,Ó.°Õ2Õ3ˆØÔØ˜q•[ˆFð �nÐ4Ô4àŒØ �
’à 1�’ô �A�u“ˆÜ�Q˜“ˆà˜qÐ!Ð!øäô #à"Ò"ð#ús   ˆB4B= Â=CÃC)NN)rU   )FF)NNFF)Úmlx.coreÚcorer   ÚmetalÚis_availabler1   r   r@   rN   rw   r   r�   rŸ   r6   © r   r   Ú<module>r¹      sK   ðÝ à�X‰X×"Ñ"Ó$€
ò*ô"WôtMô <ô~fòR+ò\Xôv)#r   