
    Wi                     |   d dl Zd dlmZ d dlmZmZmZ d dlm	Z	 d dl
Z
d dlmZ d dlmZmZ d dlZd dlZd dlmZ 	 d dlZ	 d dlZd d
lmZ dZ	 d dlZd dlmZ d dlmc mZ d dl Zd dl Zd dl!Z! G d de      Z"d Z#	 d$dZ$d%dZ%	 d&dZ&	 d'dZ'	 d'dZ(d Z)d(dZ*d)dZ+d)dZ, G d dejZ                  j\                        Z/d Z0 G d d ejb                        Z2er G d! d"ejf                        Z4d# Z5yy# e$ r  ed        ed	      dw xY w# e$ r  ed        ed      dw xY w# e$ r  ed       dZY w xY w)*    N)UMAP)warncatch_warningsfilterwarnings)TypingError)spectral_layout)check_random_statecheck_array)KDTreea  The umap.parametric_umap package requires Tensorflow > 2.0 to be installed.
    You can install Tensorflow at https://www.tensorflow.org/install
    
    or you can install the CPU version of Tensorflow using 

    pip install umap-learn[parametric_umap]

    z/umap.parametric_umap requires Tensorflow >= 2.0)opszEThe umap.parametric_umap package requires Keras >= 3 to be installed.z#umap.parametric_umap requires KerasTz7Torch and ONNX required for exporting to those formats.Fc                        e Zd Zddddddddddddi f fd	Zd fd	Z	 d fd	ZddZ fd	Zd
 ZddZ	d Z
ddZ	 	 	 	 ddZd Zd Z xZS )ParametricUMAPNF      ?r   c                    t        |   d
i | || _        || _        || _        || _        || _        || _        || _        || _	        d| _
        |
| _        || _        || _        d| _        d| _        |	| _        || _        d| _        t'        | j(                  t*              r)t,        j.                  j1                  | j(                         d| _        t,        j4                  j7                  dd      | _        | j                  i|j:                  d   j<                  d   | j>                  k7  r?tA        d	jC                  |j:                  d   j<                  d   | j>                              yy)af  
        Parametric UMAP subclassing UMAP-learn, based on keras/tensorflow.
        There is also a non-parametric implementation contained within to compare
        with the base non-parametric implementation.

        Parameters
        ----------
        batch_size : int, optional
            size of batch used for batch training, by default None
        dims :  tuple, optional
            dimensionality of data, if not flat (e.g. (32x32x3 images for ConvNet), by default None
        encoder : keras.Sequential, optional
            The encoder Keras network
        decoder : keras.Sequential, optional
            the decoder Keras network
        parametric_reconstruction : bool, optional
            Whether the decoder is parametric or non-parametric, by default False
        parametric_reconstruction_loss_fcn : bool, optional
            What loss function to use for parametric reconstruction,
            by default keras.losses.BinaryCrossentropy
        parametric_reconstruction_loss_weight : float, optional
            How to weight the parametric reconstruction loss relative to umap loss, by default 1.0
        autoencoder_loss : bool, optional
            [description], by default False
        reconstruction_validation : array, optional
            validation X data for reconstruction loss, by default None
        global_correlation_loss_weight : float, optional
            Whether to additionally train on correlation of global pairwise relationships (>0), by default 0
        landmark_loss_fn : callable, optional
            The function to use for landmark loss, by default the euclidean distance
        landmark_loss_weight : float, optional
            How to weight the landmark loss relative to umap loss, by default 1.0
        keras_fit_kwargs : dict, optional
            additional arguments for model.fit (like callbacks), by default {}
        
   N   MbP?      @	clipvaluer   zNDimensionality of embedder network output ({}) doesnot match n_components ({}) )"super__init__dimsencoderdecoderparametric_reconstruction%parametric_reconstruction_loss_weight"parametric_reconstruction_loss_fcnautoencoder_loss
batch_sizeloss_report_frequencyglobal_correlation_loss_weightlandmark_loss_fnlandmark_loss_weightprev_epoch_Xwindow_valsreconstruction_validationkeras_fit_kwargsparametric_model
isinstancerandom_stateintkerasutilsset_random_seedn_training_epochs
optimizersAdam	optimizeroutputsshapen_components
ValueErrorformat)selfr"   r   r   r   r   r    r   r!   r)   r$   r%   r&   r*   kwargs	__class__s                  `/home/sietch6/trending-topics-pipeline/venv/lib/python3.12/site-packages/umap/parametric_umap.pyr   zParametricUMAP.__init__0   sn   h 	"6" 	)B&1 	2 3U/ 0$%'".L+ 0$8!  & 	& !1 $
 d''-KK''(9(9: "# ))..ts.C<<#q!''+t/@/@@ 66<f#OOA.44R8$:K:K7  A $    c                 P   | j                   du|du z  rt        j                  t        j                  t        j                  t        j                  g      g|j
                  d   z  t        | j                  | j                               z         }t        j                  || j                   f      }|-t        |      }t        |      }||k7  rt        d| d| d      | j                  dk(  r&|t        d      || _        t        | 9  |||      S t        | 9  |||      S 	a  Fit X into an embedded space.

        Optionally use a precomputed distance matrix, y for supervised
        dimension reduction, or landmarked positions.

        Parameters
        ----------
        X : array, shape (n_samples, n_features)
            Contains a sample per row. If the method is 'exact', X may
            be a sparse matrix of type 'csr', 'csc' or 'coo'.
            Unlike UMAP, ParametricUMAP requires precomputed distances to
            be passed seperately.

        y : array, shape (n_samples)
            A target array for supervised dimension reduction. How this is
            handled is determined by parameters UMAP was instantiated with.
            The relevant attributes are ``target_metric`` and
            ``target_metric_kwds``.

        precomputed_distances : array, shape (n_samples, n_samples), optional
            A precomputed a square distance matrix. Unlike UMAP, ParametricUMAP
            still requires X to be passed seperately for training.

        landmark_positions : array, shape (n_samples, n_components), optional
            The desired position in low-dimensional space of each sample in X.
            Points that are not landmarks should have nan coordinates.
        Nr   zLength of x = z5, length of landmark_positions                     = z, while it must be equal.precomputedzTPrecomputed distances must be supplied if metric                     is precomputed.landmark_positions)r'   npstackarraynanr7   list	transformconcatenatelenr9   metric_Xr   fitr;   Xyprecomputed_distancesrD   len_Xlen_landr=   s          r>   rO   zParametricUMAP.fit   s:   8 T).@D.HI!#266266*+,qwwqz9t~~d&7&789:" 4#4#456A)FE-.H  $UG ,j 9; 
 ;;-'$, % 
 DG7;%q=O   
 7;q!8J;KKr?   c                 P   | j                   du|du z  rt        j                  t        j                  t        j                  t        j                  g      g|j
                  d   z  t        | j                  | j                               z         }t        j                  || j                   f      }|-t        |      }t        |      }||k7  rt        d| d| d      | j                  dk(  r&|t        d      || _        t        | 9  |||      S t        | 9  |||      S rA   )r'   rE   rF   rG   rH   r7   rI   rJ   rK   rL   r9   rM   rN   r   fit_transformrP   s          r>   rW   zParametricUMAP.fit_transform   s?   < T).@D.HI!#266266*+,qwwqz9t~~d&7&789:" 4#4#456A)FE-.H  $UG ,j 9; 
 ;;-'$, % 
 DG 7(%q=O )   7(ABT(UUr?   c                     |r|n| j                   }| j                  j                  t        j                  |      || j
                        S )a  Transform X into the existing embedded space and return that
        transformed output.

        Parameters
        ----------
        X : array, shape (n_samples, n_features)
            New data to be transformed.
        batch_size : int, optional
            Batch size for inference, defaults to the self.batch_size used in training.

        Returns
        -------
        X_new : array, shape (n_samples, n_components)
            Embedding of the new data in low-dimensional space.
        r"   verbose)r"   r   predictrE   
asanyarrayrZ   )r;   rQ   r"   s      r>   rJ   zParametricUMAP.transform  sA      $.Z4??
||##MM!T\\ $ 
 	
r?   c                     | j                   rE| j                  j                  t        j                  |      | j
                  | j                        S t        | !  |      S )a  Transform X in the existing embedded space back into the input
        data space and return that transformed output.

        Parameters
        ----------
        X : array, shape (n_samples, n_components)
            New points to be inverse transformed.
        Returns
        -------
        X_new : array, shape (n_samples, n_features)
            Generated data points new data in data space.
        rY   )	r   r   r[   rE   r\   r"   rZ   r   inverse_transform)r;   rQ   r=   s     r>   r^   z ParametricUMAP.inverse_transform,  sT     ))<<''a T__dll (   7,Q//r?   c                 F   | j                   }t        | j                  | j                  | j                  | j
                  | j                  | j                  | j                  || j                  | j                  | j                  | j                  | j                        | _        y)zDefine the model in keras)negative_sample_rater   r   !parametric_reconstruction_loss_fnr   r   r$   r!   r%   r&   r5   N)r   	UMAPModel_a_br`   r   r   r    r   r$   r!   r%   r&   r5   r+   )r;   prlws     r>   _define_modelzParametricUMAP._define_model@  s    99 )GGGG!%!:!:LLLL.2.U.U&*&D&D26+/+N+N!22!22!%!:!:nn!
r?   c           	         | j                   dk(  r| j                  }| j                  t        j                  |      d   g| _        nNt        | j                        dkD  r6t        j                  |t        |      gt        | j                        z         }| j                  r;t        j                  |      dkD  st        j                  |      dk  rt        d       |t        |t        j                  d      }t        || j                  | j                   | j"                  | j                  | j$                  |	      \  }| _        }}}	| _        t)        j*                  t)        j,                  |j/                  t        j0                        d
            | _        t)        j*                  t)        j,                  |	j/                  t        j0                        d
            | _        | j6                  md }
t        |      }t9        | j:                  | j<                  | j>                  | j                  || j                  |
      \  | _        | _        | jA                          tC        || j"                  z  | jD                  z        }| j                  r| jF                  t        | j                        dkD  rOt        j                  | jF                  t        | jF                        gt        | j                        z         | _#        | jF                  t)        jH                  | jF                        fd| jF                  if}nd } | j6                  jJ                  |f| jD                  | jL                  z  ||d| jN                  }tQ        | d      s|jR                  | _*        nC|jR                  jW                         D ]&  }| jT                  |xx   |jR                  |   z  cc<   ( | j:                  jY                  || jZ                        }|i fS )NrB   r   r   r           zMData should be scaled to the range 0-1 for cross-entropy reconstruction loss.z	allow-nan)dtypeensure_all_finiterC   r   reconstruction)epochssteps_per_epochvalidation_data_history)rZ   ).rM   rN   r   rE   r7   rL   reshaperI   r   maxminr   r
   float32construct_edge_datasetgraph_n_epochsr"   r$   edge_weightr   rG   expand_dimsastypeint64headtailr+   prepare_networksr   r   r8   rf   r.   r#   r)   
zeros_likerO   r2   r*   hasattrhistoryro   keysr[   rZ   )r;   rQ   rv   initr-   rD   edge_datasetn_edgesr{   r|   init_embeddingn_datarm   rn   r   key	embeddings                    r>   _fit_embed_datazParametricUMAP._fit_embed_dataS  sS   ;;-'A 99!R)DI 499~!JJq3q6(T$))_"<=))rvvay3"&&)c/_
 )!,"jj"-" #KKMMOO**//1
	
O IIcoodkk"((.CQGH	IIcoodkk"((.CQGH	  (!N VF)9!!		..*&DL$,   g7$:T:TTU **..: 499~!13227789DOK2. 22NN4#A#AB "4#A#ABO #O ,$''++
--0F0FF++	

 ##
 tZ(#OODM++- ;c"gooc&::"; LL((DLL(A	"}r?   c                 V    t        d | j                  j                         D              S )Nc              3   J   K   | ]  \  }}t        ||      r
|d vr||f  yw))r5   r   r   r+   N)should_pickle).0kvs      r>   	<genexpr>z.ParametricUMAP.__getstate__.<locals>.<genexpr>  s3      
AQ"PP F
s   !#)dict__dict__itemsr;   s    r>   __getstate__zParametricUMAP.__getstate__  s)     
----/
 
 	
r?   c                    | j                   Wt        j                  j                  |d      }| j                   j	                  |       |rt        dj                  |             | j                  Wt        j                  j                  |d      }| j                  j	                  |       |rt        dj                  |             | j                  Wt        j                  j                  |d      }| j                  j	                  |       |rt        dj                  |             i }|rdt        | d      r| j                  |d<   | `
t        | d	      r;t        | j                  d      r%| j                  j                  |d
<   | j                  `
t               5  t        d       t        j                  j                  |d      }t        |d      5 }	t        j                   | |	t        j"                         d d d        |rt        dj                  |             d d d        |r(d|v r
|d   | _
        d
|v r|d
   | j                  _
        y y y # 1 sw Y   XxY w# 1 sw Y   @xY w)Nencoder.keraszKeras encoder model saved to {}decoder.keraszKeras decoder model saved to {}zparametric_model.keraszKeras full model saved to {}	_raw_datarootknn_search_indexknnignore	model.pklwbz*Pickle of ParametricUMAP model saved to {})r   ospathjoinsaveprintr:   r   r+   r   r   r   r   r   openpickledumpHIGHEST_PROTOCOL)
r;   save_locationrZ   exclude_raw_dataencoder_outputdecoder_outputparametric_model_outputraw_datamodel_outputoutputs
             r>   r   zParametricUMAP.save  s    <<#WW\\-INLLn-7>>~NO <<#WW\\-INLLn-7>>~NO   ,&(ggll7'# !!&&'>?4;;<STU t[)#'>> Nt/0W%%{6 #'"7"7"A"A))3  	Y8$77<<{CLlD) CVD&&*A*ABCBII,WX	Y !!)&!1 2:5/%%/ ! C C	Y 	Ys$   8I&I:$II	II&c           	         || _         || _        || _        | j                  dk(  rtt        t        j
                  j                  t        |j                  d         t        |j                  d   |z        d            | _
        || j                     | _        y| j                  dk(  r)|t        d      || _
        || j                     | _        yt        d      )a  Add some points from a dataset X as "landmarks."

        Parameters
        ----------
        X : array, shape (n_samples, n_features)
            Old data to be retained.
        sample_pct : float, optional
            Percentage of old data to use as landmarks.
        sample_mode : str, optional
            Method for sampling points. Allows "uniform" and "predefined."
        landmark_loss_weight : float, optional
            Multiplier for landmark loss function.

        uniformr   F)replacepredeterminedNz'Choice of sample_mode is not supported.)
sample_pctsample_moder&   rI   rE   randomchoiceranger7   r.   prev_epoch_idxr'   r9   )r;   rQ   r   r   r&   idxs         r>   add_landmarkszParametricUMAP.add_landmarks   s    , %&$8!y("&		  !''!*%s1771:
+B'CU ! #D
 !"$"5"5 6D0{ !JKK&)#$%d&9&9$:! FGGr?   c                     d | _         y N)r'   r   s    r>   remove_landmarkszParametricUMAP.remove_landmarks+  s
     r?   c                     | j                   }t        | j                  d   | j                        }t	        ||      }t        j                  d| j                  d         }t
        j                  j                  |||      S )z(Exports trained parametric UMAP as ONNX.r   r   )	r   PumapNetr   r8   weight_copiertorchrandnonnxexport)r;   r   kmpmdummy_inputs        r>   to_ONNXzParametricUMAP.to_ONNX.  sf     \\diilD$5$562r" kk!TYYq\2zz  [-@@r?   )NNNr   )TF){Gz?r   r   N)__name__
__module____qualname__r   rO   rW   rJ   r^   rf   r   r   r   r   r   r   __classcell__r=   s   @r>   r   r   /   s     "'+/.1"&'( eN;L| IM@VD
,0(
&l\
4Br !)HV!Ar?   r   c                    | j                         }|j                          |j                  d   }||j                  d   dk  rd}nd}d|j                  |j                  |j                  j	                         t        |      z  k  <   |j                          ||j                  z  }|j                  }|j                  }|j                  }||||||fS )a<  
    gets elements of graphs, weights, and number of epochs per edge

    Parameters
    ----------
    graph_ : scipy.sparse.csr.csr_matrix
        umap graph of probabilities
    n_epochs : int
        maximum number of epochs per edge

    Returns
    -------
    graph scipy.sparse.csr.csr_matrix
        umap graph
    epochs_per_sample np.array
        number of epochs to train each sample for
    head np.array
        edge head
    tail np.array
        edge tail
    weight np.array
        edge weight
    n_vertices int
        number of vertices in graph
    r   r   '  i     rh   )	tocoosum_duplicatesr7   datarq   floateliminate_zerosrowcol)ru   rv   graph
n_verticesepochs_per_sampler{   r|   weights           r>   get_graph_elementsr   <  s    : LLNE	QJ;;q>U"HHDGEJJuzzUZZ^^-h?@A	 5::-99D99DZZF#T4CCr?   c                    |t        d      }t        |t              rG|dk(  rB|j                  dd|j                  d   |f      j                  t        j                        }|S t        |t              r|dk(  rt        | |||||      }dt        j                  |      j                         z  }	||	z  j                  t        j                        |j                  d	|j                  d   |g
      j                  t        j                        z   }|S t        j                  |      }
t        |
j                        dk(  rt        j                  |
d      j                  d   |
j                  d   k  rt        |
      }|j!                  |
d      \  }}t        j"                  |dddf         }|
|j                  d|z  |
j                  
      j                  t        j                        z   }|S |
}S )a*  Initialize embedding using graph. This is for direct embeddings.

    Parameters
    ----------
    init : str, optional
        Type of initialization to use. Either random, or spectral, by default "spectral"

    Returns
    -------
    embedding : np.array
        the initialized embedding
    Nr   g      $g      $@r   )lowhighsizespectral)rM   metric_kwds-C6?)scaler      axis)r   r   r   )r	   r,   strr   r7   ry   rE   rs   r   absrq   normalrG   rL   uniquer   querymean)r   r   r8   r-   rM   _metric_kwdsr   r   initialisation	expansion	init_datatreedistindnndists                  r>   init_embedding_from_graphr   r  s    )$/$!1 ((DA'E ) 

&
 	H C 
D#	4:#5 )$
 266.15577	#i/77JJ
A=   

&JJ
	
	*  HHTN	y1$yy+11!4yq7IIi( JJyAJ6	cad,%(;(;&.y )< )&$%	  &	r?   c                 @    t        j                  || d|z  z  z         S )a  
     convert distance representation into log probability,
        as a function of a, b params

    Parameters
    ----------
    distances : array
        euclidean distance between two points in embedding
    a : float, optional
        parameter based on min_dist, by default 1.0
    b : float, optional
        parameter based on min_dist, by default 1.0

    Returns
    -------
    float
        log probability in embedding space
    r   )r   log1p)	distancesabs      r>   #convert_distance_to_log_probabilityr     s$    & IIa)A..///r?   c                     |  t        j                  |      z  }d| z
   t        j                  |      |z
  z  |z  }||z   }|||fS )a  
    Compute cross entropy between low and high probability

    Parameters
    ----------
    probabilities_graph : array
        high dimensional probabilities
    log_probabilities_distance : array
        low dimensional log probabilities
    EPS : float, optional
        offset to ensure log is taken of a positive number, by default 1e-4
    repulsion_strength : float, optional
        strength of repulsion between negative samples, by default 1.0

    Returns
    -------
    attraction_term: float
        attraction term for cross entropy loss
    repellant_term: float
        repellent term for cross entropy loss
    cross_entropy: float
        cross entropy umap loss

    r   )r   log_sigmoid)probabilities_graphlog_probabilities_distanceEPSrepulsion_strengthattraction_termrepellant_termCEs          r>   compute_cross_entropyr	    sh    8 +*S__=W-XXO
 #
#$??569SS	U
	  
>	)BNB..r?   c                    | t        j                  t         j                  j                  |      t         j                  j	                         t         j                  j                  dd      t         j                  j                  dd      t         j                  j                  dd      t         j                  j                  t        |      d      g      } ||rt        j                  t         j                  j                  |f      t         j                  j                  dd      t         j                  j                  dd      t         j                  j                  dd      t         j                  j                  t        t        j                  |            dd	      t         j                  j                  |      g      }| |fS )
a`  
    Generates a set of keras networks for the encoder and decoder if one has not already
    been predefined.

    Parameters
    ----------
    encoder : keras.Sequential
        The encoder Keras network
    decoder : keras.Sequential
        the decoder Keras network
    n_components : int
        the dimensionality of the latent space
    dims : tuple of shape (dim1, dim2, dim3...)
        dimensionality of data
    n_data : number of elements in dataset
        # of elements in training dataset
    parametric_reconstruction : bool
        Whether the decoder is parametric or non-parametric
    init_embedding : array (optional, default None)
        The initial embedding, for nonparametric embeddings

    Returns
    -------
    encoder: keras.Sequential
        encoder keras network
    decoder: keras.Sequential
        decoder keras network
    N)r7   d   relu)units
activationz)r  namerecon)r  r  r  )
r/   
SequentiallayersInputFlattenDenser.   rE   prodReshape)r   r   r8   r   r   r   r   s          r>   r}   r}     sl   L """"".$$&"""@"""@"""@""\):"E	
 $&&LL&&l_&=LL&&SV&DLL&&SV&DLL&&SV&DLL&&!"''$-0w4 '  LL((.	G Gr?   c                 T    d  j                   dz  dkD  rdndj                   dz  dkD  rdnd fd}fd}t        ||      \  }	}
}}}} t        t        j                  |dg            t        j
                  ||
j                  d	            t        j
                  ||
j                  d	            }}t        j                  j                  t        t        |                  }||   j                  t        j                        }||   j                  t        j                        }t        j                  j                  j                  ||f      }|j                         }|j!                  d
      }|j#                  d      }|j%                  |t        j                  j&                  j(                        }|j%                  |t        j                  j&                  j(                        }|j+                  d      }|t        |      |||fS )a  
    Construct a tf.data.Dataset of edges, sampled by edge weight.

    Parameters
    ----------
    X : array, shape (n_samples, n_features)
        New data to be transformed.
    graph_ : scipy.sparse.csr.csr_matrix
        Generated UMAP graph
    n_epochs : int
        # of epochs to train each edge
    batch_size : int
        batch size
    parametric_reconstruction : bool
        Whether the decoder is parametric or non-parametric
    landmark_positions : array, shape (n_samples, n_components), optional
        The desired position in low-dimensional space of each sample in X.
        Points that are not landmarks should have nan coordinates.
    c                     | |   S r   r   )tensorindexs     r>   gather_indexz,construct_edge_dataset.<locals>.gather_indexN  s    e}r?   g&.>g      ?TFc                    rWt        j                  | gt         j                  g      d   }t        j                  |gt         j                  g      d   }n,t        j                  |       }t        j                  |      }| |||fS )Nr   )tfpy_functionrs   gather)edge_to	edge_fromedge_to_batchedge_from_batchrQ   r  gather_indices_in_pythons       r>   gather_Xz(construct_edge_dataset.<locals>.gather_XY  s    #NN<!W

|TUVWM nnq)nrzzlO IIa1M ii95O	=/AAr?   c                     dt        j                  d      i}dkD  r||d<   
r||d<   	Jr/t        j                  	| gt        j                  g      d   |d<   nt        j
                  	|       |d<   ||f|fS )Numapr   global_correlationrk   landmark_to)r   repeatr  r   rs   r!  )r"  r#  r$  r%  r6   r"   r  !gather_landmark_indices_in_pythonr$   rD   r   s        r>   get_outputsz+construct_edge_dataset.<locals>.get_outputse  s    3::a45)A-,9G()$ )6G$%)0)+ #5w"?"****& *,3Ew)O&/88r?   i  r.   r   )drop_remainder)num_parallel_callsr   )nbytesr   r.   rE   rr   r,  ry   r   permutationr   rL   rz   r  r   Datasetfrom_tensor_slicesshufflebatchmapexperimentalAUTOTUNEprefetch)rQ   ru   rv   r"   r   r$   rD   r'  r.  _r   r{   r|   r   r   edges_to_expedges_from_expshuffle_maskr   r  r&  r-  s   `  ````            @@@r>   rt   rt   1  s   :
 ()xx$'<t%%&--4s:D 	*
B9 9( <N<8A$fj
 T 234
 			$)0078
		$)0078 !L 99((s</@)ABL-44RXX>L#L188BN 77??55|^6TUL&&(L''.L%%j%FL##RWW%9%9%B%B $ L  ##(<(<(E(E $ L  ((,LS%6dFJJr?   c           
      b   	 t        j                  t        j                  |      d      j	                         }t        j
                  t        j                  |j                         d            }y# t        j                  t        j                  j                  t        t        j                  j                  t        j                  j                  t        t        t        f$ r%}t!        dj#                  | |             Y d}~yd}~wt$        $ r}t!        d|  d| d|        Y d}~yd}~ww xY w)	a  
    Checks if a dictionary item can be pickled

    Parameters
    ----------
    key : try
        key for dictionary element
    val : None
        element of dictionary

    Returns
    -------
    picklable: bool
        whether the dictionary item can be pickled
    base64zDid not pickle {}: {}NFzFailed at pickling :z due to T)codecsencoder   dumpsdecodeloadsPicklingErrorr  errorsInvalidArgumentError	TypeErrorInternalErrorNotFoundErrorOverflowErrorr   AttributeErrorr   r:   r9   )r   valpickledr;  es        r>   r   r     s      --S 18<CCELLw~~'7BC   	
		&&
		
			  	$++C34 "3%qXaS9:s%   A.A1 1A3D.$DD.D))D.c                    t         j                  j                  | d      }t        j                  t        |d            }|rt        dj                  |             t         j                  j                  | d      }t         j                  j                  |      r@t        j                  j                  |      |_        |rt        dj                  |             t         j                  j                  | d      }t         j                  j                  |      r>t        j                  j                  |      |_        t        dj                  |             t         j                  j                  | d      }t         j                  j                  |      r>t        j                  j                  |      |_        t        d	j                  |             |S )
a  
    Load a parametric UMAP model consisting of a umap-learn UMAP object
    and corresponding keras models.

    Parameters
    ----------
    save_location : str
        the folder that the model was saved in
    verbose : bool, optional
        Whether to print the loading steps, by default True

    Returns
    -------
    parametric_umap.ParametricUMAP
        Parametric UMAP objects
    r   rbz-Pickle of ParametricUMAP model loaded from {}r   z"Keras encoder model loaded from {}r   z"Keras decoder model loaded from {}r+   zKeras full model loaded from {})r   r   r   r   loadr   r   r:   existsr/   models
load_modelr   r   r+   )r   rZ   r   modelr   r   r   s          r>   load_ParametricUMAPrY    sB   ( 77<<{;LKKlD13E=DD\RS WW\\-AN	ww~~n%//?6==nMN WW\\-AN	ww~~n%//?299.IJ !ggll=:LM	ww~~-.!&!8!89P!Q/667NOPLr?   c                    t        j                  |       } | t        j                  | dd      z
  } |1| }t        j                  | t        j                  |      z  d|      }nUt        j                  || j                        }|t        j                  |dd      z
  }t        | j                        dz
  g}dg}t        j                  |d      }t        j                  |d      }t        j                  |       }t        j                  |      }t        j                  |      d   }t        j                  |      d   }t        j                  |||f      }	t        j                  |||f      }
t        j                  |||f      }	t        j                  |||f      }
t        j                  |	t        j                  |
            t        j                  || j                        z  }t        j                  ||dz  df      }t        j                  |      }t        j                  |t        j                  |      dd ||fz         }|st        j                  |d	      }|S )
zAdapted from TF Probability.r   Tr   keepdimsNri   r   int32r   r   )r   convert_to_tensorr   conjri   rL   r7   cast	transposerp   matmulsqueeze)xrR   r\  
event_axissample_axisx_permedy_permedn_events	n_samplesx_permed_flaty_permed_flatcovs               r>   
covariancero    s   a A	CHHQQ..AyXXa#((1+oAI
!!!1773T22!''lQ&'
#K*G4J((;g6K}}QH}}QHyy"1%H		(#A&I KK8Y*?@MKK8Y*?@MKK8Y*?@MKK8Y*?@M **]CMM-$@
ACHH177E C ++	1aC --
C
 ++		#rh11C
 kk#A&Jr?   c                     | t        j                  | dd      z  } ||t        j                  |dd      z  }t        | ||      S )Nr   Tr[  re  rR   r\  )r   stdro  rq  s      r>   correlationrs  .  sD    	CGGAA--A}D11Q22r?   c                   $     e Zd Zd Z fdZ xZS )StopGradientc                 ,    t        j                  |      S r   )r   stop_gradientr;   re  s     r>   callzStopGradient.call6  s      ##r?   c                      t         |          S r   )r   
get_config)r;   r=   s    r>   r{  zStopGradient.get_config9  s    w!##r?   )r   r   r   ry  r{  r   r   s   @r>   ru  ru  5  s    $$ $r?   ru  c                     t         j                  j                  t        j                  t        j
                  || z
  d                  S )Nr   r   )r/   activationsr  r   r   norm)rR   y_preds     r>   _default_landmark_lossr  =  s3     !!#((388FQJQ+G"HIIr?   c                   Z     e Zd Z	 	 	 	 	 	 	 	 	 d fd	Zd Zd	dZd
dZd Zd Zd Z	 xZ
S )rb   c                 B   t         |   |       || _        || _        || _        |
| _        |	| _        || _        || _        || _	        || _
        || _        || _        |xs! t        j                  j                  dd      }| j!                  |       t        j"                  j%                         | _        t        j(                  j+                         | _        |&t        j.                  j1                  d      | _        n|| _        |t4        | _        y || _        y )N)r  r   r   r   )r5   T)from_logits)r   r   r   r   r   r$   r   r`   umap_loss_aumap_loss_br!   r%   r&   r/   r3   r4   compiler  r  flattenr   SeedGeneratorseed_generatorlossesBinaryCrossentropyra   r  )r;   r  r  r`   r   r   r5   ra   r   r   r$   r!   r%   r&   r  r=   s                  r>   r   zUMAPModel.__init__D  s   " 	d#)B&.L+1 	2 %9!&& 0 0$8!K!1!1!6!6ts!6!K	y)||++-#ll88:,45:\\5T5T  6U 6D2 6WD2#$:D!$4D!r?   c                    |\  }}| j                  |      }| j                  |      }||d}| j                  rG| j                  r| j                  |      }n$| j                  t	        j
                  |            }||d<   |S )N)embedding_toembedding_fromrk   )r   r   r!   r   r   rw  )r;   inputsto_xfrom_xr  r  r  embedding_to_recons           r>   ry  zUMAPModel.callv  s    f||D)f- ),
 ))$$%)\\,%?" &*\\#2C2CL2Q%R"'9F#$r?   c                    g }| j                   D ]D  }|j                  t        j                  |t        j
                  j                                      F |j                  | j                  |             | j                  dkD  r!|j                  | j                  ||             | j                  r!|j                  | j                  ||             d|v r!|j                  | j                  ||             t        j                  |      S )Nr]  r   r+  )r  appendr   ra  r/   backendfloatx
_umap_lossr$   _global_correlation_lossr   _parametric_reconstruction_loss_landmark_losssum)r;   re  rR   r  sample_weightr<   r  losss           r>   compute_losszUMAPModel.compute_loss  s    KK 	HDMM#((4u}}/C/C/EFG	H 	doof-. ..2MM$776BC ))MM$>>q&IJ AMM$--a89wwvr?   c                    |d   }|d   }t        j                  || j                  d      }t        j                  || j                  d      }t        j                  |      d   }t        j
                  j                  t        j                  |      | j                        }t        j                  j                         dk(  rt        j                  ||      }	n||   }	t        j                  t        j                  ||z
  d      t        j                  ||	z
  d      gd      }
t        |
| j                   | j"                        }t        j                  |      d   }t        j                  t        j$                  |f      t        j&                  || j                  z  f      gd      }t)        |||      \  }}}t        j*                  |      S )	Nr  r  r   r   seed
tensorflowr   )r  )r   r,  r`   r7   r/   r   r5  aranger  configr  r  r!  rK   r~  r   r  r  oneszerosr	  r   )r;   r  r  r  r  embedding_neg_to
repeat_negrepeat_neg_batch_dimshuffled_indicesembedding_neg_fromdistance_embeddingr  r"   r  attraction_lossrepellant_lossce_losss                    r>   r  zUMAPModel._umap_loss  s   n- 01 ::lD4M4MTUVZZ0I0IPQR
"yy4Q7 <<//JJ+,43F3F 0 
 <<!\1!#:7G!H!+,<!= !__6Q?),>>QG 
 &I 0 0$2B2B&
"
 YY|,Q/
!oo*'		:(A(AACD 
 6K&16
2.' xx  r?   c           	      z   | j                  |d         }| j                  |d         }d } ||      } ||      }t        j                  |dd      }t        j                  |dd      }t        j                  |dd  |d d z
  d      }t        j                  |dd  |d d z
  d      }|t        j
                  j                  |j                  | j                  	      d
z  z   }t        j                  t        t        j                  |d      t        j                  |d                  }| | j                  z  S )Nr*  r  c                 ^    | t        j                  |       z
  t        j                  |       z  S r   )r   r   rr  )re  s    r>   z_scorez3UMAPModel._global_correlation_loss.<locals>.z_score  s!    Oswwqz11r?   ir   r   r   r   r  g|=)re  rR   )r  r   clipr~  r/   r   r   r7   r  rd  rs  rx   r$   )	r;   rR   r  re  z_xr  dxdzcorr_ds	            r>   r  z"UMAPModel._global_correlation_loss  s   LL/01ll6.12	2 AJcl HHQR hhsC$XXaeafn1-XXc!"gCR(q1 %,,&&rxxd6I6I&JURR #//"b1S__R5LM
 w<<<<r?   c                 P    | j                  |d   |d         }|| j                  z  S )Nrk   )ra   r   )r;   rR   r  r  s       r>   r  z)UMAPModel._parametric_reconstruction_loss  s6    55(8!9
 d@@@@r?   c                 N   |d   }t        j                  t        j                  |      t        j                  |d         |d         }t        j                  t        j                  |      t        j                  |      |      }| j	                  ||      | j
                  z  S )Nr+  r  )x1x2)r   whereisnanr~   r%   r&   )r;   rR   r  y_toclean_y_pred_to
clean_y_tos         r>   r  zUMAPModel._landmark_loss  s    
 ))IIdO~~f^45n%

 YYsyy3>>$3GDQ
 !!*o>''(	
r?   )	NNFr   rh   FNr   
umap_model)NNNN)r   )r   r   r   r   ry  r  r  r  r  r  r   r   s   @r>   rb   rb   C  sF     *."'.1'* 05d&.2!h=8A
r?   rb   c                   $     e Zd Z fdZd Z xZS )r   c                    t         t        |           t        j                  |d      | _        t        j                  dd      | _        t        j                  dd      | _        t        j                  d|      | _        y )Nr  )	r   r   r   nnLineardense1dense2dense3dense4)r;   indimoutdimr=   s      r>   r   zPumapNet.__init__  s]    (D*,))E3/DK))C-DK))C-DK))C0DK
r?   c                 6   | j                  |      }t        j                  |      }| j                  |      }t        j                  |      }| j	                  |      }t        j                  |      }| j                  |      }t        j                  |      }|S r   )r  Fr  r  r  r  rx  s     r>   forwardzPumapNet.forward%  so    AAq	AAAq	AAAq	AAAq	AHr?   )r   r   r   r   r  r   r   s   @r>   r   r     s    	(		r?   r   c                 P   | j                         }t        t        |      dz        }|j                         j	                         D cg c]  }| }}t        d      D cg c]  }|d|z     j                  d      d    }}|j                         }t        |      D ]:  }|d|z  dz      |||   dz   <   t        j                  |d|z           |||   dz   <   < |j	                         D ]  }	t        j                  ||	         ||	<    |j                  |       |S c c}w c c}w )a4  Copies weights from a parametric UMAP encoder to pytorch.
        Parameters
        ----------
        km : encoder extracted from parametric UMAP.
        pm: a PumapNet object. Will be overwritten.
        Returns
        -------
        pm : PumapNet Object.
            Net with copied weights.
        r      .r   r   z.biasz.weight)get_weightsr.   rL   
state_dictr   r   splitrE   rb  r   
from_numpyload_state_dict)
r   r   kweightsn_layersre  all_keysipm_namespyt_state_dictr   s
             r>   r   r   4  s0    >>#s8}q()  "}}3356!A66;@8DaHQUO))#.q1DD x 	TA4<QUQY4GN8A;0168ll8APQE?6SN8A;23	T "&&( 	HC"'"2"2>#3F"GN3	H 	>*	 7Ds   	D !D#)r   )r   r   )r   r   r   )T)NF)6numpyrE   r)  r   warningsr   r   r   numbar   r   umap.spectralr   sklearn.utilsr	   r
   rB  r   sklearn.neighborsr   r  r  ImportErrorr/   r   torch_importedr   torch.nnr  torch.nn.functional
functionalr  
torch.onnxtorchvisionr   r   r   r   r	  r}   rt   r   rY  ro  rs  r  Layerru  r  Modelrb   Moduler   r   r   r?   r>   <module>r     s     9 9  	 ) 9  $SG
 	##JAT JAZ3Dn NX7t0. SV(/d AV hKV%P,^8v3$5<<%% $JC
 C
T 299 JB 	O*  S		 G
HdRS   G	TU
;
<$FG  	FGNs)   C5 
D D) 5DD&)D;:D;