code: def membership_vector_flat(
      clusterer,
      points_to_predict,
      prediction_data=None,
      n_clusters=None,
      cluster_selection_epsilon=0.0,
  ):
      """
      (Adaptation of hdbscan's membership_vector for n_clusters, epsilon)
      Predict soft cluster membership probabilities;
          a vector for each point in ``points_to_predict`` that gives
          a probability that the given point is a member of a cluster
          for each of the selected clusters of the ``clusterer``.
  
      Parameters
      ----------
      clusterer: HDBSCAN
          A clustering object that has been fit to the data and
          either had ``prediction_data=True`` set, or called the
          ``generate_prediction_data`` method after the fact.
  
      points_to_predict: array, or array-like (n_samples, n_features)
          The new data points to predict cluster labels for. They should
          have the same dimensionality as the original dataset over which
          clusterer was fit.
  
      prediction_data: PredictionData, default=None
          Prediction data associated with HDBSCAN for some flat clustering
  
      n_clusters: int, default=None
          Number of clusters over which to compute membership probabilities.
          These clusters are obtained as a flat clustering at some
              cluster_selection_epsilon.
  
      cluster_selection_epsilon: float, default=0.
          core-distance below which to stop splitting clusters.
          This can indirectly impose n_clusters.
          This argument is ignored if n_clusters is supplied.
  
      Note: If neither n_clusters nor cluster_selection_epsilon are supplied,
          the clusterer's original clustering is used.
  
      Returns
      -------
      membership_vectors : array (n_samples, n_clusters)
          The probability that point ``i`` is a member of cluster ``j`` is
          in ``membership_vectors[i, j]``.
  
      See Also
      --------
      :py:func:`hdbscan.predict.membership_vector`
      :py:func:`hdbscan.predict.all_points_membership_vectors`
      """
      points_to_predict = points_to_predict.astype(np.float64)
      # Extract condensed tree for later use
      condensed_tree = clusterer.condensed_tree_
  
      # Choose flat clustering based on cluster_selection_epsilon or n_clusters.
      # If neither is specified, use clusterer's cluster_selection_epsilon
      if (
          (n_clusters is None)
          and (cluster_selection_epsilon == 0.0)
          and (prediction_data is None)
      ):
          epsilon = clusterer.cluster_selection_epsilon
          # Use the same prediction_data as clusterer's
          prediction_data = clusterer.prediction_data_
      elif prediction_data is None:
          if n_clusters is not None:
              # Compute cluster_selection_epsilon so that a flat clustering
              #   produces a specified number of n_clusters
              # With method 'eom', we may fail to get 'n_clusters' clusters. So,
              try:
                  epsilon = select_epsilon(condensed_tree, n_clusters)
              except AssertionError:
                  warn(
                      f"Failed to predict {n_clusters} clusters with "
                      "cluster selection method 'eom'. Switching to 'leaf'..."
                  )
                  condensed_tree.cluster_selection_method = "leaf"
                  epsilon = select_epsilon(condensed_tree, n_clusters)
          else:
              epsilon = cluster_selection_epsilon
          # Create another instance of prediction_data that is consistent
          #   with the selected value of epsilon.
          prediction_data = copy.deepcopy(clusterer.prediction_data_)
          re_init(
              prediction_data,
              condensed_tree,
              cluster_selection_epsilon=epsilon,
          )
  
      # Flat clustering from prediction data
      clusters = clusters_from_prediction_data(prediction_data)
  
      # Initialize probabilities
      result = np.empty(
          (points_to_predict.shape[0], clusters.shape[0]),
          dtype=np.float64,
      )
  
      # k-NN for prediciton points to training set
      min_samples = clusterer.min_samples or clusterer.min_cluster_size
      neighbor_distances, neighbor_indices = prediction_data.tree.query(
          points_to_predict, k=2 * min_samples
      )
  
      # Loop over prediction points to compute probabilities
      for i in range(points_to_predict.shape[0]):
          # We need to find where in the tree the new point would go
          # for the purposes of outlier membership approximation
          nearest_neighbor, lambda_ = _find_neighbor_and_lambda(
              neighbor_indices[i],
              neighbor_distances[i],
              prediction_data.core_distances,
              min_samples,
          )
  
          # Find row in tree where nearest neighbor drops out,
          #   so we can get a lambda value for the nearest neighbor
          neighbor_tree_row = get_tree_row_with_child(
              condensed_tree._raw_tree, nearest_neighbor
          )
  
          # Assign lambda as min(lambda-to-neighbor, neighbor's-lambda-to-tree)
          # Equivalently, this assigns core distance for prediction point as
          #   max(dist-to-neighbor, neighbor's-dist-to-tree)
          if neighbor_tree_row["lambda_val"] <= lambda_:
              lambda_ = neighbor_tree_row["lambda_val"]
  
          # Probabilities based on distance to closest exemplar in each cluster:
          # Use new prediction_data that points to exemplars that are specific
          #   to the choice of n_clusters
          distance_vec = dist_membership_vector(
              points_to_predict[i],
              prediction_data.exemplars,
              prediction_data.dist_metric,
          )
          # Probabilities based on how long the nearest exemplar persists in
          #   each cluster (with respect to most persistent exemplar)
          # Use new clusters that are defined by the choice of n_clusters.
          outlier_vec = outlier_membership_vector(
              nearest_neighbor,
              lambda_,
              clusters,
              condensed_tree._raw_tree,
              prediction_data.leaf_max_lambdas,
              prediction_data.cluster_tree,
          )
  
          # Merge the two probabilities to produce a single set of probabilities
          result[i] = distance_vec**0.5 * outlier_vec**2.0
          result[i] /= result[i].sum()
  
          # Include probability that the nearest neighbor belongs to a cluster
          result[i] *= prob_in_some_cluster(
              nearest_neighbor,
              lambda_,
              clusters,
              condensed_tree._raw_tree,
              prediction_data.leaf_max_lambdas,
              prediction_data.cluster_tree,
          )
  
      # Rename variable so it's easy to understand what's being returned
      membership_vectors = result
      return membership_vectors
  
imports: import copy
  from warnings import warn
  import numpy
  from ._hdbscan_tree import compute_stability, get_cluster_tree_leaves
  from .hdbscan_ import HDBSCAN, _tree_to_labels
  from .plots import _bfs_from_cluster_tree
  from .prediction import PredictionData, _find_cluster_and_probability, _find_neighbor_and_lambda
  from ._prediction_utils import get_tree_row_with_child, dist_membership_vector, outlier_membership_vector, prob_in_some_cluster, all_points_dist_membership_vector, all_points_outlier_membership_vector, all_points_prob_in_some_cluster
label_desc: Use image node_id 3 for calling a global function with example usage: membership_vector_flat(clusterer, points_to_predict, prediction_data, n_clusters, cluster_selection_epsilon) and returns: membership_vectors