o
    XεiM                     @   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?      @	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__r   H/home/ubuntu/.local/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nanr4   list	transformconcatenatelenr6   metric_Xr   fitr8   Xyprecomputed_distancesrA   len_Xlen_landr:   r   r<   rL      s8   
zParametricUMAP.fitc                    r=   r>   )r$   rB   rC   rD   rE   r4   rF   rG   rH   rI   r6   rJ   rK   r   fit_transformrM   r:   r   r<   rS      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   verbose)r   r   predictrB   
asanyarrayrU   )r8   rN   r   r   r   r<   rG     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.
        rT   )	r   r   rV   rB   rW   r   rU   r   inverse_transform)r8   rN   r:   r   r<   rX   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#   r2   N)r   	UMAPModel_a_brY   r   r   r   r   r!   r   r"   r#   r2   r(   )r8   prlwr   r   r<   _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)dtypeforce_all_finiter@   r   reconstruction)epochssteps_per_epochvalidation_data_history)rU   ).rJ   rK   r   rB   r4   rI   reshaperF   r   maxminr   r	   float32construct_edge_datasetgraph_n_epochsr   r!   edge_weightr   rD   expand_dimsastypeint64headtailr(   prepare_networksr   r   r5   r_   r+   r    r&   
zeros_likerL   r/   r'   hasattrhistoryrg   keysrV   rU   )r8   rN   rn   initr*   rA   edge_datasetn_edgesrs   rt   init_embeddingn_datare   rf   rx   key	embeddingr   r   r<   _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 ))r2   r   r   r(   N)should_pickle).0kvr   r   r<   	<genexpr>  s    z.ParametricUMAP.__getstate__.<locals>.<genexpr>)dict__dict__itemsr8   r   r   r<   __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printr7   r   r(   r   r   openpickledumpHIGHEST_PROTOCOL)r8   save_locationrU   encoder_outputdecoder_outputparametric_model_outputmodel_outputoutputr   r   r<   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)replacepredeterminedNz'Choice of sample_mode is not supported.)
sample_pctsample_moder#   rF   rB   randomchoiceranger4   r+   prev_epoch_idxr$   r6   )r8   rN   r   r   r#   idxr   r   r<   add_landmarks  s(   

zParametricUMAP.add_landmarksc                 C   s
   d | _ d S N)r$   r   r   r   r<   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   )	r   PumapNetr   r5   weight_copiertorchrandnonnxexport)r8   r   kmpmdummy_inputr   r   r<   to_ONNX$  s
   
zParametricUMAP.to_ONNX)NNNr   T)r   r   r   N)__name__
__module____qualname__r   rL   rS   rG   rX   r_   r   r   r   r   r   r   __classcell__r   r   r:   r<   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     r`   )	tocoosum_duplicatesr4   datari   floateliminate_zerosrowcol)rm   rn   graph
n_verticesepochs_per_samplers   rt   weightr   r   r<   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   )rJ   metric_kwds-C6?)scaler      axis)r   r   r   )r   r)   strr   r4   rq   rB   rk   r   absri   normalrD   rI   uniquer
   querymean)	_raw_datar   r5   r*   rJ   _metric_kwdsrz   r   initialisation	expansion	init_datatreedistindnndistr   r   r<   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   )r   log1p)	distancesabr   r   r<   #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   )r   log_sigmoid)probabilities_graphlog_probabilities_distanceEPSrepulsion_strengthattraction_termrepellant_termCEr   r   r<   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)r4   d   relu)units
activationz)r   namerecon)r   r   r   )	r,   
SequentiallayersInputFlattenDenserB   productReshape)r   r   r5   r   r~   r   r}   r   r   r<   ru     s0   &
ru   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   )tensorindexr   r   r<   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_functionrk   gather)edge_to	edge_fromedge_to_batchedge_from_batch)rN   r  gather_indices_in_pythonr   r<   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_correlationrc   landmark_to)r   repeatr  r  rk   r  )r  r	  r
  r  r3   )r   r  !gather_landmark_indices_in_pythonr!   rA   r   r   r<   get_outputs[  s   
z+construct_edge_dataset.<locals>.get_outputsi  r+   r   )drop_remainder)num_parallel_callsr   )nbytesr   r+   rB   rj   r  rq   r   permutationr   rI   rr   r  r   Datasetfrom_tensor_slicesshufflebatchmapexperimentalAUTOTUNEprefetch)rN   rm   rn   r   r   r!   rA   r  r  _r   rs   rt   r   r   edges_to_expedges_from_expshuffle_maskr{   r   )rN   r   r  r  r  r!   rA   r   r<   rl   '  s<   



rl   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  errorsInvalidArgumentError	TypeErrorInternalErrorNotFoundErrorOverflowErrorr   AttributeErrorr   r7   r6   )r   valpickledr   er   r   r<   r     s,   
r   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 {})r   r   r   r   loadr   r   r7   existsr,   models
load_modelr   r   r(   )r   rU   r   modelr   r   r   r   r   r<   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ra   r   int32r   r   )r   convert_to_tensorr   conjra   rI   r4   cast	transposerh   matmulsqueeze)xrO   r>  
event_axissample_axisx_permedy_permedn_events	n_samplesx_permed_flaty_permed_flatcovr   r   r<   
covariance  sD   




rQ  c                 C   s>   | t j| ddd } |d ur|t j|ddd }t| ||dS )Nr   Tr=  rG  rO   r>  )r   stdrQ  rR  r   r   r<   correlation$  s   rT  c                   @   s   e Zd Zdd ZdS )StopGradientc                 C   s
   t |S r   )r   stop_gradientr8   rG  r   r   r<   call,  r   zStopGradient.callN)r   r   r   rX  r   r   r   r<   rU  +  s    rU  c                 C   s    t jttj||  ddS )Nr   r   )r,   activationsr   r   r   norm)rO   y_predr   r   r<   _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 )r[   NFr   r`   
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   )r2   T)from_logits)r   r   r   r   r   r!   r   rY   umap_loss_aumap_loss_br   r"   r#   r,   r0   r1   compiler   r   flattenr   SeedGeneratorseed_generatorlossesBinaryCrossentropyrZ   r\  )r8   r_  r`  rY   r   r   r2   rZ   r   r   r!   r   r"   r#   r   r:   r   r<   r   7  s2   


zUMAPModel.__init__c                 C   sZ   |\}}|  |}|  |}||d}| jr+| jr| |}n| t|}||d< |S )N)embedding_toembedding_fromrc   )r   r   r   r   r   rV  )r8   inputsto_xfrom_xrg  rh  r[  embedding_to_reconr   r   r<   rX  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  )re  appendr   rC  r,   backendfloatx
_umap_lossr!   _global_correlation_lossr   _parametric_reconstruction_loss_landmark_losssum)r8   rG  rO   r[  sample_weightr9   re  lossr   r   r<   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 )	Nrg  rh  r   r   seed
tensorflowr   )r   )r   r  rY   r4   r,   r   r  arangerd  configrn  r  r  rH   rZ  r   r_  r`  oneszerosr   r   )r8   r[  r   rg  rh  embedding_neg_to
repeat_negrepeat_neg_batch_dimshuffled_indicesembedding_neg_fromdistance_embeddingr   r   r   attraction_lossrepellant_lossce_lossr   r   r<   rp    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  rg  c                 S   s   | t |  t |  S r   )r   r   rS  )rG  r   r   r<   z_score  s   z3UMAPModel._global_correlation_loss.<locals>.z_scoreir   r   r   r   rx  g|=)rG  rO   )rb  r   cliprZ  r,   r   r   r4   rd  rF  rT  rp   r!   )	r8   rO   r[  rG  z_xr  dxdzcorr_dr   r   r<   rq    s   ""z"UMAPModel._global_correlation_lossc                 C   s   |  |d |d }|| j S )Nrc   )rZ   r   )r8   rO   r[  rv  r   r   r<   rr    s   
z)UMAPModel._parametric_reconstruction_lossc                 C   sZ   |d }t jt |t |d |d d}t jt |t ||d}| ||| j S )Nr  rg  )x1x2)r   whereisnanrv   r"   r#   )r8   rO   r[  y_toclean_y_pred_to
clean_y_tor   r   r<   rs    s   
zUMAPModel._landmark_loss)	NNFr   r`   FNr   r]  )NNNN)r   )r   r   r   r   rX  rw  rp  rq  rr  rs  r   r   r   r:   r<   r[   6  s"    2

4r[   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   nnLineardense1dense2dense3dense4)r8   indimoutdimr:   r   r<   r     s   zPumapNet.__init__c                 C   sT   |  |}t|}| |}t|}| |}t|}| |}t|}|S r   )r  Fr   r  r  r  rW  r   r   r<   forward  s   







zPumapNet.forward)r   r   r   r   r  r   r   r   r:   r<   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   )r   rG  r   r   r<   
<listcomp>6  s    z!weight_copier.<locals>.<listcomp>c                    s"   g | ]} d |   dd qS )r   .r   )split)r   iall_keysr   r<   r  7  s   "    r   z.biasz.weight)get_weightsr+   rI   
state_dictry   r   rB   rD  r   
from_numpyload_state_dict)r   r   kweightsn_layerspm_namespyt_state_dictr  r   r   r  r<   r   '  s    
r   )r   )r   r   )r   r   r   r   )NF)6numpyrB   r  r   warningsr   r   r   numbar   r   umap.spectralr   sklearn.utilsr   r	   r&  r   sklearn.neighborsr
   rz  r  ImportErrorr,   r   torch_importedr   torch.nnr  torch.nn.functional
functionalr  
torch.onnxtorchvisionr   r   r   r   r   ru   rl   r   r<  rQ  rT  r   LayerrU  r\  Modelr[   Moduler   r   r   r   r   r<   <module>   s~    

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

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