o
    .ѹgM                     @   s  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 zd dlZW n eyP   ed ed	dw zd dlZd d
lmZ W n eym   ed eddw dZz!d dlZd dlmZ d dlm  mZ d dl Zd dl Zd dl!Z!W n ey   ed dZY nw G dd deZ"dd Z#	d3ddZ$d4ddZ%	d5ddZ&	d6ddZ'	d6dd Z(d!d" Z)d7d#d$Z*d8d%d&Z+d8d'd(Z,G d)d* d*ej-j.Z/d+d, Z0G d-d. d.ej1Z2erG d/d0 d0ej3Z4d1d2 Z5dS 	 dS )9    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                       s   e Zd Zddddddddddddi f fdd	Zd  fdd	Z	d  fd	d
	Zd!ddZ fddZdd Zd!ddZ	dd Z
d"ddZ				d#ddZdd Zdd Z  ZS )$ParametricUMAPNF      ?r   c                    s   t  jd
i | || _|| _|| _|| _|| _|| _|| _|| _	d| _
|
| _|| _|| _d| _d| _|	| _|| _d| _t| jtrItj| j d| _tjjddd| _| jdurt|jd jd | jkrvt d	!|jd jd | jdS dS )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?      @Z	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_XZwindow_valsreconstruction_validationkeras_fit_kwargsparametric_model
isinstancerandom_stateintkerasutilsZ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__r   X/Users/admin/.pyenv/versions/3.10.0/lib/python3.10/site-packages/umap/parametric_umap.pyr   0   sD   4
zParametricUMAP.__init__c                       | j du|du @ r+tttjtjgg|jd  t| | j  }t|| j f}|durFt	|}t	|}||krFt
d| d| d| jdkr_|du rSt
d|| _t j|||dS t j|||d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nanr1   list	transformconcatenatelenr3   metric_Xr   fitr5   XyZprecomputed_distancesr>   Zlen_XZlen_landr7   r   r9   rI      s8   
zParametricUMAP.fitc                    r:   r;   )r#   r?   r@   rA   rB   r1   rC   rD   rE   rF   r3   rG   rH   r   fit_transformrJ   r7   r   r9   rM      s8   
zParametricUMAP.fit_transformc                 C   s(   |r|n| j }| jjt||| jd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   verboseN)r   r   predictr?   
asanyarrayrO   )r5   rK   r   r   r   r9   rD     s   zParametricUMAP.transformc                    s.   | j r| jjt|| j| jd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.
        rN   N)	r   r   rP   r?   rQ   r   rO   r   inverse_transform)r5   rK   r7   r   r9   rR   2  s
   z ParametricUMAP.inverse_transformc                 C   sF   | j }t| j| j| j| j| j| j| j|| j	| j
| j| j| jd| _dS )zDefine the model in keras)negative_sample_rater   r   !parametric_reconstruction_loss_fnr   r   r    r   r!   r"   r/   N)r   	UMAPModelZ_a_brS   r   r   r   r   r    r   r!   r"   r/   r&   )r5   Zprlwr   r   r9   _define_modelF  s    zParametricUMAP._define_modelc              	   C   s:  | j dkr| j}| jd u rt|d g| _nt| jdkr,t|t|gt| j }| jrAt	|dks=t
|dk rAtd |d urMt|tjdd}t|| j| j| j| j| j|d	\}| _}}}	| _tt|tjd
| _tt|	tjd
| _| jd u rd }
t|}t| j| j| j| j|| j|
\| _| _|    t!|| j | j" }| jr| j#d urt| jdkrt| j#t| j#gt| j | _#| j#t$| j#fd| j#if}nd }| jj%|f| j"| j& ||d| j'}t(| ds|j)| _*n|j)+ D ]}| j*|  |j)| 7  < q | jj,|| j-d}|i fS )Nr<   r   r   r           zMData should be scaled to the range 0-1 for cross-entropy reconstruction loss.z	allow-nan)dtypeZforce_all_finiter=   r   reconstruction)Zepochssteps_per_epochvalidation_data_history)rO   ).rG   rH   r   r?   r1   rF   reshaperC   r   maxminr   r	   float32construct_edge_datasetgraph_n_epochsr   r    Zedge_weightr   rA   expand_dimsastypeint64headtailr&   prepare_networksr   r   r2   rW   r)   r   r$   
zeros_likerI   r,   r%   hasattrhistoryr]   keysrP   rO   )r5   rK   rd   initr(   r>   edge_datasetZn_edgesrh   ri   init_embeddingn_datar[   r\   rm   key	embeddingr   r   r9   _fit_embed_dataY  s   

"





zParametricUMAP._fit_embed_datac                 C   s   t dd | j D S )Nc                 s   s.    | ]\}}t ||r|d vr||fV  qdS ))r/   r   r   r&   N)should_pickle).0kvr   r   r9   	<genexpr>  s    
z.ParametricUMAP.__getstate__.<locals>.<genexpr>)dict__dict__itemsr5   r   r   r9   __getstate__  s   zParametricUMAP.__getstate__Tc              	   C   s@  | j d urtj|d}| j | |rtd| | jd ur6tj|d}| j| |r6td| | jd urQtj|d}| j| |rQtd| t	 B t
d tj|d}t|d	}t| |tj W d    n1 sxw   Y  |rtd
| W d    d S W d    d S 1 sw   Y  d S )Nencoder.keraszKeras encoder model saved to {}decoder.keraszKeras decoder model saved to {}zparametric_model.keraszKeras full model saved to {}ignore	model.pklwbz*Pickle of ParametricUMAP model saved to {})r   ospathjoinsaveprintr4   r   r&   r   r   openpickledumpHIGHEST_PROTOCOL)r5   save_locationrO   encoder_outputdecoder_outputparametric_model_outputmodel_outputoutputr   r   r9   r     s8   


"zParametricUMAP.save{Gz?uniformc                 C   s   || _ || _|| _| jdkr.ttjjt|jd t	|jd | dd| _
|| j
 | _dS | jdkrF|du r;td|| _
|| j
 | _dS 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.

        r   r   F)replaceZpredeterminedNz'Choice of sample_mode is not supported.)
sample_pctsample_moder"   rC   r?   randomchoiceranger1   r)   Zprev_epoch_idxr#   r3   )r5   rK   r   r   r"   idxr   r   r9   add_landmarks  s(   

zParametricUMAP.add_landmarksc                 C   s
   d | _ d S N)r#   r~   r   r   r9   remove_landmarks!     
zParametricUMAP.remove_landmarksc                 C   sD   | j }t| jd | j}t||}td| jd }tj|||S )z(Exports trained parametric UMAP as ONNX.r   r   N)	r   PumapNetr   r2   weight_copiertorchZrandnZonnxZexport)r5   r   kmpmZdummy_inputr   r   r9   to_ONNX$  s
   
zParametricUMAP.to_ONNX)NNNr   T)r   r   r   N)__name__
__module____qualname__r   rI   rM   rD   rR   rW   ru   r   r   r   r   r   __classcell__r   r   r7   r9   r   /   s>    gA
E
n
	%
/r   c                 C   s   |   }|  |jd }|du r|jd dkrd}nd}d|j|j|j t| k < |  ||j }|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   Nr   '  i     rX   )	ZtocooZsum_duplicatesr1   datar_   floatZeliminate_zerosrowcol)rc   rd   graph
n_verticesepochs_per_samplerh   ri   weightr   r   r9   get_graph_elements2  s   

r   spectralc                 C   sF  |du rt d}t|tr$|dkr$|jdd|jd |fdtj}|S t|trZ|dkrZt| |||||d}dt	|
  }	||	 tj|jd	|jd |gd
tj }|S t|}
t|
jdkrtj|
ddjd |
jd k rt|
}|j|
dd\}}t|dddf }|
|jd| |
jd
tj }|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sizer   )rG   Zmetric_kwds-C6?)Zscaler      axis)rx   r   r   )r   r'   strr   r1   rf   r?   ra   r   absr_   normalrA   rF   uniquer
   querymean)Z	_raw_datar   r2   r(   rG   Z_metric_kwdsro   rt   ZinitialisationZ	expansionZ	init_datatreedistindZnndistr   r   r9   init_embedding_from_graphh  sX   $

r   r   c                 C   s   t || d|    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   N)r   log1p)Z	distancesabr   r   r9   #convert_distance_to_log_probability  s   r   r   c                 C   s>   |  t | }d|   t ||  | }|| }|||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   N)r   Zlog_sigmoid)probabilities_graphlog_probabilities_distanceZEPSrepulsion_strengthZattraction_termZrepellant_termZCEr   r   r9   compute_cross_entropy  s   
r   c                 C   s   | du r/t t jj|dt j t jjdddt jjdddt jjdddt jj|ddg} |du rf|rft t jj|fdt jjdddt jjdddt jjdddt jjt|ddd	t 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)r1   d   relu)units
activationz)r   nameZrecon)r   r   r   )	r*   Z
SequentiallayersZInputFlattenZDenser?   productZReshape)r   r   r2   r   rr   r   rq   r   r   r9   rj     s0   &
rj   c                    sd  dd  j d dkrdnddurj d dkrdnd fdd	}fd
d}t||\}	}
}}}}du rItt|dgt||
dt||
d}}tjt	t
|}|| tj}|| tj}tjj||f}| }|d}|jdd}|j|tjjjd}|j|tjjjd}|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   s   | | S r   r   )Ztensorindexr   r   r9   gather_indexD  s   z,construct_edge_dataset.<locals>.gather_indexg&.>g      ?TFNc                    s^   rt  | gt jgd }t  |gt jgd }nt  | }t  |}| |||fS )Nr   )tfpy_functionra   gather)edge_to	edge_fromedge_to_batchedge_from_batch)rK   r   gather_indices_in_pythonr   r9   gather_XO  s   z(construct_edge_dataset.<locals>.gather_Xc                    st   dt d i}dkr||d< r||d< d ur4r,t| gtjgd |d< nt| |d< ||f|fS )Numapr   global_correlationrZ   landmark_to)r   repeatr   r   ra   r   )r   r   r   r   r0   )r   r   !gather_landmark_indices_in_pythonr    r>   r   r   r9   get_outputs[  s   
z+construct_edge_dataset.<locals>.get_outputsi  r)   r   )Zdrop_remainder)Znum_parallel_callsr   )nbytesr   r)   r?   r`   r   rf   r   Zpermutationr   rF   rg   r   r   ZDatasetZfrom_tensor_slicesshufflebatchmapZexperimentalZAUTOTUNEZprefetch)rK   rc   rd   r   r   r    r>   r   r   _r   rh   ri   r   r   Zedges_to_expZedges_from_expZshuffle_maskrp   r   )rK   r   r   r   r   r    r>   r   r9   rb   '  s<   



rb   c                 C   s   zt t|d }tt | d}W dS  tjtjj	t
tjjtjjtttfyC } ztd| | W Y d}~dS d}~w tyb } ztd|  d| d|  W Y d}~dS d}~w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   errorsZInvalidArgumentError	TypeErrorZInternalErrorZNotFoundErrorOverflowErrorr   AttributeErrorr   r4   r3   )rs   valZpickledr   er   r   r9   rv     s,   
rv   c                 C   s   t j| d}tt|d}|rtd| t j| d}t j|r5t	j
||_|r5td| t j| d}t j|rPt	j
||_td| t j| d}t j|rkt	j
||_td	| |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 {}N)r   r   r   r   loadr   r   r4   existsr*   modelsZ
load_modelr   r   r&   )r   rO   r   modelr   r   r   r   r   r9   load_ParametricUMAP  s$   r  c                 C   s  t | } | t j| ddd } |du r#| }t j| t | d|d}nt j|| jd}|t j|ddd }t| jd g}dg}t j|dd}t j|dd}t | }t |}t |d }t |d }t 	|||f}	t 	|||f}
t 	|||f}	t 	|||f}
t 
|	t |
t || j }t 	||d df}t |}t 	|t |dd ||f }|st j|dd	}|S )
zAdapted from TF Probability.r   Tr   keepdimsNrY   r   Zint32r   r   )r   Zconvert_to_tensorr   ZconjrY   rF   r1   cast	transposer^   matmulsqueeze)xrL   r  Z
event_axisZsample_axisZx_permedZy_permedZn_eventsZ	n_samplesZx_permed_flatZy_permed_flatZcovr   r   r9   
covariance  sD   




r  c                 C   s>   | t j| ddd } |d ur|t j|ddd }t| ||dS )Nr   Tr  r  rL   r  )r   stdr  r  r   r   r9   correlation$  s   r  c                   @   s   e Zd Zdd ZdS )StopGradientc                 C   s
   t |S r   )r   stop_gradientr5   r  r   r   r9   call,  r   zStopGradient.callN)r   r   r   r  r   r   r   r9   r  +  s    r  c                 C   s    t jttj||  ddS )Nr   r   )r*   Zactivationsr   r   r   norm)rL   y_predr   r   r9   _default_landmark_loss0  s    r  c                       sd   e Zd Z									d fdd	Zdd	 Zdd
dZdddZdd Zdd Zdd Z	  Z
S )rU   NFr   rX   
umap_modelc                    s   t  j|d || _|| _|| _|
| _|	| _|| _|| _|| _	|| _
|| _|| _|p1tjjddd}| j|d tj | _tj | _|d u rQtjjdd| _n|| _|d u r]t| _d S || _d S )N)r   r   r   r   )r/   T)Zfrom_logits)r   r   r   r   r   r    r   rS   umap_loss_aumap_loss_br   r!   r"   r*   r-   r.   compiler   r   flattenr   ZSeedGeneratorseed_generatorlossesZBinaryCrossentropyrT   r  )r5   r  r  rS   r   r   r/   rT   r   r   r    r   r!   r"   r   r7   r   r9   r   7  s2   


zUMAPModel.__init__c                 C   sZ   |\}}|  |}|  |}||d}| jr+| jr| |}n| t|}||d< |S )N)embedding_toembedding_fromrZ   )r   r   r   r   r   r  )r5   inputsZto_xZfrom_xr  r  r  Zembedding_to_reconr   r   r9   r  i  s   

zUMAPModel.callc                 K   s   g }| j D ]}|tj|tj d q|| | | jdkr+|| 	|| | j
r7|| || d|v rD|| || t|S )Nr  r   r   )r  appendr   r  r*   backendZfloatx
_umap_lossr    _global_correlation_lossr   _parametric_reconstruction_loss_landmark_losssum)r5   r  rL   r  Zsample_weightr6   r  lossr   r   r9   compute_loss|  s   


zUMAPModel.compute_lossc                 C   s  |d }|d }t j|| jdd}t j|| jdd}t |d }tjjt || jd}tj	
 dkr;t||}	n|| }	t jt j|| ddt j||	 ddgdd}
t|
| j| j}t |d }t jt |ft || j fgdd}t|||d\}}}t |S )	Nr  r  r   r   seed
tensorflowr   )r   )r   r   rS   r1   r*   r   r   Zaranger  configr"  r   r   rE   r  r   r  r  Zoneszerosr   r   )r5   r  r   r  r  Zembedding_neg_toZ
repeat_negZrepeat_neg_batch_dimZshuffled_indicesZembedding_neg_fromZdistance_embeddingr   r   r   Zattraction_lossZrepellant_lossZce_lossr   r   r9   r#    sB   	

	
zUMAPModel._umap_lossc           	      C   s   |  |d }|  |d }dd }||}||}t|dd}t|dd}tj|dd  |d d  dd	}tj|dd  |d d  dd	}|tjj|j| jd
d  }t	t
t|dt|dd}| | j S )Nr   r  c                 S   s   | t |  t |  S r   )r   r   r  )r  r   r   r9   z_score  s   z3UMAPModel._global_correlation_loss.<locals>.z_scoreir   r   r   r   r*  g|=)r  rL   )r  r   Zclipr  r*   r   r   r1   r  r
  r  re   r    )	r5   rL   r  r  Zz_xr/  ZdxZdzZcorr_dr   r   r9   r$    s   ""z"UMAPModel._global_correlation_lossc                 C   s   |  |d |d }|| j S )NrZ   )rT   r   )r5   rL   r  r(  r   r   r9   r%    s   
z)UMAPModel._parametric_reconstruction_lossc                 C   sZ   |d }t jt |t |d |d d}t jt |t ||d}| ||| j S )Nr   r  )x1Zx2)r   whereisnanrk   r!   r"   )r5   rL   r  Zy_toZclean_y_pred_toZ
clean_y_tor   r   r9   r&    s   
zUMAPModel._landmark_loss)	NNFr   rX   FNr   r  )NNNN)r   )r   r   r   r   r  r)  r#  r$  r%  r&  r   r   r   r7   r9   rU   6  s"    2

4rU   c                       s$   e Zd Z fddZdd Z  ZS )r   c                    sJ   t t|   t|d| _tdd| _tdd| _td|| _d S )Nr   )	r   r   r   nnZLineardense1dense2dense3dense4)r5   ZindimZoutdimr7   r   r9   r     s   zPumapNet.__init__c                 C   sT   |  |}t|}| |}t|}| |}t|}| |}t|}|S r   )r4  Fr   r5  r6  r7  r  r   r   r9   forward  s   







zPumapNet.forward)r   r   r   r   r9  r   r   r   r7   r9   r     s    r   c                    s   |   }tt|d }dd |  D   fddtdD }| }t|D ]}|d| d  ||| d < t|d|  ||| d < q*| D ]}t	|| ||< qN|
| |S )
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   c                 S   s   g | ]}|qS r   r   )rw   r  r   r   r9   
<listcomp>6  s    z!weight_copier.<locals>.<listcomp>c                    s"   g | ]} d |   dd qS )r   .r   )split)rw   iall_keysr   r9   r:  7  s   "    r   z.biasz.weightN)Zget_weightsr)   rF   Z
state_dictrn   r   r?   r  r   Z
from_numpyZload_state_dict)r   r   ZkweightsZn_layersZpm_namesZpyt_state_dictr=  rs   r   r>  r9   r   '  s    
r   )r   )r   r   )r   r   r   r   )NF)6Znumpyr?   r   r   warningsr   r   r   Znumbar   r   Zumap.spectralr   Zsklearn.utilsr   r	   r   r   Zsklearn.neighborsr
   r,  r   ImportErrorr*   r   Ztorch_importedr   Ztorch.nnr3  Ztorch.nn.functionalZ
functionalr8  Z
torch.onnxZtorchvisionr   r   r   r   r   rj   rb   rv   r  r  r  r   ZLayerr  r  ZModelrU   Moduler   r   r   r   r   r9   <module>   s~    


    7

:
2
K
k
(
/
; K%!