# Path: scvelo/preprocessing/neighbors.py
# def get_connectivities(
#     adata, mode="connectivities", n_neighbors=None, recurse_neighbors=False
# ):
#     if "neighbors" in adata.uns.keys():
#         C = get_neighs(adata, mode)
#         if n_neighbors is not None and n_neighbors < get_n_neighs(adata):
#             if mode == "connectivities":
#                 C = select_connectivities(C, n_neighbors)
#             else:
#                 C = select_distances(C, n_neighbors)
#         connectivities = C > 0
#         with warnings.catch_warnings():
#             warnings.simplefilter("ignore")
#             connectivities.setdiag(1)
#             if recurse_neighbors:
#                 connectivities += connectivities.dot(connectivities * 0.5)
#                 connectivities.data = np.clip(connectivities.data, 0, 1)
#             connectivities = connectivities.multiply(1.0 / connectivities.sum(1))
#         return connectivities.tocsr().astype(np.float32)
#     else:
#         return None
# 
# def get_neighs(adata, mode="distances"):
#     if hasattr(adata, "obsp") and mode in adata.obsp.keys():
#         return adata.obsp[mode]
#     elif "neighbors" in adata.uns.keys() and mode in adata.uns["neighbors"]:
#         return adata.uns["neighbors"][mode]
#     else:
#         raise ValueError("The selected mode is not valid.")
# 
# Path: scvelo/tools/utils.py
# def normalize(X):
#     with warnings.catch_warnings():
#         warnings.simplefilter("ignore")
#         if issparse(X):
#             return X.multiply(csr_matrix(1.0 / np.abs(X).sum(1)))
#         else:
#             return X / X.sum(1)


import warnings
import numpy as np
import pandas as pd
from scipy.sparse import csr_matrix, SparseEfficiencyWarning
from scipy.spatial.distance import pdist, squareform
from scvelo.preprocessing.neighbors import get_connectivities, get_neighs
from .utils import normalize
        from sklearn.neighbors import NearestNeighbors
                graph_neg = adata.obsp[f"{vkey}_graph_neg"]
        else:
            graph = csr_matrix(adata.uns[f"{vkey}_graph"]).copy()
            if f"{vkey}_graph_neg" in adata.uns.keys():
                graph_neg = adata.uns[f"{vkey}_graph_neg"]

    if basis_constraint is not None and f"X_{basis_constraint}" in adata.obsm.keys():

        neighs = NearestNeighbors(n_neighbors=100)
        neighs.fit(adata.obsm[f"X_{basis_constraint}"])
        basis_graph = neighs.kneighbors_graph(mode="connectivity") > 0
        graph = graph.multiply(basis_graph)

    if self_transitions:
        confidence = graph.max(1).A.flatten()
        ub = np.percentile(confidence, 98)
        self_prob = np.clip(ub - confidence, 0, 1)
        graph.setdiag(self_prob)

    T = np.expm1(graph * scale)  # equivalent to np.exp(graph.A * scale) - 1
    if graph_neg is not None:
        graph_neg = adata.uns[f"{vkey}_graph_neg"]
        if use_negative_cosines:
            T -= np.expm1(-graph_neg * scale)
        else:
            T += np.expm1(graph_neg * scale)
            T.data += 1

    # weight direct and indirect (recursed) neighbors
    if weight_indirect_neighbors is not None and weight_indirect_neighbors < 1:

# Path: scvelo/preprocessing/neighbors.py
# def get_connectivities(
#     adata, mode="connectivities", n_neighbors=None, recurse_neighbors=False
# ):
#     if "neighbors" in adata.uns.keys():
#         C = get_neighs(adata, mode)
#         if n_neighbors is not None and n_neighbors < get_n_neighs(adata):
#             if mode == "connectivities":
#                 C = select_connectivities(C, n_neighbors)
#             else:
#                 C = select_distances(C, n_neighbors)
#         connectivities = C > 0
#         with warnings.catch_warnings():
#             warnings.simplefilter("ignore")
#             connectivities.setdiag(1)
#             if recurse_neighbors:
#                 connectivities += connectivities.dot(connectivities * 0.5)
#                 connectivities.data = np.clip(connectivities.data, 0, 1)
#             connectivities = connectivities.multiply(1.0 / connectivities.sum(1))
#         return connectivities.tocsr().astype(np.float32)
#     else:
#         return None
# 
# def get_neighs(adata, mode="distances"):
#     if hasattr(adata, "obsp") and mode in adata.obsp.keys():
#         return adata.obsp[mode]
#     elif "neighbors" in adata.uns.keys() and mode in adata.uns["neighbors"]:
#         return adata.uns["neighbors"][mode]
#     else:
#         raise ValueError("The selected mode is not valid.")
# 
# Path: scvelo/tools/utils.py
# def normalize(X):
#     with warnings.catch_warnings():
#         warnings.simplefilter("ignore")
#         if issparse(X):
#             return X.multiply(csr_matrix(1.0 / np.abs(X).sum(1)))
#         else:
#             return X / X.sum(1)


# Path: scvelo/tools/transition_matrix.py
import warnings
import numpy as np
import pandas as pd
from scipy.sparse import csr_matrix, SparseEfficiencyWarning
from scipy.spatial.distance import pdist, squareform
from scvelo.preprocessing.neighbors import get_connectivities, get_neighs
from .utils import normalize
        from sklearn.neighbors import NearestNeighbors

                graph_neg = adata.obsp[f"{vkey}_graph_neg"]
        else:
            graph = csr_matrix(adata.uns[f"{vkey}_graph"]).copy()
            if f"{vkey}_graph_neg" in adata.uns.keys():
                graph_neg = adata.uns[f"{vkey}_graph_neg"]

    if basis_constraint is not None and f"X_{basis_constraint}" in adata.obsm.keys():

        neighs = NearestNeighbors(n_neighbors=100)
        neighs.fit(adata.obsm[f"X_{basis_constraint}"])
        basis_graph = neighs.kneighbors_graph(mode="connectivity") > 0
        graph = graph.multiply(basis_graph)

    if self_transitions:
        confidence = graph.max(1).A.flatten()
        ub = np.percentile(confidence, 98)
        self_prob = np.clip(ub - confidence, 0, 1)
        graph.setdiag(self_prob)

    T = np.expm1(graph * scale)  # equivalent to np.exp(graph.A * scale) - 1
    if graph_neg is not None:
        graph_neg = adata.uns[f"{vkey}_graph_neg"]
        if use_negative_cosines:
            T -= np.expm1(-graph_neg * scale)
        else:
            T += np.expm1(graph_neg * scale)
            T.data += 1

    # weight direct and indirect (recursed) neighbors
    if weight_indirect_neighbors is not None and weight_indirect_neighbors < 1:

        direct_neighbors = get_neighs(adata, "distances") > 0