
    hx              '       r   d Z ddlZddlmZmZmZmZmZ ddlm	Z	m
Z
 ddlZddlmZ ddlZddlmc mZ ddlmZ ddlZddlmZmZmZ ddlmZ d	eed
f         deedf         deedf         deedf         deeedf         ef         deedf         deedf         deeed
f         eedf         eedf         f         fdZdeedf         deedf         deedf         deeedf         ef         deed
f         deed
f         deedf         deedf         dedeedf         deeed
f         eed
f         eedf         eedf         f         fdadedej        fdZd ej        dej        fd!Z G d" d#e	          Z  G d$ d%e           Z! G d& d'e           Z" G d( d)e           Z#	 	 	 	 	 	 	 	 	 	 	 dEdeedf         deeed3f         eed4f         f         deed3f         d5eed6f         d7e$deed8f         d9e%d:e%d;e$d<e%d=ed>ed?e%d@e$dAeej&                 dBe$dCe%deej'        ej'        f         f$dDZ(dS )FaG  Hit caller module implementing the Fi-NeMo motif instance calling algorithm.

This module provides the core functionality for identifying transcription factor
binding motif instances in neural network contribution scores using a competitive
optimization approach based on proximal gradient descent.

The main algorithm fits a sparse linear model where contribution scores are
reconstructed as a weighted combination of motif contribution weight matrices (CWMs)
at specific genomic positions. The sparsity constraint ensures that only the most
significant motif instances are called.
    N)TupleUnionOptionalDictList)ABCabstractmethod)ndarray)Tensor)FloatIntBool)tqdmcoefficientszB M Pimportance_scalezB 1 PcwmszM 4 WcontribsB 4 L	sequenceslambdasz1 M 1
step_sizeszB 1 1return Bc                 Z   | |z  }t          j        ||          }||z  }	||	z
  }
t          j        |
|          |z  }|
dz                      d          }||z                      d          }t          j        d|z  d          dz  dz   dz  }||z  }|
|z                      d          }t          j        |                               dd          |z                      d          }||z
  |z                                   }| |||z
  z  z   }t          j        |          }|||fS )	u  Perform a proximal gradient descent optimization step for non-negative lasso.

    This function implements a single optimization step of the Fi-NeMo algorithm,
    which uses proximal gradient descent to solve a sparse reconstruction problem.
    The goal is to represent contribution scores as a sparse linear combination
    of motif contribution weight matrices (CWMs).

    Dimension notation:
    - B = batch size (number of regions processed simultaneously)
    - M = number of motifs
    - L = sequence length
    - W = motif width (length of each motif)
    - P = L - W + 1 (number of valid motif positions)

    Parameters
    ----------
    coefficients : Float[Tensor, "B M P"]
        Current coefficient matrix representing motif instance strengths.
    importance_scale : Float[Tensor, "B 1 P"]
        Scaling factors for importance-weighted reconstruction.
    cwms : Float[Tensor, "M 4 W"]
        Motif contribution weight matrices for all motifs.
        4 represents the DNA bases (A, C, G, T).
    contribs : Float[Tensor, "B 4 L"]
        Target contribution scores to reconstruct.
    sequences : Float[Tensor, "B 4 L"] | int
        One-hot encoded DNA sequences. Can be a scalar (1) for hypothetical mode.
    lambdas : Float[Tensor, "1 M 1"]
        L1 regularization weights for each motif.
    step_sizes : Float[Tensor, "B 1 1"]
        Optimization step sizes for each batch element.

    Returns
    -------
    c_next : Float[Tensor, "B M P"]
        Updated coefficient matrix after the optimization step (shape: batch_size × motifs × positions).
    dual_gap : Float[Tensor, " B"]
        Duality gap for convergence assessment (shape: batch_size).
    nll : Float[Tensor, " B"]
        Negative log likelihood (proportional to MSE, shape: batch_size).

    Notes
    -----
    The algorithm uses proximal gradient descent to solve:

    minimize_c: ||contribs - conv_transpose(c * importance_scale, cwms) * sequences||²₂ + λ||c||₁

    subject to: c ≥ 0

    References
    ----------
    - Proximal gradient descent: https://yuxinchen2020.github.io/ele520_math_data/lectures/lasso_algorithm_extension.pdf, slide 22
    - Duality gap computation: https://stanford.edu/~boyd/papers/pdf/l1_ls.pdf, Section III
          r   dimr         ?maxT)r   keepdim)	Fconv_transpose1dconv1dsumamaxtorchclampabsrelu)r   r   r   r   r   r   r   coef_adjpred_unmaskedpred	residualsngradnll	dual_norm
dual_scale
nll_scaled	dual_diffl1_termdual_gapc_nexts                       7/srv/www/kundaje/kobbad/Fi-NeMo/src/finemo/hitcaller.pyprox_grad_stepr;      sa   @ ..H&x66M	! 	
 4IHY%%(88E a<



(
(C &&6&22I+a)m555:Q>!CJz!JX%**v*66Iy&&**q$*??'INN O  G Y&05577H J%'/::FVF^^F8S      
coef_intercoefiLc
           	          |}
t          ||| |||	|          \  }}}||z  }|d|z  z  }||dz   z  }d|z   |z  ||
z  z
  }||||fS )ug  Perform a non-negative lasso optimizer step with Nesterov momentum.

    This function combines proximal gradient descent with momentum acceleration
    to improve convergence speed while maintaining the non-negative constraint
    on coefficients.

    Dimension notation:
    - B = batch size (number of regions processed simultaneously)
    - M = number of motifs
    - L = sequence length
    - W = motif width (length of each motif)
    - P = L - W + 1 (number of valid motif positions)

    Parameters
    ----------
    cwms : Float[Tensor, "M 4 W"]
        Motif contribution weight matrices.
    contribs : Float[Tensor, "B 4 L"]
        Target contribution scores.
    importance_scale : Float[Tensor, "B 1 P"]
        Importance scaling factors.
    sequences : Union[Int[Tensor, "B 4 L"], int]
        One-hot encoded sequences or scalar for hypothetical mode.
    coef_inter : Float[Tensor, "B M P"]
        Intermediate coefficient matrix (with momentum).
    coef : Float[Tensor, "B M P"]
        Current coefficient matrix.
    i : Float[Tensor, "B 1 1"]
        Iteration counter for each batch element.
    step_sizes :  Float[Tensor, "B 1 1"]
        Step sizes for optimization.
    L : int
        Sequence length for normalization.
    lambdas : Float[Tensor, "1 M 1"]
        Regularization parameters.

    Returns
    -------
    coef_inter : Float[Tensor, "B M P"]
        Updated intermediate coefficients with momentum (shape: batch_size × motifs × positions).
    coef : Float[Tensor, "B M P"]
        Updated coefficient matrix (shape: batch_size × motifs × positions).
    gap : Float[Tensor, " B"]
        Normalized duality gap (shape: batch_size).
    nll : Float[Tensor, " B"]
        Normalized negative log likelihood (shape: batch_size).

    Notes
    -----
    Uses Nesterov momentum with momentum coefficient i/(i+3) for improved
    convergence properties. The duality gap and NLL are normalized by
    sequence length for scale-invariant convergence assessment.

    References
    ----------
    https://yuxinchen2020.github.io/ele520_math_data/lectures/lasso_algorithm_extension.pdf, slides 22, 27
    r         @r   )r;   )r   r   r   r   r=   r>   r?   r   r@   r   	coef_prevgapr2   mom_terms                 r:   optimizer_steprF   {   s    T I $$dHi* ND#s 'C
Q-C AG}Hh,$&I)==JtS#%%r<   tensorc                 z     | dddddddf         j         ddt          j        i|                    d          S )aT  Convert tensor to channel-last memory layout for optimized convolution operations.

    Parameters
    ----------
    tensor : torch.Tensor
        Input tensor to convert.
    **kwargs
        Additional keyword arguments passed to tensor.to().

    Returns
    -------
    torch.Tensor
        Tensor with channel-last memory layout.
    Nmemory_format    )tor)   channels_lastsqueeze)rG   kwargss     r:   _to_channel_last_layoutrP      sO      	!qqq!!!QQQ} MMu/BMfMMUUVWXXr<   xc                 x    t          j        |           t          j        t          j        |                     z  S )a  Apply signed square root transformation to input tensor.

    This transformation preserves the sign while applying square root to the
    absolute value, which can help with numerical stability and gradient flow.

    Parameters
    ----------
    x : torch.Tensor
        Input tensor.

    Returns
    -------
    torch.Tensor
        Transformed tensor with same shape as input.
    )r)   signsqrtr+   )rQ   s    r:   _signed_sqrtrU      s)      :a==5:eill3333r<   c                   2   e Zd ZdZdeeedf         eedf         f         deedf         dede	j
        dd	f
d
Zdededeeedf         eedf         f         fdZedededeeedf         eeedf         ef         eedf         f         fd            Zd	S )BatchLoaderBasea  Base class for loading batches of contribution scores and sequences.

    This class provides common functionality for different input formats
    including batch indexing and padding for consistent batch sizes.

    Dimension notation:
    - N = number of sequences/regions in dataset
    - L = sequence length
    - B = batch size (number of regions processed simultaneously)

    Parameters
    ----------
    contribs : Union[Float[Tensor, "N 4 L"], Float[Tensor, "N L"]]
        Contribution scores array.
    sequences : Int[Tensor, "N 4 L"]
        One-hot encoded sequences array.
    L : int
        Sequence length.
    device : torch.device
        Target device for tensor operations.
    r   N 4 LN Lr   r@   devicer   Nc                 >    || _         || _        || _        || _        d S )N)r   r   r@   rZ   )selfr   r   r@   rZ   s        r:   __init__zBatchLoaderBase.__init__  s$     !"r<   startendz Z.c                    ||z
  }t          || j        j        d                   }|||z
  z
  }ddddd|f}t          j        t          j        ||t
          j                  d|fd                              | j	                  }||fS )a  Get indices and padding lengths for batch loading.

        Parameters
        ----------
        start : int
            Start index for batch.
        end : int
            End index for batch.

        Returns
        -------
        inds : Int[Tensor, " Z"]
            Padded indices tensor with -1 for padding positions (shape: padded_batch_size).
        pad_lens : tuple
            Padding specification for F.pad (left, right, top, bottom, front, back).
        r   )dtype)value)rZ   )
minr   shaper$   padr)   arangeintrL   rZ   )r\   r^   r_   Noverhangpad_lensindss          r:   _get_inds_and_pad_lensz&BatchLoaderBase._get_inds_and_pad_lens  s    & %K#t}*1-..e$q!Q8,uL595558}B
 
 

"DK"
 
  	 X~r<   r   r   c                     dS )u  Load a batch of data.

        Dimension notation:
        - B = batch size (number of regions in this batch)
        - L = sequence length

        Parameters
        ----------
        start : int
            Start index (used by subclasses).
        end : int
            End index (used by subclasses).

        Returns
        -------
        contribs_batch : Float[Tensor, "B 4 L"]
            Batch of contribution scores (shape: batch_size × 4_bases × L).
        sequences_batch : Union[Int[Tensor, "B 4 L"], int]
            Batch of one-hot encoded sequences (shape: batch_size × 4_bases × L) or scalar 1 for hypothetical mode.
        inds_batch : Int[Tensor, " B"]
            Batch indices mapping to original sequence indices (shape: batch_size).

        Notes
        -----
        This is an abstract method that must be implemented by subclasses.
        Parameters are intentionally unused in the base implementation.
        NrK   )r\   r^   r_   s      r:   
load_batchzBatchLoaderBase.load_batch=  s
    B 	r<   )__name__
__module____qualname____doc__r   r   r   r   rh   r)   rZ   r]   r   rm   r	   ro   rK   r<   r:   rW   rW      s<        ,
fgo.fem0DDE
 vw'
 	

 
 

 
 
 
"	s64< %S/1	2   <   " 	fgoc&'/&:C&? @#fdlBSS
      ^     r<   rW   c                   h    e Zd ZdZdededeeedf         eedf         eedf         f         fdZ	dS )	BatchLoaderCompactFmtzBatch loader for compact format contribution scores.

    Handles contribution scores in shape (N, L) representing projected
    scores that need to be broadcasted to (N, 4, L) format.
    r^   r_   r   r   r   c                 l   |                      ||          \  }}t          j        | j        ||d d d f         |          }t	          || j        t          j                  }t          j        | j        ||d d d d f         |          }t	          || j        t          j	                  }||z  }|||fS NrZ   ra   
rm   r$   rf   r   rP   rZ   r)   float32r   int8)r\   r^   r_   rl   rk   contribs_compactcontribs_batchsequences_batchs           r:   ro   z BatchLoaderCompactFmt.load_batchh  s     44UC@@h5uSy$/A!BHMM0T[
 
 
 %uSy!!!QQQ ?JJ1DKuz
 
 
 (/944r<   N
rp   rq   rr   rs   rh   r   r   r   r   ro   rK   r<   r:   ru   ru   a  sq         55"5	uVW_%s67?';S=NN	O5 5 5 5 5 5r<   ru   c                   h    e Zd ZdZdededeeedf         eedf         eedf         f         fdZ	dS )	BatchLoaderProjzBatch loader for projected contribution scores.

    Handles contribution scores in shape (N, 4, L) where scores are
    element-wise multiplied by one-hot sequences to get projected contributions.
    r^   r_   r   r   r   c                 p   |                      ||          \  }}t          j        | j        ||d d d d f         |          }t	          || j        t          j                  }t          j        | j        ||d d d d f         |          }t	          || j        t          j	                  }||z  }|||fS rw   ry   )r\   r^   r_   rl   rk   contribs_hypr~   r}   s           r:   ro   zBatchLoaderProj.load_batch  s     44UC@@huT]59aaa?;XFF.EM
 
 
 %uSy!!!QQQ ?JJ1DKuz
 
 
 &744r<   Nr   rK   r<   r:   r   r   {  sq         55"5	uVW_%s67?';S=NN	O5 5 5 5 5 5r<   r   c                   X    e Zd ZdZdededeeedf         eeedf         f         fdZ	dS )	BatchLoaderHypzBatch loader for hypothetical contribution scores.

    Handles hypothetical contribution scores in shape (N, 4, L) where
    scores represent counterfactual effects of base substitutions.
    r^   r_   r   r   r   c                     |                      ||          \  }}t          j        | j        ||d d d d f         |          }t	          || j        t          j                  }|d|fS )Nrx   r   )rm   r$   rf   r   rP   rZ   r)   rz   )r\   r^   r_   rl   rk   r}   s         r:   ro   zBatchLoaderHyp.load_batch  su     44UC@@ht}U3Y111_=xHH04;em
 
 
 q$&&r<   Nr   rK   r<   r:   r   r     sh         
'
'"
'	uVW_%sC,==	>
' 
' 
' 
' 
' 
'r<   r   rB   {Gz?FMb@?'    ffffff?Tr    rX   rY   cwm_trim_maskzM Wuse_hypotheticalz Mstep_size_maxstep_size_minsqrt_transformconvergence_tol	max_steps
batch_sizestep_adjustpost_filterrZ   compile_optimizerepsc                    | j         \  }}}|j         \  }}}|}|at          j                                        rt          j        d          }n.t          j        d          }t          j        dt                     |rt          j        t          d          a	t          j
        |           }t          j
        |          }t          j
        |          }t          j
        |          dddddf                             ddd          }t          j
        |          ddddf                             |t          j        	          }t          ||t          j        	          }t          ||t          j        	          }||z  }|rJt          |          }|d
z                      d                                          }||ddddf         z  }t%          |j                   dk    r(|rt'          ||||          }nft)          ||||          }nSt%          |j                   d
k    r$|rt+          d          t-          ||||          }nt+          d|j                    g }g }g } g }!g }"g g g g g g d}#t          j        ||||z
  dz   f          }$t          |$|t          j        	          }$t          j        |$          }%t          j        |ddft          j        |          }&t          j        |ddf|t          j        |          }'t          j        |fdt          j        |          }(|})t          j        |d|f          }*t          |*|t          j        	          }*|rd}+n3t          j        |d|f          }+t          |+|t          j        	          }+t          j        ||||z
  dz   f          },t          |,|t          j        	          },t          j        |ft          j        |          }-t          j        |ft          j        |          }.t=          dd|d          5 }/d}0d}1|0|k     r|)dk    r`|1}2|2|)z   }3t?          |3|j         d                   }1|                     t3          |2          t3          |3                    }4|4\  }5}6}7|rt          |5          }5|5d
z                      d          |z                                  }8t          j!        |5|8ddddf         z            }5tE          j#        |5d
z  |          |z   dz  }9|9$                    d          }9|5|*|(ddddf<   |s|6|+|(ddddf<   |9|,|(ddddf<   |7|-|(<   |8|.|(<   |$|(ddddfxx         dz  cc<   |%|(ddddfxx         dz  cc<   |&|(xx         dz  cc<   ||'|(<   t          ||*|,|+|$|%|&|'||
  
        \  }$}%}:};|&dz  }&|-dk    }<t          j%        |:           |<z  }=|$|=ddddfxx         dz  cc<   |%|=ddddfxx         dz  cc<   |&|=xx         dz  cc<   |'|=ddddfxx         |z  cc<   |&|
k    &                                |<z  }>|>                                '                                dk    r.|-|>         }?|?D ]#}@t          j        d|@ d|
 dt                     $|'|k     &                                |<z  }A|A                                '                                dk    r+|-|A         }B|BD ] }@t          j        d|@ dt                     !|:|	k    |>z  |Az  |<z  }(|(                                '                                })|)dk    r|-|(         }C|.|(         }D|%|(ddddf         }E|,|(ddddf         }F|Fdz  |z
  }G|G                                }H|*|(ddddf         }ItE          j#        t          j(        |I          |          }JtE          j#        |I|          }K|K|Hz  }L|r	|E|L|k    z  }E|E)                                }Et          j*        |E+                                          }MtE          j,        |Mdddf         |Cdddf                   &                                |Mdddf<   t          j-        |E+                                          }N|J|N         }O|G|N         }P|L|N         }Q|E.                                }R|:|(         }S|;|(         }T|&|(ddf         }U|'|(ddf         }V|/                    |M0                    d          j1                   |/                    |R0                    d                     | /                    |Q0                    d                     |!/                    |O0                    d                     |"/                    |P0                    d                     |#d          /                    |T0                    d                     |#d!         /                    |S0                    d                     |#d"         /                    |U0                    d                     |#d#         /                    |D0                    d                     |#d$         /                    |V0                    d                     |#d%         /                    |C0                    d          2                    tf          j4                             |0|)z  }0|/5                    |)           |0|k     ddd           n# 1 swxY w Y   tg          j6        |d&          }Wtg          j6        |d&          }Xtg          j6        | d&          }Ytg          j6        |!d&          }Ztg          j6        |"d&          }[|Wdddf         2                    tf          j4                  |Wdddf         2                    tf          j4                  |Wddd
f         |X|Y|Z|[d'}\d( |#7                                D             }]tq          j9        |\          }^tq          j9        |]          }_|^|_fS ))u  Call motif hits by fitting sparse linear model to contribution scores.

    This is the main function implementing the Fi-NeMo algorithm. It identifies
    motif instances by solving a sparse reconstruction problem where contribution
    scores are approximated as a linear combination of motif CWMs at specific
    positions. The optimization uses proximal gradient descent with momentum.

    Parameters
    ----------
    cwms : Float[ndarray, "M 4 W"]
        Motif contribution weight matrices where:
        - M = number of motifs (transcription factor binding patterns)
        - 4 = DNA bases (A, C, G, T dimensions)
        - W = motif width (length of each motif pattern)
    contribs : Float[ndarray, "N 4 L"] | Float[ndarray, "N L"]
        Neural network contribution scores where:
        - N = number of regions in dataset
        - L = sequence length
        Can be hypothetical (N, 4, L) or projected (N, L) format.
    sequences : Int[ndarray, "N 4 L"]
        One-hot encoded DNA sequences (shape: num_regions × 4_bases × L).
    cwm_trim_mask : Float[ndarray, "M W"]
        Binary mask indicating which positions of each CWM to use (shape: num_motifs × motif_width).
    use_hypothetical : bool
        Whether to use hypothetical contribution scores (True) or
        projected scores (False).
    lambdas : Float[ndarray, " M"]
        L1 regularization weights for each motif (shape: num_motifs).
    step_size_max : float, default 3.0
        Maximum optimization step size.
    step_size_min : float, default 0.08
        Minimum optimization step size (for convergence failure detection).
    sqrt_transform : bool, default False
        Whether to apply signed square root transformation to inputs.
    convergence_tol : float, default 0.0005
        Convergence tolerance based on duality gap.
    max_steps : int, default 10000
        Maximum number of optimization steps.
    batch_size : int, default 2000
        Number of regions to process simultaneously.
    step_adjust : float, default 0.7
        Factor to reduce step size when optimization diverges.
    post_filter : bool, default True
        Whether to filter hits based on similarity threshold.
    device : torch.device, optional
        Target device for computation. Auto-detected if None.
    compile_optimizer : bool, default False
        Whether to JIT compile the optimizer for speed.
    eps : float, default 1.0
        Small constant for numerical stability.

    Returns
    -------
    hits_df : pl.DataFrame
        DataFrame containing called motif hits with columns:
        - peak_id: Region index
        - motif_id: Motif index
        - hit_start: Start position of hit
        - hit_coefficient: Hit strength coefficient
        - hit_similarity: Cosine similarity with motif
        - hit_importance: Total contribution score in hit region
        - hit_importance_sq: Sum of squared contributions (for normalization)
    qc_df : pl.DataFrame
        DataFrame containing quality control metrics with columns:
        - peak_id: Region index
        - nll: Final negative log likelihood
        - dual_gap: Final duality gap
        - num_steps: Number of optimization steps
        - step_size: Final step size
        - global_scale: Region-level scaling factor

    Notes
    -----
    The algorithm solves the optimization problem:

    minimize_c: ||contribs - Σⱼ convolve(c * scale, cwms[j]) * sequences||²₂ + Σⱼ λⱼ||c[:,j]||₁

    subject to: c ≥ 0

    where c[i,j] represents the strength of motif j at position i.

    The importance scaling balances reconstruction across different
    motifs and positions based on the local contribution magnitude.

    Examples
    --------
    >>> hits_df, qc_df = fit_contribs(
    ...     cwms=motif_cwms,
    ...     contribs=contrib_scores,
    ...     sequences=onehot_seqs,
    ...     cwm_trim_mask=trim_masks,
    ...     use_hypothetical=False,
    ...     lambdas=np.array([0.7, 0.8]),
    ...     step_size_max=3.0,
    ...     step_size_min=0.08,
    ...     sqrt_transform=False,
    ...     convergence_tol=0.0005,
    ...     max_steps=10000,
    ...     batch_size=1000,
    ...     step_adjust=0.7,
    ...     post_filter=True,
    ...     device=None,
    ...     compile_optimizer=False
    ... )
    Ncudacpuz!No GPU available. Running on CPU.T)	fullgraphr      rx   r   r   r   rJ   z=Input regions do not contain hypothetical contribution scoresz0Input contributions array is of incorrect shape )r2   r8   	num_steps	step_sizeglobal_scalepeak_id)ra   rZ   regionsx   )disableunittotalncolsr   g      
   r!   zRegion z$ has not converged within max_steps=z iterations.zOptimizer failed for region .)forcer2   r8   r   r   r   r   axis)r   motif_id	hit_starthit_coefficienthit_similarityhit_importancehit_importance_sqc                 B    i | ]\  }}|t          j        |d           S )r   r   )npconcatenate).0kvs      r:   
<dictcomp>z fit_contribs.<locals>.<dictcomp>6  s-    WWWtq!a!:!:!:WWWr<   ):re   r)   r   is_availablerZ   warningswarnRuntimeWarningcompilerF   
from_numpyrepeatrL   rz   rP   rU   r'   rT   lenr   r   
ValueErrorru   zeros
zeros_likerh   fullboolr{   floatr   rd   ro   
nan_to_numr$   r&   r*   isfiniterN   itemr+   	to_sparsecloneindices	embeddingunbindvaluesappendnumpyTastyper   uint32updater   itemspl	DataFrame)`r   r   r   r   r   r   r   r   r   r   r   r   r   r   rZ   r   r   M_Wri   r@   Bcwms_tensorcontribs_tensorsequences_tensorcwm_trim_mask_tensorlambdas_tensorcwm_normbatch_loaderhit_idxs_lstcoefficients_lstsimilarity_lstimportance_lstimportance_sq_lstqc_lstsr=   r>   r?   r   	convergednum_loadcontribs_bufseqs_bufimportance_scale_bufinds_bufglobal_scale_bufpbarnum_completenext_ind
load_startload_end
batch_datar}   
seqs_batch
inds_batchglobal_scale_batchimportance_scale_batchrD   r2   activedivergedtimeoutstimeout_indsindfails	fail_indsinds_outglobal_scale_outcoef_outimportance_scale_out_denseimportance_sq
xcor_scalecontribs_convergedimportance_sum_out_densexcov_out_densexcor_out_densehit_idxs_out	ind_tupleimportance_outimportance_sq_outxcor_outscores_out_rawgap_outnll_outstep_outstep_sizes_outhit_idxsscores_coefficientscores_similarityscores_importancescores_importance_sqhitsqchits_dfqc_dfs`                                                                                                   r:   fit_contribsr     s   x jGAq!oGAq!A~:""$$ 	O\&))FF\%((FM=~NNN  G~FFF !& 0 6 6K$)$4X$>$>O%*%5i%@%@ +M::111dAAA:FMMaQRTUVV#(#3G#<#<T111d]#K#N#NU] $O $ $N
 *F%-  K 3V5=    44K <";//N''F'3388::!HQQQd]$;; ? !!Q&& 	Y)/;KQPVWWLL*?<LaQWXXLL	_"	#	#q	(	( 	O   1!11f LL V?TVV
 
 	

 #%L&($&N$&N')) )G */	
Aq1uqy* *J )F%-XXXJ#(#3J#?#?D %Q1IUYv V V VA).	
Aq	=f* * *J %*J	
d%*V% % %I H+0;1ay+A+AL*V5=  L
  V;1ay))*8F%*UUU38;1a!eai?P3Q3Q2V5=   #(+qd%)F"S"S"SH,1K	
EK- - - 
d!3	?	?	? N&4Q!||%
%0x)>q)ABB)44S__c(mmTT
9C6
J! B%1.%A%AN'5q'8&=&=&&=&I&IA&M%S%S%U%U"!&!1"%74%FF" "
 H^Q.0DEEK*& *@)E)E")E)M)M&0>Y111_-' ;0:HY111_-8N$Y111_5&0#.@ +9aaa?+++q0+++Y111_%%%*%%%)!(5
9% *8$* *&Jc3 FA ]Fs+++f4HxAAA~&&&!+&&&111aaa   A%   hKKK1KKKxAAA~&&&+5&&&I..0069H||~~""$$q(('1'  CMb#bb9bbb&   
  -/88::VCEyy{{!!A%%$UO	$ Y YCM"G"G"G"GXXXX0H<uDNI }}++--H !||#I.#3I#>   	111aaa0-A)QQQPQPQPQ/-R* :r BS H*//11
%1)QQQ/%B"+,8I0113G, ,( "#*<k!J!J!/*!< M'>^+KLH $--//  %{8+;+;+=+=>>%&[ AAA&D(9& &')) QT"
 "L)9)9););<<	!9)!D$1)$<!))4!)!2!2 i.i.Y1_-!+Iq!O!<##L$6$6T$6$B$B$DEEE ''(<(<4(<(H(HIII%%hnn4n&@&@AAA%%n&:&:&:&F&FGGG!(():)@)@t)@)L)LMMM%%gmm$m&?&?@@@
#**7==t=+D+DEEE$++HNNN,F,FGGG'../?/E/ED/E/Q/QRRR$++N,@,@t,@,L,LMMM	"))(..t.*D*D*K*KBI*V*VWWW(H%%%W QN& N& N& N& N& N& N& N& N& N& N& N& N& N& N&b ~l333H(8qAAA~A>>>~A>>>>*;!DDD AAAqD>((33QQQTN))")44aaad^-++1   D XWw}}WWWBl4  GLEE>s   .[*l$$l(+l()rB   r   Fr   r   r   r   TNFr    ))rs   r   typingr   r   r   r   r   abcr   r	   r   r   r
   r)   torch.nn.functionalnn
functionalr$   r   polarsr   	jaxtypingr   r   r   r   rh   r;   rF   rP   rU   rW   ru   r   r   r   r   rZ   r   r   rK   r<   r:   <module>r(     sN  
 
  5 5 5 5 5 5 5 5 5 5 5 5 5 5 # # # # # # # #                               & & & & & & & & & &      \!(\!FGO,\! 
 \! FGO$	\!
 S)3./\! 67?#\! fgo&\! 5!5#6fdl8KKL\! \! \! \!~W&

 W&FGO$W& FGO,W& S)3./	W&
 fgo&W& 
 W& VW_W& fgo&W& W& 67?#W& 	&'/	&'/	&$,	&$,W& W& W& W&tF     (4EL 4U\ 4 4 4 4&b b b b bc b b bJ5 5 5 5 5O 5 5 545 5 5 5 5o 5 5 52' ' ' ' '_ ' ' '6  #%)##S S
 
!SE'7*+U7E>-BBCS 7G#$S %(	S
 S 7D=!S S S S S S S S S U\"S  !S" 
#S$ 2<%&%S S S S S Sr<   