files.new_contents: import numpy as np
  import numba
  import umap.distances as dist
  from umap.utils import tau_rand_int
  
  
  @numba.njit()
  def clip(val):
      """Standard clamping of a value into a fixed range (in this case -4.0 to
      4.0)
  
      Parameters
      ----------
      val: float
          The value to be clamped.
  
      Returns
      -------
      The clamped value, now fixed to be in the range -4.0 to 4.0.
      """
      if val > 4.0:
          return 4.0
      elif val < -4.0:
          return -4.0
      else:
          return val
  
  
  @numba.njit(
      "f4(f4[::1],f4[::1])",
      fastmath=True,
      cache=True,
      locals={
          "result": numba.types.float32,
          "diff": numba.types.float32,
          "dim": numba.types.intp,
      },
  )
  def rdist(x, y):
      """Reduced Euclidean distance.
  
      Parameters
      ----------
      x: array of shape (embedding_dim,)
      y: array of shape (embedding_dim,)
  
      Returns
      -------
      The squared euclidean distance between x and y
      """
      result = 0.0
      dim = x.shape[0]
      for i in range(dim):
          diff = x[i] - y[i]
          result += diff * diff
  
      return result
  
  
  def _optimize_layout_euclidean_single_epoch(
      head_embedding,
      tail_embedding,
      head,
      tail,
      n_vertices,
      epochs_per_sample,
      a,
      b,
      rng_state,
      gamma,
      dim,
      move_other,
      alpha,
      epochs_per_negative_sample,
      epoch_of_next_negative_sample,
      epoch_of_next_sample,
      n,
      densmap_flag,
      dens_phi_sum,
      dens_re_sum,
      dens_re_cov,
      dens_re_std,
      dens_re_mean,
      dens_lambda,
      dens_R,
      dens_mu,
      dens_mu_tot,
  ):
      for i in numba.prange(epochs_per_sample.shape[0]):
          if epoch_of_next_sample[i] <= n:
              j = head[i]
              k = tail[i]
  
              current = head_embedding[j]
              other = tail_embedding[k]
  
              dist_squared = rdist(current, other)
  
              if densmap_flag:
                  phi = 1.0 / (1.0 + a * pow(dist_squared, b))
                  dphi_term = (
                      a * b * pow(dist_squared, b - 1) / (1.0 + a * pow(dist_squared, b))
                  )
  
                  q_jk = phi / dens_phi_sum[k]
                  q_kj = phi / dens_phi_sum[j]
  
                  drk = q_jk * (
                      (1.0 - b * (1 - phi)) / np.exp(dens_re_sum[k]) + dphi_term
                  )
                  drj = q_kj * (
                      (1.0 - b * (1 - phi)) / np.exp(dens_re_sum[j]) + dphi_term
                  )
  
                  re_std_sq = dens_re_std * dens_re_std
                  weight_k = (
                      dens_R[k]
                      - dens_re_cov * (dens_re_sum[k] - dens_re_mean) / re_std_sq
                  )
                  weight_j = (
                      dens_R[j]
                      - dens_re_cov * (dens_re_sum[j] - dens_re_mean) / re_std_sq
                  )
  
                  grad_cor_coeff = (
                      dens_lambda
                      * dens_mu_tot
                      * (weight_k * drk + weight_j * drj)
                      / (dens_mu[i] * dens_re_std)
                      / n_vertices
                  )
  
              if dist_squared > 0.0:
                  grad_coeff = -2.0 * a * b * pow(dist_squared, b - 1.0)
                  grad_coeff /= a * pow(dist_squared, b) + 1.0
              else:
                  grad_coeff = 0.0
  
              for d in range(dim):
                  grad_d = clip(grad_coeff * (current[d] - other[d]))
  
                  if densmap_flag:
                      grad_d += clip(2 * grad_cor_coeff * (current[d] - other[d]))
  
                  current[d] += grad_d * alpha
                  if move
  
  [... the rest is omitted ...]
files.new_path: umap/layouts.py
files.old_contents: import numpy as np
  import numba
  import umap.distances as dist
  from umap.utils import tau_rand_int
  
  
  @numba.njit()
  def clip(val):
      """Standard clamping of a value into a fixed range (in this case -4.0 to
      4.0)
  
      Parameters
      ----------
      val: float
          The value to be clamped.
  
      Returns
      -------
      The clamped value, now fixed to be in the range -4.0 to 4.0.
      """
      if val > 4.0:
          return 4.0
      elif val < -4.0:
          return -4.0
      else:
          return val
  
  
  @numba.njit(
      "f4(f4[::1],f4[::1])",
      fastmath=True,
      cache=True,
      locals={
          "result": numba.types.float32,
          "diff": numba.types.float32,
          "dim": numba.types.intp,
      },
  )
  def rdist(x, y):
      """Reduced Euclidean distance.
  
      Parameters
      ----------
      x: array of shape (embedding_dim,)
      y: array of shape (embedding_dim,)
  
      Returns
      -------
      The squared euclidean distance between x and y
      """
      result = 0.0
      dim = x.shape[0]
      for i in range(dim):
          diff = x[i] - y[i]
          result += diff * diff
  
      return result
  
  
  def _optimize_layout_euclidean_single_epoch(
      head_embedding,
      tail_embedding,
      head,
      tail,
      n_vertices,
      epochs_per_sample,
      a,
      b,
      rng_state,
      gamma,
      dim,
      move_other,
      alpha,
      epochs_per_negative_sample,
      epoch_of_next_negative_sample,
      epoch_of_next_sample,
      n,
      densmap_flag,
      dens_phi_sum,
      dens_re_sum,
      dens_re_cov,
      dens_re_std,
      dens_re_mean,
      dens_lambda,
      dens_R,
      dens_mu,
      dens_mu_tot,
  ):
      for i in numba.prange(epochs_per_sample.shape[0]):
          if epoch_of_next_sample[i] <= n:
              j = head[i]
              k = tail[i]
  
              current = head_embedding[j]
              other = tail_embedding[k]
  
              dist_squared = rdist(current, other)
  
              if densmap_flag:
                  phi = 1.0 / (1.0 + a * pow(dist_squared, b))
                  dphi_term = (
                      a * b * pow(dist_squared, b - 1) / (1.0 + a * pow(dist_squared, b))
                  )
  
                  q_jk = phi / dens_phi_sum[k]
                  q_kj = phi / dens_phi_sum[j]
  
                  drk = q_jk * (
                      (1.0 - b * (1 - phi)) / np.exp(dens_re_sum[k]) + dphi_term
                  )
                  drj = q_kj * (
                      (1.0 - b * (1 - phi)) / np.exp(dens_re_sum[j]) + dphi_term
                  )
  
                  re_std_sq = dens_re_std * dens_re_std
                  weight_k = (
                      dens_R[k]
                      - dens_re_cov * (dens_re_sum[k] - dens_re_mean) / re_std_sq
                  )
                  weight_j = (
                      dens_R[j]
                      - dens_re_cov * (dens_re_sum[j] - dens_re_mean) / re_std_sq
                  )
  
                  grad_cor_coeff = (
                      dens_lambda
                      * dens_mu_tot
                      * (weight_k * drk + weight_j * drj)
                      / (dens_mu[i] * dens_re_std)
                      / n_vertices
                  )
  
              if dist_squared > 0.0:
                  grad_coeff = -2.0 * a * b * pow(dist_squared, b - 1.0)
                  grad_coeff /= a * pow(dist_squared, b) + 1.0
              else:
                  grad_coeff = 0.0
  
              for d in range(dim):
                  grad_d = clip(grad_coeff * (current[d] - other[d]))
  
                  if densmap_flag:
                      grad_d += clip(2 * grad_cor_coeff * (current[d] - other[d]))
  
                  current[d] += grad_d * alpha
                  if move
  
  [... the rest is omitted ...]
files.old_path: umap/layouts.py
files.new_contents: # Author: Leland McInnes <leland.mcinnes@gmail.com>
  #
  # License: BSD 3 clause
  from __future__ import print_function
  
  import locale
  from warnings import warn
  import time
  
  from scipy.optimize import curve_fit
  from sklearn.base import BaseEstimator
  from sklearn.utils import check_random_state, check_array
  from sklearn.utils.validation import check_is_fitted
  from sklearn.metrics import pairwise_distances
  from sklearn.preprocessing import normalize
  from sklearn.neighbors import KDTree
  
  try:
      import joblib
  except ImportError:
      # sklearn.externals.joblib is deprecated in 0.21, will be removed in 0.23
      from sklearn.externals import joblib
  
  import numpy as np
  import scipy.sparse
  from scipy.sparse import tril as sparse_tril, triu as sparse_triu
  import scipy.sparse.csgraph
  import numba
  
  import umap.distances as dist
  
  import umap.sparse as sparse
  
  from umap.utils import (
      submatrix,
      ts,
      csr_unique,
      fast_knn_indices,
  )
  from umap.spectral import spectral_layout
  from umap.layouts import (
      optimize_layout_euclidean,
      optimize_layout_generic,
      optimize_layout_inverse,
  )
  
  from pynndescent import NNDescent
  from pynndescent.distances import named_distances as pynn_named_distances
  from pynndescent.sparse import sparse_named_distances as pynn_sparse_named_distances
  
  locale.setlocale(locale.LC_NUMERIC, "C")
  
  INT32_MIN = np.iinfo(np.int32).min + 1
  INT32_MAX = np.iinfo(np.int32).max - 1
  
  SMOOTH_K_TOLERANCE = 1e-5
  MIN_K_DIST_SCALE = 1e-3
  NPY_INFINITY = np.inf
  
  DISCONNECTION_DISTANCES = {
      "correlation": 2,
      "cosine": 2,
      "hellinger": 1,
      "jaccard": 1,
      "dice": 1,
  }
  
  
  def flatten_iter(container):
      for i in container:
          if isinstance(i, (list, tuple)):
              for j in flatten_iter(i):
                  yield j
          else:
              yield i
  
  
  def flattened(container):
      return tuple(flatten_iter(container))
  
  
  def breadth_first_search(adjmat, start, min_vertices):
      explored = []
      queue = [start]
      levels = {}
      levels[start] = 0
      max_level = np.inf
      visited = [start]
  
      while queue:
          node = queue.pop(0)
          explored.append(node)
          if max_level == np.inf and len(explored) > min_vertices:
              max_level = max(levels.values())
  
          if levels[node] + 1 < max_level:
              neighbors = adjmat[node].indices
              for neighbour in neighbors:
                  if neighbour not in visited:
                      queue.append(neighbour)
                      visited.append(neighbour)
  
                      levels[neighbour] = levels[node] + 1
  
      return np.array(explored)
  
  
  def raise_disconnected_warning(
      edges_removed,
      vertices_disconnected,
      disconnection_distance,
      total_rows,
      threshold=0.1,
      verbose=False,
  ):
      """A simple wrapper function to avoid large amounts of code repetition."""
      if verbose & (vertices_disconnected == 0) & (edges_removed > 0):
          print(
              f"Disconnection_distance = {disconnection_distance} has removed {edges_removed} edges.  "
              f"This is not a problem as no vertices were disconnected."
          )
      elif (vertices_disconnected > 0) & (
          vertices_disconnected <= threshold * total_rows
      ):
          warn(
              f"A few of your vertices were disconnected from the manifold.  This shouldn't cause problems.\n"
              f"Disconnection_distance = {disconnection_distance} has removed {edges_removed} edges.\n"
              f"It has only fully disconnected {vertices_disconnected} vertices.\n"
              f"Use umap.utils.disconnected_vertices() to identify them.",
          )
      elif vertices_disconnected > threshold * total_rows:
          warn(
              f"A large number of your vertices were disconnected from the manifold.\n"
              f"Disconnection_distance = {disconnection_distance} has removed {edges_removed} edges.\n"
              f"It has fully disconnected {vertices_disconnected} vertices.\n"
              f"You might consider using find_disconnected_points() to find and remove these points
  
  [... the rest is omitted ...]
files.new_path: umap/umap_.py
files.old_contents: # Author: Leland McInnes <leland.mcinnes@gmail.com>
  #
  # License: BSD 3 clause
  from __future__ import print_function
  
  import locale
  from warnings import warn
  import time
  
  from scipy.optimize import curve_fit
  from sklearn.base import BaseEstimator
  from sklearn.utils import check_random_state, check_array
  from sklearn.utils.validation import check_is_fitted
  from sklearn.metrics import pairwise_distances
  from sklearn.preprocessing import normalize
  from sklearn.neighbors import KDTree
  
  try:
      import joblib
  except ImportError:
      # sklearn.externals.joblib is deprecated in 0.21, will be removed in 0.23
      from sklearn.externals import joblib
  
  import numpy as np
  import scipy.sparse
  from scipy.sparse import tril as sparse_tril, triu as sparse_triu
  import scipy.sparse.csgraph
  import numba
  
  import umap.distances as dist
  
  import umap.sparse as sparse
  
  from umap.utils import (
      submatrix,
      ts,
      csr_unique,
      fast_knn_indices,
  )
  from umap.spectral import spectral_layout
  from umap.layouts import (
      optimize_layout_euclidean,
      optimize_layout_generic,
      optimize_layout_inverse,
  )
  
  from pynndescent import NNDescent
  from pynndescent.distances import named_distances as pynn_named_distances
  from pynndescent.sparse import sparse_named_distances as pynn_sparse_named_distances
  
  locale.setlocale(locale.LC_NUMERIC, "C")
  
  INT32_MIN = np.iinfo(np.int32).min + 1
  INT32_MAX = np.iinfo(np.int32).max - 1
  
  SMOOTH_K_TOLERANCE = 1e-5
  MIN_K_DIST_SCALE = 1e-3
  NPY_INFINITY = np.inf
  
  DISCONNECTION_DISTANCES = {
      "correlation": 2,
      "cosine": 2,
      "hellinger": 1,
      "jaccard": 1,
      "dice": 1,
  }
  
  
  def flatten_iter(container):
      for i in container:
          if isinstance(i, (list, tuple)):
              for j in flatten_iter(i):
                  yield j
          else:
              yield i
  
  
  def flattened(container):
      return tuple(flatten_iter(container))
  
  
  def breadth_first_search(adjmat, start, min_vertices):
      explored = []
      queue = [start]
      levels = {}
      levels[start] = 0
      max_level = np.inf
      visited = [start]
  
      while queue:
          node = queue.pop(0)
          explored.append(node)
          if max_level == np.inf and len(explored) > min_vertices:
              max_level = max(levels.values())
  
          if levels[node] + 1 < max_level:
              neighbors = adjmat[node].indices
              for neighbour in neighbors:
                  if neighbour not in visited:
                      queue.append(neighbour)
                      visited.append(neighbour)
  
                      levels[neighbour] = levels[node] + 1
  
      return np.array(explored)
  
  
  def raise_disconnected_warning(
      edges_removed,
      vertices_disconnected,
      disconnection_distance,
      total_rows,
      threshold=0.1,
      verbose=False,
  ):
      """A simple wrapper function to avoid large amounts of code repetition."""
      if verbose & (vertices_disconnected == 0) & (edges_removed > 0):
          print(
              f"Disconnection_distance = {disconnection_distance} has removed {edges_removed} edges.  "
              f"This is not a problem as no vertices were disconnected."
          )
      elif (vertices_disconnected > 0) & (
          vertices_disconnected <= threshold * total_rows
      ):
          warn(
              f"A few of your vertices were disconnected from the manifold.  This shouldn't cause problems.\n"
              f"Disconnection_distance = {disconnection_distance} has removed {edges_removed} edges.\n"
              f"It has only fully disconnected {vertices_disconnected} vertices.\n"
              f"Use umap.utils.disconnected_vertices() to identify them.",
          )
      elif vertices_disconnected > threshold * total_rows:
          warn(
              f"A large number of your vertices were disconnected from the manifold.\n"
              f"Disconnection_distance = {disconnection_distance} has removed {edges_removed} edges.\n"
              f"It has fully disconnected {vertices_disconnected} vertices.\n"
              f"You might consider using find_disconnected_points() to find and remove these points
  
  [... the rest is omitted ...]
files.old_path: umap/umap_.py