§
    +�’j&²  ã                  óè  — d dl mZ d dlmZ d dlmZ d dlZd dlZd dl	m
Z
 d dlmZ d dlmZmZ dd	lmZmZmZmZmZ  ej        e¦  «        ZdZd„Zd[d„Zd\d„Zd\d„Zd\d„Zd\d„Zd\d„Zd\d„Zd\d„Z d\d„Z!dZ"dZ#	 d]d^d#„Z$d_d(„Z%d`d,„Z&dadbd1„Z'dcd3„Z(ddd7„Z)ded:„Z*dfd;„Z+dgd=„Z,	 	 	 	 	 dhdidC„Z-djdD„Z.dkdG„Z/	 	 	 	 	 dhdidH„Z0	 	 	 	 	 dldidJ„Z1	 	 	 	 	 dldidK„Z2djdL„Z3dmdN„Z4dndR„Z5dodT„Z6dpdW„Z7 G dX„ dYe¦  «        Z8dS )qé    )Úannotations)ÚCallable)ÚEnumN)Úpairwise_distances)ÚTensor)Úis_torchdynamo_compilingÚloggingé   )Ú_convert_to_batch_tensorÚ_convert_to_float_tensorÚ_convert_to_tensorÚnormalize_embeddingsÚto_scipy_cooÚar   ÚbÚreturnútuple[Tensor, Tensor]c                óš   — | j         r|j         s| |                     ¦   «         fS |j         r| j         s|                      ¦   «         |fS | |fS )aW  
    Converts the dense tensor to sparse COO if exactly one of the two inputs is sparse, so that mixed inputs can
    reuse the all-sparse computations. The lone dense operand in such a mix typically still holds mostly zeros
    (e.g. sparse embeddings encoded with ``convert_to_sparse_tensor=False``), making the conversion cheap, whereas
    densifying the sparse operand would allocate a second full-size dense tensor.

    Args:
        a (Tensor): The first tensor.
        b (Tensor): The second tensor.

    Returns:
        tuple[Tensor, Tensor]: The two tensors, using the same layout.
    )Ú	is_sparseÚ	to_sparse©r   r   s     úSC:\Projects\DSCons\.venv\Lib\site-packages\sentence_transformers\util\similarity.pyÚ_match_layoutsr      sY   € ð 	„{ð  ˜1œ;ð  Ø�!—+’+‘-”-ÐÐØ„{ð  ˜1œ;ð  Ø�{Š{‰}Œ}˜aÐÐØˆaˆ4€Kó    c                ó"   — t          | |¦  «        S )á  
    Computes the cosine similarity between two tensors.

    Args:
        a (Union[list, np.ndarray, Tensor]): The first tensor.
        b (Union[list, np.ndarray, Tensor]): The second tensor.

    Returns:
        Tensor: Matrix with res[i][j] = cos_sim(a[i], b[j])
    )Úcos_simr   s     r   Úpytorch_cos_simr   -   s   € õ �1�a‰=Œ=Ðr   úlist | np.ndarray | Tensorc                óð   — t          | ¦  «        } t          |¦  «        }t          | ¦  «        }t          |¦  «        }t          j        ||                     dd¦  «        ¦  «                             ¦   «         S )r   r   r
   )r   r   ÚtorchÚmmÚ	transposeÚto_dense©r   r   Úa_normÚb_norms       r   r   r   ;   sf   € õ 	! Ñ#Ô#€AÝ  Ñ#Ô#€Aå! !Ñ$Ô$€FÝ! !Ñ$Ô$€FÝŒ8�F˜F×,Ò,¨Q°Ñ2Ô2Ñ3Ô3×<Ò<Ñ>Ô>Ð>r   c                ód  — t          | ¦  «        } t          |¦  «        }| j        s|j        rIt          | ¦  «        }t          |¦  «        }||z                       d¬¦  «                             ¦   «         S t          t          | ¦  «        t          |¦  «        ¦  «                             ¦   «         S )a  
    Computes the pairwise cosine similarity cos_sim(a[i], b[i]).

    Args:
        a (Union[list, np.ndarray, Tensor]): The first tensor.
        b (Union[list, np.ndarray, Tensor]): The second tensor.

    Returns:
        Tensor: Vector with res[i] = cos_sim(a[i], b[i])
    éÿÿÿÿ©Údim)r   r   r   Úsumr$   Úpairwise_dot_scorer%   s       r   Úpairwise_cos_simr.   N   s¥   € õ 	! Ñ#Ô#€AÝ  Ñ#Ô#€Að 	„{ð _�a”kð _Ý% aÑ(Ô(ˆÝ% aÑ(Ô(ˆØ˜‘×$Ò$¨Ð$Ñ,Ô,×5Ò5Ñ7Ô7Ð7å!Õ"6°qÑ"9Ô"9Õ;OÐPQÑ;RÔ;RÑSÔS×\Ò\Ñ^Ô^Ð^r   c                ó´   — t          | ¦  «        } t          |¦  «        }t          j        | |                     dd¦  «        ¦  «                             ¦   «         S )a  
    Computes the dot-product dot_prod(a[i], b[j]) for all i and j.

    Args:
        a (Union[list, np.ndarray, Tensor]): The first tensor.
        b (Union[list, np.ndarray, Tensor]): The second tensor.

    Returns:
        Tensor: Matrix with res[i][j] = dot_prod(a[i], b[j])
    r   r
   )r   r!   r"   r#   r$   r   s     r   Ú	dot_scorer0   e   sJ   € õ 	! Ñ#Ô#€AÝ  Ñ#Ô#€AåŒ8�A�q—{’{ 1 aÑ(Ô(Ñ)Ô)×2Ò2Ñ4Ô4Ð4r   c                ó”   — t          | ¦  «        } t          |¦  «        }| |z                       d¬¦  «                             ¦   «         S )a  
    Computes the pairwise dot-product dot_prod(a[i], b[i]).

    Args:
        a (Union[list, np.ndarray, Tensor]): The first tensor.
        b (Union[list, np.ndarray, Tensor]): The second tensor.

    Returns:
        Tensor: Vector with res[i] = dot_prod(a[i], b[i])
    r)   r*   )r   r,   r$   r   s     r   r-   r-   v   sB   € õ 	! Ñ#Ô#€AÝ  Ñ#Ô#€Aà�‰E�;Š;˜2ˆ;ÑÔ×'Ò'Ñ)Ô)Ð)r   c                ó
  — t          | ¦  «        } t          |¦  «        }| j        s|j        r®t                               d¦  «         t	          | |¦  «        \  } }t          | ¦  «        }t          |¦  «        }t          ||d¬¦  «        }t          j        | ¦  «         	                    ¦   «          
                    | j        ¦  «                             ¦   «         S t          j        | |d¬¦  «                             ¦   «          S )a€  
    Computes the manhattan similarity (i.e., negative distance) between two tensors.
    Handles sparse tensors without converting to dense when possible.

    Args:
        a (Union[list, np.ndarray, Tensor]): The first tensor.
        b (Union[list, np.ndarray, Tensor]): The second tensor.

    Returns:
        Tensor: Matrix with res[i][j] = -manhattan_distance(a[i], b[j])
    z8Using scipy for sparse Manhattan similarity computation.Ú	manhattan)Úmetricg      ð?©Úp)r   r   ÚloggerÚwarning_oncer   r   r   r!   Ú
from_numpyÚfloatÚtoÚdevicer$   Úcdist)r   r   Úa_cooÚb_cooÚdists        r   Úmanhattan_simrA   ‡   sæ   € õ 	! Ñ#Ô#€AÝ  Ñ#Ô#€Aà„{ð 
4�a”kð 
4Ý×ÒÐVÑWÔWÐWå˜a Ñ#Ô#‰ˆˆ1Ý˜Q‘”ˆÝ˜Q‘”ˆÝ! %¨°{ÐCÑCÔCˆÝÔ  Ñ&Ô&×,Ò,Ñ.Ô.×1Ò1°!´(Ñ;Ô;×DÒDÑFÔFÐFõ ”˜A˜q CÐ(Ñ(Ô(×1Ò1Ñ3Ô3Ð3Ð3r   c                óà   — t          | ¦  «        } t          |¦  «        }t          | |¦  «        \  } }t          j        t          j        | |z
  ¦  «        d¬¦  «                             ¦   «          S )a<  
    Computes the manhattan similarity (i.e., negative distance) between pairs of tensors.

    Args:
        a (Union[list, np.ndarray, Tensor]): The first tensor.
        b (Union[list, np.ndarray, Tensor]): The second tensor.

    Returns:
        Tensor: Vector with res[i] = -manhattan_distance(a[i], b[i])
    r)   r*   )r   r   r!   r,   Úabsr$   r   s     r   Úpairwise_manhattan_simrD   £   sc   € õ 	! Ñ#Ô#€AÝ  Ñ#Ô#€AÝ˜!˜QÑÔ�D€A€qåŒI•e”i  A¡Ñ&Ô&¨BÐ/Ñ/Ô/×8Ò8Ñ:Ô:Ð:Ð:r   c                óØ  — t          | ¦  «        } t          |¦  «        }| j        s|j        �r&t          | |¦  «        \  } }t          j                             | | z  d¬¦  «                             ¦   «                              d¦  «        }t          j                             ||z  d¬¦  «                             ¦   «                              d¦  «        }t          j        | | 	                    ¦   «         ¦  «                             ¦   «         }|d|z  z
  |z   }t          j
        |d¬¦  «        }t          j        |¦  «                             ¦   «          S t          j        | |d¬¦  «         S )	a€  
    Computes the euclidean similarity (i.e., negative distance) between two tensors.
    Handles sparse tensors without converting to dense when possible.

    Args:
        a (Union[list, np.ndarray, Tensor]): The first tensor.
        b (Union[list, np.ndarray, Tensor]): The second tensor.

    Returns:
        Tensor: Matrix with res[i][j] = -euclidean_distance(a[i], b[j])
    r
   r*   r   é   g        ©Úming       @r5   )r   r   r   r!   Úsparser,   r$   Ú	unsqueezeÚmatmulÚtÚclampÚsqrtr=   )r   r   Ú	a_norm_sqÚ	b_norm_sqÚdot_productÚsquared_dists         r   Úeuclidean_simrS   µ   s=  € õ 	! Ñ#Ô#€AÝ  Ñ#Ô#€Aà„{ð )�a”kñ )Ý˜a Ñ#Ô#‰ˆˆ1Ý”L×$Ò$ Q¨¡U°Ð$Ñ2Ô2×;Ò;Ñ=Ô=×GÒGÈÑJÔJˆ	Ý”L×$Ò$ Q¨¡U°Ð$Ñ2Ô2×;Ò;Ñ=Ô=×GÒGÈÑJÔJˆ	Ý”l 1 a§c¢c¡e¤eÑ,Ô,×5Ò5Ñ7Ô7ˆð ! 1 {¡?Ñ2°YÑ>ˆõ ”{ <°SÐ9Ñ9Ô9ˆå”
˜<Ñ(Ô(×1Ò1Ñ3Ô3Ð3Ð3å”˜A˜q CÐ(Ñ(Ô(Ð(Ð(r   c                óæ   — t          | ¦  «        } t          |¦  «        }t          | |¦  «        \  } }t          j        t          j        | |z
  dz  d¬¦  «        ¦  «                             ¦   «          S )a:  
    Computes the euclidean distance (i.e., negative distance) between pairs of tensors.

    Args:
        a (Union[list, np.ndarray, Tensor]): The first tensor.
        b (Union[list, np.ndarray, Tensor]): The second tensor.

    Returns:
        Tensor: Vector with res[i] = -euclidean_distance(a[i], b[i])
    rF   r)   r*   )r   r   r!   rN   r,   r$   r   s     r   Úpairwise_euclidean_simrU   Õ   sg   € õ 	! Ñ#Ô#€AÝ  Ñ#Ô#€AÝ˜!˜QÑÔ�D€A€qåŒJ•u”y ! a¡%¨A¡°2Ð6Ñ6Ô6Ñ7Ô7×@Ò@ÑBÔBÐBÐBr   i áõg    eÍÍÁÚitem_widthsú	list[int]Úper_item_tokenÚintÚelement_budgetÚper_item_fixedúlist[tuple[int, int]]c                ó  — g }d}d}t          | ¦  «        D ]P\  }}t          ||¦  «        }	||z
  dz   }
|
dk    r+||	z  |z   |
z  |k    r|                     ||f¦  «         |}|}ŒN|	}ŒQ|                     |t          | ¦  «        f¦  «         |S )a@  Greedily pack items into ``(start, end)`` chunks whose padded cost of
    ``(per_item_token * chunk_width + per_item_fixed) * chunk_size`` elements stays under
    ``element_budget``, with a floor of one item per chunk. The cost uses each chunk's local max
    width, matching the per-chunk padding in :func:`maxsim`, so one long outlier only sizes its own
    chunk.

    The item is a document in :func:`maxsim` and in
    :func:`~sentence_transformers.multi_vector_encoder.scoring.xtr_scores` (which packs the flattened
    ``Q * N`` document axis), and a query-document pair in :func:`maxsim_pairwise`.

    ``per_item_token`` must count every allocation that scales with an item's padded width: the
    scoring intermediate and, where the caller materializes them, the padded embeddings themselves.
    Omitting the embeddings overshoots the budget several-fold whenever the query side is small, since
    the padding then dominates. ``per_item_fixed`` covers what grows with the chunk size but not with
    the item width, such as the padded queries in :func:`maxsim_pairwise`.
    r   r
   )Ú	enumerateÚmaxÚappendÚlen)rV   rX   rZ   r[   ÚrangesÚstartÚwidthÚindexÚ
item_widthÚcandidate_widthÚcounts              r   Ú_chunk_rangesri   ï   s¼   € ð& %'€FØ€EØ€EÝ& {Ñ3Ô3ð $ð $ÑˆˆzÝ˜e ZÑ0Ô0ˆØ˜‘ Ñ!ˆØ�1Š9ˆ9˜.¨?Ñ:¸^ÑKÈuÑTÐWeÒeÐeØ�MŠM˜5 %˜.Ñ)Ô)Ð)ØˆEØˆEˆEà#ˆEˆEØ
‡M‚M�5�#˜kÑ*Ô*Ð+Ñ,Ô,Ð,Ø€Mr   Ú
embeddingsÚmaskúTensor | Noneú0tuple[list | np.ndarray | Tensor, Tensor | None]c                ó8  — t          | t          j        ¦  «        r!| j        dk    rt          j        | d¦  «        } n:t          | t
          ¦  «        r!| j        dk    r|                      d¦  «        } n| |fS |� |j        dk    r|                     d¦  «        }| |fS )NrF   r   r
   )Ú
isinstanceÚnpÚndarrayÚndimÚexpand_dimsr   rJ   )rj   rk   s     r   Ú_batch_singular_inputrt     s¡   € õ
 �*�bœjÑ)Ô)ð  ¨j¬oÀÒ.BÐ.BÝ”^ J°Ñ2Ô2ˆ
ˆ
Ý	�J¥Ñ	'Ô	'ð  ¨J¬O¸qÒ,@Ð,@Ø×)Ò)¨!Ñ,Ô,ˆ
ˆ
à˜4ÐÐØÐ˜DœI¨šN˜NØ�~Š~˜aÑ Ô ˆØ�tÐÐr   ú!Tensor | np.ndarray | list | NoneÚnameÚstrc                ó˜  — t          |t          t          f¦  «        r6t          j        j        j                             d„ |D ¦   «         d¬¦  «        }nit          |t          j	        ¦  «        rt          |¦  «        }n?|�=t          |t          ¦  «        s(t          d|› dt          |¦  «        j        › d�¦  «        ‚t          | |¦  «        S )z¹Shared input front door for one side of a scoring call: masks become a single tensor (a list
    of per-item masks is padded to the batch), and a bare 2D input batches as a single item.c                ó,   — g | ]}t          |¦  «        ‘ŒS © ©r   ©Ú.0Úms     r   ú
<listcomp>z&_canonicalize_side.<locals>.<listcomp>*  s!   € Ð/TÐ/TÐ/TÈ!Õ0BÀ1Ñ0EÔ0EÐ/TÐ/TÐ/Tr   T)Úbatch_firstNú`zA` must be a tensor, an ndarray, or a list of per-item masks, not ú.)ro   ÚlistÚtupler!   ÚnnÚutilsÚrnnÚpad_sequencerp   rq   r   r   Ú	TypeErrorÚtypeÚ__name__rt   )rj   rk   rv   s      r   Ú_canonicalize_siderŒ   "  sÊ   € õ �$��u˜Ñ&Ô&ð 
ÝŒxŒ~Ô!×.Ò.Ð/TÐ/TÈtÐ/TÑ/TÔ/TÐbfÐ.ÑgÔgˆˆÝ	�D�"œ*Ñ	%Ô	%ð 
Ý! $Ñ'Ô'ˆˆØ	Ð	¥*¨Tµ6Ñ":Ô":Ð	ÝØm�ÐmÐmÕW[Ð\`ÑWaÔWaÔWjÐmÐmÐmñ
ô 
ð 	
õ ! ¨TÑ2Ô2Ð2r   Frd   ÚtruncateÚboolc           	     ó®   — | j         d         |k    r| S |r| j         d         |k    r| dd|…f         S t          d|› d| j         d         › d|› d�¦  «        ‚)a  Match a mask's token span to the padded embeddings. The chunk loops pass ``truncate=True``,
    since a batch-wide mask legitimately spans more than one chunk's local padding. Caller-facing
    inputs must match exactly: a mismatched mask is a construction bug, not a layout to guess at.r)   .Nr�   z	` covers z( tokens, but the padded embeddings have r‚   )ÚshapeÚ
ValueError)rk   rd   rv   r�   s       r   Ú_fit_mask_widthr’   4  sv   € ð „z�"„~˜ÒÐØˆØð !�D”J˜r”N UÒ*Ð*Ø�C˜˜%˜�KÔ Ð Ý
Ðh˜ÐhÐh¨¬
°2¬ÐhÐhÐ`eÐhÐhÐhÑ
iÔ
iÐir   útorch.device | Nonec                ó¼   — t          | t          ¦  «        r| j        S t          | t          ¦  «        r*| r(t          | d         t          ¦  «        r| d         j        S dS )zOThe device multi-vector embeddings live on, or None for numpy and empty inputs.r   N)ro   r   r<   rƒ   ©rj   s    r   Ú_embeddings_devicer–   ?  s^   € å�*�fÑ%Ô%ð !ØÔ Ð Ý�*�dÑ#Ô#ð $¨
ð $µzÀ*ÈQÄ-ÕQWÑ7XÔ7Xð $Ø˜!Œ}Ô#Ð#Øˆ4r   r<   útorch.deviceútuple[Tensor, Tensor | None]c                óŽ   — | j         |k    r|                      |¦  «        } |� |j         |k    r|                     |¦  «        }| |fS )zÓMove one side's padded embeddings and mask onto the scoring device. The mask is checked
    separately, since a caller can hand in a cpu mask alongside gpu embeddings and the masked_fill
    kernel rejects that.)r<   r;   )rj   rk   r<   s      r   Ú
_to_devicerš   H  sO   € ð Ô˜FÒ"Ð"Ø—]’] 6Ñ*Ô*ˆ
ØÐ˜DœK¨6Ò1Ð1Ø�wŠw�v‰ŒˆØ�tÐÐr   rc   Úendc                óÄ   — |�
|||…         nd}t          | ||…         |¦  «        \  }}t          |||¦  «        \  }}|�t          ||j        d         |d¬¦  «        }||fS )a
  Pad one chunk of a side onto the scoring device, with its mask narrowed to the chunk's local
    width. Padding the whole batch upfront instead would let one long outlier size the full
    ``(batch, max_len, dim)`` tensor: multi-GB of mostly padding on ragged input.Nr
   T)r�   )Ú_pad_multi_vector_inputsrš   r’   r�   )rj   rk   rc   r›   r<   rv   Ú
chunk_maskÚchunks           r   Ú
_pad_chunkr    S  s{   € ð %)Ð$4��e˜C�i”�¸$€JÝ0°¸EÀ#¸IÔ1FÈ
ÑSÔSÑ€Eˆ:Ý" 5¨*°fÑ=Ô=Ñ€Eˆ:ØÐå$ Z°´¸Q´ÀÐPTÐUÑUÔUˆ
Ø�*ÐÐr   c                óz   — t          | t          ¦  «        s| j        d         S t          d„ | D ¦   «         d¦  «        S )zLThe trailing embedding dimension, read without materializing a padded batch.r)   c              3  ó^   K  — | ](}t          |¦  «        ¯t          |d          ¦  «        V — Œ)dS )r   N©ra   ©r}   Úitems     r   ú	<genexpr>z!_embedding_dim.<locals>.<genexpr>k  s7   è è € ÐBÐB $½¸D¹	¼	ÐB•�T˜!”W‘”ÐBÐBÐBÐBÐBÐBr   r
   )ro   rƒ   r�   Únextr•   s    r   Ú_embedding_dimr¨   g  sA   € å�j¥$Ñ'Ô'ð $ØÔ Ô#Ð#ÝÐBÐB¨*ÐBÑBÔBÀAÑFÔFÐFr   Úa_maskc                ó�  — |�<|                      ¦   «                              d¬¦  «                             d¬¦  «        S t          | t          ¦  «        rt          j        d„ | D ¦   «         ¦  «        S t          t          | ¦  «        ¦  «                              ¦   «                              d¬¦  «                             d¬¦  «        S )z¯Per-item count of real query tokens for MeanMaxSim scoring: the mask sum when a mask is
    given, the item lengths for ragged lists, and the non-zero rows for padded tensors.Nr)   r*   r
   rG   c                óH   — g | ]}t          t          |¦  «        d ¦  «        ‘Œ S )r
   )r_   ra   r¤   s     r   r   z'_query_token_counts.<locals>.<listcomp>t  s(   € Ð=Ð=Ð=°4�S¥ T¡¤¨AÑ.Ô.Ð=Ð=Ð=r   )	rŽ   r,   rM   ro   rƒ   r!   ÚtensorÚ_zero_row_maskr   )r   r©   s     r   Ú_query_token_countsr®   n  s°   € ð ÐØ�{Š{‰}Œ}× Ò  RÐ Ñ(Ô(×.Ò.°1Ð.Ñ5Ô5Ð5Ý�!•TÑÔð ?ÝŒ|Ð=Ð=¸1Ð=Ñ=Ô=Ñ>Ô>Ð>ÝÕ,¨QÑ/Ô/Ñ0Ô0×5Ò5Ñ7Ô7×;Ò;ÀÐ;ÑCÔC×IÒIÈaÐIÑPÔPÐPr   Úb_maskÚchunk_elementsú
int | NoneÚlength_normalizeústr | torch.device | Nonec           	     ó8  — t          | |d¦  «        \  } }t          ||d¦  «        \  }}t          | ¦  «        dk    st          |¦  «        dk    rZt          |¦  «        pt          | ¦  «        }t          j        t          | ¦  «        t          |¦  «        t          j        |¬¦  «        S |rt          | |¦  «        nd}t          | |¦  «        \  } }	|	�t          |	| j	        d         d¦  «        }	t          |¦  «        }
|�|nt          }t          |t          ¦  «        rd„ |D ¦   «         }n|j	        d         g|
z  }|�t          |t          |¦  «        d¦  «        }t          |¦  «        p| j        }|�t          j        |¦  «        n|}t          | |	|¦  «        \  } }	t!          || j	        d         | j	        d         z  t#          |¦  «        z   |¦  «        }g }|D ]T\  }}t%          |||||d¦  «        \  }}|                     t)          | ||	|¦  «                             |¦  «        ¦  «         ŒUt          |¦  «        dk    r|d         nt          j        |d¬¦  «        }|�7||                     |j        |j        ¬	¦  «                             d¦  «        z  }|S )
a³  
    Computes the MaxSim (late-interaction) score between two collections of multi-vector embeddings.

    For each query in ``a`` and document in ``b``, the score is the sum over query tokens of the maximum
    similarity to any document token: ``sum_i max_j (a_i . b_j)``. This is the scoring function used by
    ColBERT-style models.

    Args:
        a (Union[list, np.ndarray, Tensor]): Query embeddings. Either a 3D tensor of shape
            ``(batch_a, num_query_tokens, embedding_dim)`` (pre-padded), a list of 2D tensors of shape
            ``(num_query_tokens_i, embedding_dim)`` (variable-length, padded internally), or a single
            2D tensor or array (one query, e.g. from a singular encode call, scored as a batch of one).
        b (Union[list, np.ndarray, Tensor]): Document embeddings. Either a 3D tensor of shape
            ``(batch_b, num_doc_tokens, embedding_dim)``, a list of 2D tensors of shape
            ``(num_doc_tokens_i, embedding_dim)``, or a single 2D tensor or array (one document,
            scored as a batch of one).
        a_mask (Tensor, optional): Boolean or float mask for query tokens, shape ``(batch_a, num_query_tokens)``,
            ``(num_query_tokens,)`` alongside a single 2D ``a``, or a list of per-item 1D masks (padded to
            the batch). Tokens with a 0 / False entry are excluded from the sum. Defaults to None (use all tokens).
        b_mask (Tensor, optional): Boolean or float mask for document tokens, shape ``(batch_b, num_doc_tokens)``,
            ``(num_doc_tokens,)`` alongside a single 2D ``b``, or a list of per-item 1D masks. Tokens with a
            0 / False entry are excluded from the max. Defaults to None (use all tokens).
        chunk_elements (int, optional): Element budget for the padded ``(chunk, d_tokens, dim)``
            documents plus the 4D ``(batch_a, chunk, q_tokens, d_tokens)`` scoring intermediate. Documents
            are greedily packed into chunks (padded per chunk, so a long outlier only sizes its own chunk)
            that stay under the budget, with a floor of one document per chunk. Defaults to None, which
            applies a 100M-element budget (at most ~400 MB, half that in bf16 / fp16). With very large
            query batches that floor can still be big: shard queries externally if a single document
            exceeds memory.
        length_normalize (bool, optional): Divide each score by the number of real (unmasked) query
            tokens, yielding MeanMaxSim: scores land in the per-token similarity range (about
            ``[-1, 1]`` for normalized embeddings) independent of the query length. Defaults to False.
        device (str, torch.device, optional): Device to run the scoring on, moving each budget-sized
            document chunk there rather than the whole corpus. The returned scores stay on the
            documents' device either way. Defaults to None (the documents' device).

    Returns:
        Tensor: Matrix with ``res[i][j]`` = MaxSim(a[i], b[j]), shape ``(batch_a, batch_b)``, always
        float32 (half precision inputs are accumulated in float32 to keep nearby scores distinct), on
        the documents' device: CPU documents score on the CPU even against GPU queries.
    r©   r¯   r   ©Údtyper<   Nr
   c                ó,   — g | ]}t          |¦  «        ‘ŒS rz   r£   ©r}   Údocuments     r   r   zmaxsim.<locals>.<listcomp>¸  s   € Ð;Ð;Ð;¨X�3˜x™=œ=Ð;Ð;Ð;r   r*   ©r<   r¶   )rŒ   ra   r–   r!   ÚzerosÚfloat32r®   r�   r’   r�   Ú_MAXSIM_CHUNK_ELEMENT_BUDGETro   rƒ   r_   r<   rš   ri   r¨   r    r`   Ú_maxsim_score_documentsr;   Úcatr¶   rJ   )r   r   r©   r¯   r°   r²   r<   Úresult_deviceÚquery_token_countsÚa_mask_paddedÚnum_documentsÚbudgetÚdocument_widthsÚscoring_devicerb   Úscore_chunksÚd_startÚd_endÚchunk_bÚchunk_b_maskÚscoress                        r   ÚmaxsimrÍ   x  sœ  € õd # 1 f¨hÑ7Ô7�I€A€vÝ" 1 f¨hÑ7Ô7�I€A€vÝ
ˆ1�v„v�‚{€{•c˜!‘f”f ’k�kå*¨1Ñ-Ô-ÐFÕ1CÀAÑ1FÔ1FˆÝŒ{�3˜q™6œ6¥3 q¡6¤6µ´À}ÐUÑUÔUÐUØ;KÐUÕ,¨Q°Ñ7Ô7Ð7ÐQUÐÝ/°°6Ñ:Ô:Ñ€A€}ØÐ Ý'¨°q´w¸q´zÀ8ÑLÔLˆå˜‘F”F€MØ-Ð9ˆ^ˆ^Õ?[€FÝ�!•TÑÔð 7Ø;Ð;¸Ð;Ñ;Ô;ˆˆàœ7 1œ:˜,¨Ñ6ˆØÐÝ  ­¨_Ñ)=Ô)=¸xÑHÔHˆõ
 ' qÑ)Ô)Ð5¨Q¬X€MØ-3Ð-?•U”\ &Ñ)Ô)Ð)À]€NÝ! ! ]°NÑCÔCÑ€A€}õ ˜?¨A¬G°A¬J¸¼À¼Ñ,CÅnÐUVÑFWÔFWÑ,WÐY_Ñ`Ô`€Fà€LØ ð pð p‰ˆ�Ý *¨1¨f°g¸uÀnÐV^Ñ _Ô _Ñˆ�Ø×ÒÕ3°A°wÀÈ|Ñ\Ô\×_Ò_Ð`mÑnÔnÑoÔoÐoÐoå # LÑ 1Ô 1°QÒ 6Ð 6ˆ\˜!Œ_ˆ_½E¼IÀlÐXYÐ<ZÑ<ZÔ<Z€FØÐ%ØÐ,×/Ò/°v´}ÈFÌLÐ/ÑYÔY×cÒcÐdeÑfÔfÑfˆØ€Mr   c                ój  — |j         d         dk    rˆt          j        | j         d         |j         d         t          j        |j        ¬¦  «        }t          t          j        | j         d         |j         d         t          j        |j        ¬¦  «        |¦  «        S t          j        d| |¦  «        }|�k| 	                    |                     ¦   «          
                    d¦  «         
                    d¦  «         t          j        |j        ¦  «        j        ¦  «         |                     d¬¦  «        j                             ¦   «         }|�|| 
                    d¦  «        z  }|                     d¬¦  «        }|�7t          ||                     ¦   «                              d¬¦  «         ¦  «        }|S )	a‡  Score one chunk of documents against every query, returned as ``(a_batch, b_batch)`` float32.
    Pulled out of :func:`maxsim` so the chunk loop stays readable. Reducing the chunk all the way down
    to final scores here is what makes the chunking pay off: concatenating the
    ``(a_batch, b_batch, q_tokens)`` reductions first would rebuild a full-corpus-width intermediate.

    The float32 cast ahead of the query-token sum keeps that accumulation in float32: MaxSim scores
    reach O(num_query_tokens) magnitudes where the bf16 grid is 0.125 wide, coarse enough to collapse
    thousands of documents onto a handful of distinct scores.
    r
   r   rµ   zash,bth->abstNrF   r)   r*   ©r�   r!   ÚonesrŽ   r<   Ú_fill_empty_document_scoresr»   r¼   ÚeinsumÚmasked_fill_rJ   Úfinfor¶   rH   r_   Úvaluesr:   r,   Úany©r   r   r©   r¯   ÚemptyrÌ   s         r   r¾   r¾   Ô  sj  € ð 	„wˆq„z�Q‚€å”
˜1œ7 1œ: q¤w¨q¤z½¼ÈAÌHÐUÑUÔUˆÝ*ÝŒK˜œ œ
 A¤G¨A¤Jµe´mÈAÌHÐUÑUÔUÐW\ñ
ô 
ð 	
õ Œ\˜/¨1¨aÑ0Ô0€Fð ÐØ×Ò˜VŸ[š[™]œ]×4Ò4°QÑ7Ô7×AÒAÀ!ÑDÔDÐDÅeÄkÐRXÔR^ÑF_ÔF_ÔFcÑdÔdÐdà�ZŠZ˜BˆZÑÔÔ&×,Ò,Ñ.Ô.€FØÐØ˜&×*Ò*¨1Ñ-Ô-Ñ-ˆØ�ZŠZ˜BˆZÑÔ€FØÐÝ,¨V°f·k²k±m´m×6GÒ6GÈBÐ6GÑ6OÔ6OÐ5OÑPÔPˆØ€Mr   rÌ   rØ   c                óä   — t          ¦   «         sH|j        j        dk    r8|                     ¦   «         r$t                               dt          d›d�¦  «         |                      |t          ¦  «        S )a¹  Overwrite the scores of documents flagged in ``empty`` (no unmasked token), whose every token
    sat at the masked-fill dtype minimum and whose sum therefore poisons downstream losses.

    The fill is unconditional: reading ``empty`` on the host costs a device synchronization per
    scoring call and is a data-dependent branch that :func:`torch.compile` cannot capture, so only
    the warning reads it, and only where that is free.
    Úcpua  Encountered documents without any scoreable token during multi-vector similarity scoring, e.g. because MultiVectorMask (via keep_only_token_ids or skiplist_words) masked out every token, or because a document embedding has zero token vectors. These documents score about z.0ezD (before any normalization), ranking them below every real document.)r   r<   rŠ   rÖ   r7   r8   Ú_EMPTY_DOCUMENT_SCOREÚmasked_fill)rÌ   rØ   s     r   rÑ   rÑ   ù  s{   € õ $Ñ%Ô%ð 
¨%¬,Ô*;¸uÒ*DÐ*DÈÏÊÉÌÐ*DÝ×Òðõ +Ðfðð ð ñ	
ô 	
ð 	
ð ×Ò˜eÕ%:Ñ;Ô;Ð;r   c           	     óä  — t          | |d¦  «        \  } }t          ||d¦  «        \  }}t          | ¦  «        t          |¦  «        k    r0t          dt          | ¦  «        › dt          |¦  «        › d�¦  «        ‚t          | ¦  «        dk    r?t          |¦  «        pt          | ¦  «        }t	          j        dt          j        |¬¦  «        S |rt          | |¦  «        nd}|�|nt          }	t          | t          ¦  «        rd	„ | D ¦   «         n| j        d
         gt          | ¦  «        z  }
t          |t          ¦  «        rd„ |D ¦   «         n|j        d
         gt          |¦  «        z  }|�t          |t          |
¦  «        d¦  «        }|�t          |t          |¦  «        d¦  «        }t          |¦  «        p"t          | ¦  «        pt	          j        d¦  «        }|�t	          j        |¦  «        n|}t          |
¦  «        }t          |¦  «        }t!          |||z   |	||z  ¬¦  «        }g }|D ]k\  }}t#          | ||||d¦  «        \  }}t#          |||||d¦  «        \  }}|                     t'          ||||¦  «                             |¦  «        ¦  «         Œlt          |¦  «        d
k    r|d         nt	          j        |d¬¦  «        }|�$||                     |j        |j        ¬¦  «        z  }|S )aÞ  
    Computes the pairwise MaxSim (late-interaction) score between each query-document pair.

    For each ``i``, computes the MaxSim score between ``a[i]`` and ``b[i]``: the sum over query tokens of the
    maximum similarity to any document token. This is the pairwise analogue of :func:`maxsim`.

    Args:
        a (Union[list, np.ndarray, Tensor]): Query embeddings. Either a 3D tensor of shape
            ``(batch, num_query_tokens, embedding_dim)`` (pre-padded), a list of 2D tensors with
            shape ``(num_query_tokens_i, embedding_dim)``, or a single 2D tensor or array (one query,
            e.g. from a singular encode call, scored as a batch of one).
        b (Union[list, np.ndarray, Tensor]): Document embeddings. Either a 3D tensor of shape
            ``(batch, num_doc_tokens, embedding_dim)``, a list of 2D tensors with shape
            ``(num_doc_tokens_i, embedding_dim)``, or a single 2D tensor or array (one document,
            scored as a batch of one).
        a_mask (Tensor, optional): Boolean or float mask for query tokens, shape ``(batch, num_query_tokens)``,
            ``(num_query_tokens,)`` alongside a single 2D ``a``, or a list of per-item 1D masks (padded to
            the batch). Tokens with a 0 / False entry are excluded from the sum. Defaults to None (use all tokens).
        b_mask (Tensor, optional): Boolean or float mask for document tokens, shape ``(batch, num_doc_tokens)``,
            ``(num_doc_tokens,)`` alongside a single 2D ``b``, or a list of per-item 1D masks. Tokens with a
            0 / False entry are excluded from the max. Defaults to None (use all tokens).
        chunk_elements (int, optional): Element budget for the padded ``(chunk, q_tokens, dim)``
            queries and ``(chunk, d_tokens, dim)`` documents plus the ``(chunk, q_tokens, d_tokens)``
            scoring intermediate. Pairs are greedily packed into chunks (padded per chunk, so a long
            outlier only sizes its own chunk) that stay under the budget, with a floor of one pair per
            chunk. Defaults to None, which applies a 100M-element budget (at most ~400 MB, half that
            in bf16 / fp16).
        length_normalize (bool, optional): Divide each score by the number of real (unmasked) query
            tokens, yielding MeanMaxSim: scores land in the per-token similarity range (about
            ``[-1, 1]`` for normalized embeddings) independent of the query length. Defaults to False.
        device (str, torch.device, optional): Device to run the scoring on, moving each budget-sized
            chunk of pairs there rather than everything. The returned scores stay on the documents'
            device either way. Defaults to None (the documents' device).

    Returns:
        Tensor: Vector with ``res[i]`` = MaxSim(a[i], b[i]), shape ``(batch,)``, always float32
        (half precision inputs are accumulated in float32 to keep nearby scores distinct), on the
        documents' device: CPU documents score on the CPU even against GPU queries.
    r©   r¯   zF`a` and `b` must hold the same number of items to score as pairs, got z and r‚   r   rµ   Nc                ó,   — g | ]}t          |¦  «        ‘ŒS rz   r£   )r}   Úquerys     r   r   z#maxsim_pairwise.<locals>.<listcomp>J  s   € Ð.Ð.Ð. 5•C˜‘J”JÐ.Ð.Ð.r   r
   c                ó,   — g | ]}t          |¦  «        ‘ŒS rz   r£   r¸   s     r   r   z#maxsim_pairwise.<locals>.<listcomp>K  s   € Ð7Ð7Ð7¨•s˜8‘}”}Ð7Ð7Ð7r   rÚ   )r[   r*   rº   )rŒ   ra   r‘   r–   r!   r»   r¼   r®   r½   ro   rƒ   r�   r’   r_   r<   r¨   ri   r    r`   Ú_maxsim_score_pairsr;   r¿   r¶   )r   r   r©   r¯   r°   r²   r<   rÀ   rÁ   rÄ   Úquery_widthsrÅ   rÆ   Úquery_widthr+   rb   rÇ   rc   r›   Úchunk_aÚchunk_a_maskrÊ   rË   rÌ   s                           r   Úmaxsim_pairwiseræ     s  € õ` # 1 f¨hÑ7Ô7�I€A€vÝ" 1 f¨hÑ7Ô7�I€A€vÝ
ˆ1�v„v•�Q‘”ÒÐÝØkÕUXÐYZÑU[ÔU[ÐkÐkÕbeÐfgÑbhÔbhÐkÐkÐkñ
ô 
ð 	
õ ˆ1�v„v�‚{€{å*¨1Ñ-Ô-ÐFÕ1CÀAÑ1FÔ1FˆÝŒ{˜1¥E¤M¸-ÐHÑHÔHÐHØ;KÐUÕ,¨Q°Ñ7Ô7Ð7ÐQUÐà-Ð9ˆ^ˆ^Õ?[€FÝ2<¸QÅÑ2EÔ2EÐ`Ð.Ð.¨AÐ.Ñ.Ô.Ð.ÈAÌGÐTUÌJÈ<ÕZ]Ð^_ÑZ`ÔZ`ÑK`€LÝ;EÀaÍÑ;NÔ;NÐiÐ7Ð7°QÐ7Ñ7Ô7Ð7ÐUVÔU\Ð]^ÔU_ÐT`ÕcfÐghÑciÔciÑTi€OØÐÝ  ­¨\Ñ):Ô):¸HÑEÔEˆØÐÝ  ­¨_Ñ)=Ô)=¸xÑHÔHˆõ ' qÑ)Ô)ÐYÕ-?ÀÑ-BÔ-BÐYÅeÄlÐSXÑFYÔFY€MØ-3Ð-?•U”\ &Ñ)Ô)Ð)À]€Nõ
 �lÑ#Ô#€KÝ
˜Ñ
Ô
€CÝ˜?¨K¸#Ñ,=¸vÐVaÐdgÑVgÐhÑhÔh€Fà€LØð qð q‰
ˆˆsÝ *¨1¨f°e¸SÀ.ÐRZÑ [Ô [Ñˆ�Ý *¨1¨f°e¸SÀ.ÐRZÑ [Ô [Ñˆ�Ø×ÒÕ/°¸À,ÐP\Ñ]Ô]×`Ò`ÐanÑoÔoÑpÔpÐpÐpÝ # LÑ 1Ô 1°QÒ 6Ð 6ˆ\˜!Œ_ˆ_½E¼IÀlÐXYÐ<ZÑ<ZÔ<Z€FØÐ%ØÐ,×/Ò/°v´}ÈFÌLÐ/ÑYÔYÑYˆØ€Mr   Tc           	     ó.   — t          | ||||||¬¦  «        S )aÅ  
    Computes the MeanMaxSim score between two collections of multi-vector embeddings: :func:`maxsim`
    divided by each query's real token count, with :func:`maxsim`'s arguments and return shape.

    MaxSim sums one similarity per query token, so its scale grows with query length and scores are
    not comparable across queries. MeanMaxSim averages instead, landing in the per-token similarity
    range (about ``[-1, 1]`` for normalized embeddings). Rankings within a query are unchanged, since
    the divisor is constant per row.

    ``length_normalize`` defaults to True here (the Mean in the name): False recovers plain
    :func:`maxsim`, so the whole MaxSim family accepts the same keywords.
    ©r©   r¯   r°   r²   r<   )rÍ   ©r   r   r©   r¯   r°   r²   r<   s          r   Úmean_maxsimrê   g  s0   € õ* Ø	Ø	ØØØ%Ø)Øðñ ô ð r   c           	     ó.   — t          | ||||||¬¦  «        S )a@  
    Computes the pairwise MeanMaxSim score for each query-document pair: :func:`maxsim_pairwise`
    divided by each query's real token count, with its arguments and return shape. See
    :func:`mean_maxsim` for why. ``length_normalize`` defaults to True here, and False recovers
    plain :func:`maxsim_pairwise`.
    rè   )ræ   ré   s          r   Úmean_maxsim_pairwiserì   ‡  s0   € õ Ø	Ø	ØØØ%Ø)Øðñ ô ð r   c                óî  — |j         d         dk    rpt          j        |j         d         t          j        |j        ¬¦  «        }t          t          j        |j         d         t          j        |j        ¬¦  «        |¦  «        S t          j        d| |¦  «        }|�X| 	                    |                     ¦   «          
                    d¦  «         t          j        |j        ¦  «        j        ¦  «         |                     d¬¦  «        j                             ¦   «         }|�||z  }|                     d¬¦  «        }|�7t          ||                     ¦   «                              d¬¦  «         ¦  «        }|S )a  Score one chunk of aligned query-document pairs, returned as ``(batch,)`` float32. Pulled out of
    :func:`maxsim_pairwise` so the chunk loop stays readable. The mirror of
    :func:`_maxsim_score_documents`, differing only in the einsum and the mask broadcast axes.r
   r   rµ   zbsh,bth->bstNr)   r*   rÏ   r×   s         r   rá   rá   ¡  s4  € ð 	„wˆq„z�Q‚€å”
˜1œ7 1œ:­U¬ZÀÄÐIÑIÔIˆÝ*­5¬;°q´w¸q´zÍÌÐ_`Ô_gÐ+hÑ+hÔ+hÐjoÑpÔpÐpÝŒ\˜.¨!¨QÑ/Ô/€Fð ÐØ×Ò˜VŸ[š[™]œ]×4Ò4°QÑ7Ô7Ð7½¼ÀVÄ\Ñ9RÔ9RÔ9VÑWÔWÐWà�ZŠZ˜BˆZÑÔÔ&×,Ò,Ñ.Ô.€FØÐØ˜&‘ˆØ�ZŠZ˜BˆZÑÔ€FØÐÝ,¨V°f·k²k±m´m×6GÒ6GÈBÐ6GÑ6OÔ6OÐ5OÑPÔPˆØ€Mr   Úpaddedc                ó^   — |                       d¬¦  «                             | j        ¦  «        S )aæ  Derive a ``(B, T)`` mask from a pre-padded ``(B, T, D)`` token-embedding tensor by treating
    all-zero rows as padding.

    Real token embeddings normally carry information in at least one dim, so a fully-zero row is the
    all-but-impossible-except-by-pad signal. This matches the zero padding of
    :func:`_pad_tensor_list`. Returned in the input dtype (1.0 for real tokens, 0.0 for pad).

    Boundary: a real all-zero row is indistinguishable from padding here and is masked out of
    scoring. L2-normalized pipelines cannot produce one, but token pooling can (a cluster mean of
    antipodal vectors cancels to zero). Masking such a row scores it as 0 rather than dtype-min
    garbage, the preferable failure mode. A document whose rows are *all* zero instead reads as empty
    and takes the :func:`_fill_empty_document_scores` sentinel. Any future module that intentionally
    emits zero rows (e.g. learned pruning) must pass explicit masks instead of relying on this detection.
    r)   r*   )rÖ   r;   r¶   )rî   s    r   r­   r­   ¹  s(   € ð �:Š:˜"ˆ:ÑÔ× Ò  ¤Ñ.Ô.Ð.r   Útensorsúlist[Tensor]Úlengthsc                óÂ  — | d         j         j        dk    r,t          j        j        j                             | dd¬¦  «        S t          |                     ¦   «         ¦  «        }t          | 	                    ¦   «         ¦  «        |k    rt          j
        | ¦  «        S t          j        | d¬¦  «        }t          |¦  «        }|                     |j         ¦  «        }t          j        |d¦  «        |z
  }t          j        ||j         ¬¦  «        t          j        |||¬¦  «        z
  }t          j        t          j        t          | ¦  «        |j         ¬¦  «        ||¬¦  «        }|                     t          | ¦  «        |z  |j        d         ¦  «        }|                     d||z  |z   |¦  «         |                     t          | ¦  «        ||j        d         ¦  «        S )	aí  Stack per-item ``(tokens_i, dim)`` embeddings into a padded ``(batch, max_tokens, dim)``.

    ``pad_sequence`` copies item by item, which on an accelerator is one kernel launch per item: for
    a 10k document corpus that padding can outweigh the MaxSim that follows it by two orders of
    magnitude. Both alternatives here launch a constant number of kernels instead. On CPU there are
    no launches to amortize and ``pad_sequence`` is the fastest of the three, so it keeps that side.
    r   rÚ   T)r€   Úpadding_valuer*   ©r<   )Úoutput_sizer)   )r<   rŠ   r!   r…   r†   r‡   rˆ   rY   r_   rH   Ústackr¿   ra   r;   ÚcumsumÚarangeÚrepeat_interleaveÚ	new_zerosr�   Úindex_copy_Úview)	rð   rò   Úmax_lenÚflatÚtotalÚstartsÚ	positionsÚrowsrî   s	            r   Ú_pad_tensor_listr  Ë  s‹  € ð ˆq„zÔÔ Ò&Ð&ÝŒxŒ~Ô!×.Ò.¨wÀDÐXYÐ.ÑZÔZÐZÝ�'—+’+‘-”-Ñ Ô €GÝ
ˆ7�;Š;‰=Œ=ÑÔ˜WÒ$Ð$ÝŒ{˜7Ñ#Ô#Ð#åŒ9�W !Ð$Ñ$Ô$€DÝ�‰IŒI€EØ�jŠj˜œÑ%Ô%€GÝŒ\˜' 1Ñ%Ô%¨Ñ/€FÝ”˜U¨4¬;Ð7Ñ7Ô7½%Ô:QÐRXÐZaÐotÐ:uÑ:uÔ:uÑu€IÝÔ"¥5¤<µ°G±´ÀTÄ[Ð#QÑ#QÔ#QÐSZÐhmÐnÑnÔn€DØ�^Š^�C ™LœL¨7Ñ2°D´J¸r´NÑCÔC€FØ
×Ò�q˜$ ™.¨9Ñ4°dÑ;Ô;Ð;Ø�;Š;•s˜7‘|”| W¨d¬j¸¬nÑ=Ô=Ð=r   Úinputsc                ó�  — t          | t          ¦  «        rÎd„ | D ¦   «         }d„ |D ¦   «         }t          j        d„ |D ¦   «         ¦  «        }t	          ||¦  «        }|€‚t          j        |j        d         |j        ¬¦  «        }|                     d¦  «        | 	                    |j        ¦  «                             d¦  «        k      	                    |j
        ¦  «        }||fS t          | ¦  «        }|                     ¦   «         s|                     ¦   «         }|€'|                     ¦   «         dk    rt          |¦  «        }||fS )	ac  Pad a list of variable-length multi-vector tensors into a single 3D tensor with a mask.

    Returns the padded tensor and either the user-provided mask or one derived from the input. For a
    list input the mask comes from the per-row lengths. For a 3D tensor input without a mask the
    mask comes from all-zero rows (see :func:`_zero_row_mask`).
    c                ó,   — g | ]}t          |¦  «        ‘ŒS rz   r{   ©r}   rL   s     r   r   z,_pad_multi_vector_inputs.<locals>.<listcomp>ð  s!   € Ð9Ð9Ð9¨QÕ% aÑ(Ô(Ð9Ð9Ð9r   c                ób   — g | ],}|                      ¦   «         r|n|                     ¦   «         ‘Œ-S rz   )Úis_floating_pointr:   r  s     r   r   z,_pad_multi_vector_inputs.<locals>.<listcomp>ñ  s5   € ÐNÐNÐNÀ˜×+Ò+Ñ-Ô-Ð<�1�1°1·7²7±9´9ÐNÐNÐNr   c                ó(   — g | ]}|j         d          ‘ŒS ©r   )r�   r  s     r   r   z,_pad_multi_vector_inputs.<locals>.<listcomp>ò  s   € Ð<Ð<Ð<¨q ¤¨¤
Ð<Ð<Ð<r   Nr
   rõ   r   é   )ro   rƒ   r!   r¬   r  rù   r�   r<   rJ   r;   r¶   r   r
  r:   r+   r­   )r  rk   rð   rò   rî   r  s         r   r�   r�   ä  s7  € õ �&�$ÑÔð 
à9Ð9°&Ð9Ñ9Ô9ˆØNÐNÀgÐNÑNÔNˆÝ”,Ð<Ð<°GÐ<Ñ<Ô<Ñ=Ô=ˆÝ! '¨7Ñ3Ô3ˆØˆ<åœ V¤\°!¤_¸V¼]ÐKÑKÔKˆIØ×'Ò'¨Ñ*Ô*¨W¯ZªZ¸¼Ñ-FÔ-F×-PÒ-PÐQRÑ-SÔ-SÒS×WÒWÐX^ÔXdÑeÔeˆDØ�tˆ|ÐÝ Ñ'Ô'€FØ×#Ò#Ñ%Ô%ð  Ø—’‘”ˆØ€|˜Ÿ
š
™œ¨Ò)Ð)Ý˜fÑ%Ô%ˆØ�4ˆ<Ðr   ÚxÚyc                óÎ  — | j         s|j         rPt                               d¦  «         | j         r|                      ¦   «         } |j         r|                     ¦   «         }t	          | ¦  «        } t	          |¦  «        }| j        d         dz  dk    rPt          j        j         	                    | ddd¬¦  «        } t          j        j         	                    |ddd¬¦  «        }t          j
        | dd¬¦  «        \  }}t          j
        |dd¬¦  «        \  }}t          j        |dz  |dz  z   dd	¬
¦  «        }||z  ||z  z   |z  }||z  ||z  z
  |z  }t          j        |dz  |dz  z   dd	¬
¦  «        dz  }	t          j        |dz  |dz  z   dd	¬
¦  «        dz  }
||	|
z  z  }||	|
z  z  }t          j        t          j        ||fd¬¦  «        d¬¦  «        }t          j        |¦  «        S )ak  
    Computes the absolute normalized angle distance. See :class:`~sentence_transformers.sentence_transformer.losses.AnglELoss`
    or https://huggingface.co/papers/2309.12871 for more information.

    Args:
        x (Tensor): The first tensor.
        y (Tensor): The second tensor.

    Returns:
        Tensor: Vector with res[i] = angle_sim(a[i], b[i])
    zOPairwise angle similarity does not support sparse tensors. Converting to dense.r
   rF   r   )r   r
   Úconstant)ÚmodeÚvaluer*   T)r+   Úkeepdimg      à?)r   r7   r8   r$   r   r�   r!   r…   Ú
functionalÚpadrŸ   r,   ÚconcatrC   )r  r  r   r   ÚcÚdÚzÚreÚimÚdzÚdwÚ
norm_angles               r   Úpairwise_angle_simr     sð  € ð 	„{ð �a”kð Ý×ÒÐmÑnÔnÐnØŒ;ð 	Ø—
’
‘”ˆAØŒ;ð 	Ø—
’
‘”ˆAå  Ñ#Ô#€AÝ  Ñ#Ô#€Að 	„wˆq„z�A�~˜ÒÐÝŒHÔ×#Ò# A v°JÀaÐ#ÑHÔHˆÝŒHÔ×#Ò# A v°JÀaÐ#ÑHÔHˆõ Œ;�q˜! Ð#Ñ#Ô#�D€A€qÝŒ;�q˜! Ð#Ñ#Ô#�D€A€qåŒ	�!�Q‘$˜˜A™‘+ 1¨dÐ3Ñ3Ô3€AØ
ˆa‰%�!�a‘%‰-˜1Ñ	€BØ
ˆa‰%�!�a‘%‰-˜1Ñ	€Bå	Œ�1�a‘4˜!˜Q™$‘; A¨tÐ	4Ñ	4Ô	4¸Ñ	;€BÝ	Œ�1�a‘4˜!˜Q™$‘; A¨tÐ	4Ñ	4Ô	4¸Ñ	;€BØˆ"ˆr‰'�M€BØˆ"ˆr‰'�M€Bå”�5œ<¨¨R¨°aÐ8Ñ8Ô8¸aÐ@Ñ@Ô@€JÝŒ9�ZÑ Ô Ð r   c                  óv   — e Zd ZdZdZdZdZdZdZdZ	dZ
edd„¦   «         Zedd„¦   «         Zedd„¦   «         ZdS )ÚSimilarityFunctiona  
    Enum class for supported similarity functions. The following functions are supported:

    - ``SimilarityFunction.COSINE`` (``"cosine"``): Cosine similarity
    - ``SimilarityFunction.DOT_PRODUCT`` (``"dot"``, ``dot_product``): Dot product similarity
    - ``SimilarityFunction.EUCLIDEAN`` (``"euclidean"``): Euclidean distance
    - ``SimilarityFunction.MANHATTAN`` (``"manhattan"``): Manhattan distance
    - ``SimilarityFunction.MAXSIM`` (``"maxsim"``): Late-interaction MaxSim, used by
      :class:`~sentence_transformers.multi_vector_encoder.model.MultiVectorEncoder` (ColBERT-style) models.
    - ``SimilarityFunction.MEAN_MAXSIM`` (``"meanmaxsim"``): MaxSim divided by the query's token
      count, so scores are comparable across query lengths. Same rankings within a query.
    ÚcosineÚdotÚ	euclideanr3   rÍ   Ú
meanmaxsimÚsimilarity_functionústr | SimilarityFunctionr   úJCallable[[list | np.ndarray | Tensor, list | np.ndarray | Tensor], Tensor]c                óŽ  — t          | ¦  «        } | t           j        k    rt          S | t           j        k    rt          S | t           j        k    rt          S | t           j        k    rt          S | t           j	        k    rt          S | t           j        k    rt          S t          d| › dt                                ¦   «         › d�¦  «        ‚)aI  
        Converts a similarity function name or enum value to the corresponding similarity function.

        Args:
            similarity_function (Union[str, SimilarityFunction]): The name or enum value of the similarity function.

        Returns:
            Callable[[Union[list, np.ndarray, Tensor], Union[list, np.ndarray, Tensor]], Tensor]: The corresponding similarity function. The MaxSim family also accepts further keyword arguments, see :func:`maxsim`.

        Raises:
            ValueError: If the provided function is not supported.

        Example:
            >>> similarity_fn = SimilarityFunction.to_similarity_fn("cosine")
            >>> similarity_scores = similarity_fn(embeddings1, embeddings2)
            >>> similarity_scores
            tensor([[0.3952, 0.0554],
                    [0.0992, 0.1570]])
        úThe provided function ú4 is not supported. Use one of the supported values: r‚   )r"  ÚCOSINEr   ÚDOT_PRODUCTr0   Ú	MANHATTANrA   Ú	EUCLIDEANrS   ÚMAXSIMrÍ   ÚMEAN_MAXSIMrê   r‘   Úpossible_values©r'  s    r   Úto_similarity_fnz#SimilarityFunction.to_similarity_fnD  së   € õ. 1Ð1DÑEÔEÐàÕ"4Ô";Ò;Ð;ÝˆNØÕ"4Ô"@Ò@Ð@ÝÐØÕ"4Ô">Ò>Ð>Ý Ð ØÕ"4Ô">Ò>Ð>Ý Ð ØÕ"4Ô";Ò;Ð;ÝˆMØÕ"4Ô"@Ò@Ð@ÝÐåð VÐ%8ð  Vð  Võ  oA÷  oQò  oQñ  oSô  oSð  Vð  Vð  Vñ
ô 
ð 	
r   c                óŽ  — t          | ¦  «        } | t           j        k    rt          S | t           j        k    rt          S | t           j        k    rt          S | t           j        k    rt          S | t           j	        k    rt          S | t           j        k    rt          S t          d| › dt                                ¦   «         › d�¦  «        ‚)a1  
        Converts a similarity function into a pairwise similarity function.

        The pairwise similarity function returns the diagonal vector from the similarity matrix, i.e. it only
        computes the similarity(a[i], b[i]) for each i in the range of the input tensors, rather than
        computing the similarity between all pairs of a and b.

        Args:
            similarity_function (Union[str, SimilarityFunction]): The name or enum value of the similarity function.

        Returns:
            Callable[[Union[list, np.ndarray, Tensor], Union[list, np.ndarray, Tensor]], Tensor]: The pairwise similarity function. The MaxSim family also accepts further keyword arguments, see :func:`maxsim_pairwise`.

        Raises:
            ValueError: If the provided similarity function is not supported.

        Example:
            >>> pairwise_fn = SimilarityFunction.to_similarity_pairwise_fn("cosine")
            >>> similarity_scores = pairwise_fn(embeddings1, embeddings2)
            >>> similarity_scores
            tensor([0.3952, 0.1570])
        r+  r,  r‚   )r"  r-  r.   r.  r-   r/  rD   r0  rU   r1  ræ   r2  rì   r‘   r3  r4  s    r   Úto_similarity_pairwise_fnz,SimilarityFunction.to_similarity_pairwise_fnn  sí   € õ4 1Ð1DÑEÔEÐàÕ"4Ô";Ò;Ð;Ý#Ð#ØÕ"4Ô"@Ò@Ð@Ý%Ð%ØÕ"4Ô">Ò>Ð>Ý)Ð)ØÕ"4Ô">Ò>Ð>Ý)Ð)ØÕ"4Ô";Ò;Ð;Ý"Ð"ØÕ"4Ô"@Ò@Ð@Ý'Ð'åð VÐ%8ð  Vð  Võ  oA÷  oQò  oQñ  oSô  oSð  Vð  Vð  Vñ
ô 
ð 	
r   ú	list[str]c                 ó$   — d„ t           D ¦   «         S )a|  
        Returns a list of possible values for the SimilarityFunction enum.

        Returns:
            list: A list of possible values for the SimilarityFunction enum.

        Example:
            >>> possible_values = SimilarityFunction.possible_values()
            >>> possible_values
            ['cosine', 'dot', 'euclidean', 'manhattan', 'maxsim', 'meanmaxsim']
        c                ó   — g | ]	}|j         ‘Œ
S rz   )r  r|   s     r   r   z6SimilarityFunction.possible_values.<locals>.<listcomp>¨  s   € Ð4Ð4Ð4˜A�”Ð4Ð4Ð4r   )r"  rz   r   r   r3  z"SimilarityFunction.possible_values›  s   € ð 5Ð4Õ!3Ð4Ñ4Ô4Ð4r   N)r'  r(  r   r)  )r   r8  )r‹   Ú
__module__Ú__qualname__Ú__doc__r-  r.  ÚDOTr0  r/  r1  r2  Ústaticmethodr5  r7  r3  rz   r   r   r"  r"  .  s£   € € € € € ðð ð €FØ€KØ
€CØ€IØ€IØ€FØ€Kàð'
ð '
ð '
ñ „\ð'
ðR ð*
ð *
ð *
ñ „\ð*
ðX ð5ð 5ð 5ñ „\ð5ð 5ð 5r   r"  )r   r   r   r   r   r   )r   r   r   r   r   r   )r   r   r   r   r   r   r  )
rV   rW   rX   rY   rZ   rY   r[   rY   r   r\   )rj   r   rk   rl   r   rm   )rj   r   rk   ru   rv   rw   r   rm   )F)
rk   r   rd   rY   rv   rw   r�   rŽ   r   r   )rj   r   r   r“   )rj   r   rk   rl   r<   r—   r   r˜   )rj   r   rk   rl   rc   rY   r›   rY   r<   r—   rv   rw   r   r˜   )rj   r   r   rY   )r   r   r©   rl   r   r   )NNNFN)r   r   r   r   r©   rl   r¯   rl   r°   r±   r²   rŽ   r<   r³   r   r   )
r   r   r   r   r©   rl   r¯   rl   r   r   )rÌ   r   rØ   r   r   r   )NNNTN)rî   r   r   r   )rð   rñ   rò   r   r   r   )r  r   rk   rl   r   r˜   )r  r   r  r   r   r   )9Ú
__future__r   Úcollections.abcr   Úenumr   Únumpyrp   r!   Úsklearn.metricsr   r   Útransformers.utilsr   r	   r¬   r   r   r   r   r   Ú
get_loggerr‹   r7   r   r   r   r.   r0   r-   rA   rD   rS   rU   r½   rÛ   ri   rt   rŒ   r’   r–   rš   r    r¨   r®   rÍ   r¾   rÑ   ræ   rê   rì   rá   r­   r  r�   r   r"  rz   r   r   ú<module>rG     s  ðØ "Ð "Ð "Ð "Ð "Ð "à $Ð $Ð $Ð $Ð $Ð $Ø Ð Ð Ð Ð Ð à Ð Ð Ð Ø €€€Ø .Ð .Ð .Ð .Ð .Ð .Ø Ð Ð Ð Ð Ð Ø @Ð @Ð @Ð @Ð @Ð @Ð @Ð @ðð ð ð ð ð ð ð ð ð ð ð ð ð ð 
ˆÔ	˜HÑ	%Ô	%€ðð ð ð ð*ð ð ð ð?ð ?ð ?ð ?ð&_ð _ð _ð _ð.5ð 5ð 5ð 5ð"*ð *ð *ð *ð"4ð 4ð 4ð 4ð8;ð ;ð ;ð ;ð$)ð )ð )ð )ð@Cð Cð Cð Cð(  +Ð ð Ð ð ]^ð ð  ð  ð  ð  ðFð ð ð ð 3ð 3ð 3ð 3ð$jð jð jð jð jðð ð ð ðð ð ð ðð ð ð ð(Gð Gð Gð GðQð Qð Qð Qð !Ø Ø!%Ø"Ø(,ðYð Yð Yð Yð Yðx"ð "ð "ð "ðJ<ð <ð <ð <ð. !Ø Ø!%Ø"Ø(,ðWð Wð Wð Wð Wðz !Ø Ø!%Ø!Ø(,ðð ð ð ð ðF !Ø Ø!%Ø!Ø(,ðð ð ð ð ð4ð ð ð ð0/ð /ð /ð /ð$>ð >ð >ð >ð2ð ð ð ð:*!ð *!ð *!ð *!ðZz5ð z5ð z5ð z5ð z5˜ñ z5ô z5ð z5ð z5ð z5r   