code: def all_points_membership_vectors_flat(
      clusterer,
      prediction_data=None,
      n_clusters=None,
      cluster_selection_epsilon=None,
  ):
      """
      (Adaptation of hdbscan's all_points_membership_vector
          for n_clusters, epsilon)
      Predict soft cluster membership vectors for all points in the
      original dataset the clusterer was trained on. This function is more
      efficient by making use of the fact that all points are already in the
      condensed tree, and processing in bulk.
  
      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.
          This method does not work if the clusterer was trained
          with ``metric='precomputed'``.
  
      prediction_data: PredictionData, default=None
          Prediction data associated with HDBSCAN for some flat clustering
  
      n_clusters: int, optional, 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, optional, default=None
          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`` of the original dataset is a member of
          cluster ``j`` is in ``membership_vectors[i, j]``.
      See Also
      --------
      :py:func:`hdbscan.prediction.all_points_membership_vectors`
      :py:func:`hdbscan.prediction.membership_vector`
      """
      # 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 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 at the chosen epsilon from prediction_data
      clusters = clusters_from_prediction_data(prediction_data)
  
      all_points = prediction_data.raw_data
  
      # When no clusters found, return array of 0's
      if clusters.size == 0:
          return np.zeros(all_points.shape[0])
  
      # 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_vecs = all_points_dist_membership_vector(
          all_points,
          prediction_data.exemplars,
          prediction_data.dist_metric,
      )
  
      # Probabilities based on how long the point persists in
      #   each cluster (with respect to most persistent exemplar)
      # Use new clusters that are defined by the choice of n_clusters.
      outlier_vecs = all_points_outlier_membership_vector(
          clusters,
          condensed_tree._raw_tree,
          prediction_data.leaf_max_lambdas,
          prediction_data.cluster_tree,
      )
  
      # Include probability that the point belongs to a cluster
      in_cluster_probs = all_points_prob_in_some_cluster(
          clusters,
          condensed_tree._raw_tree,
          prediction_data.leaf_max_lambdas,
          prediction_data.cluster_tree,
      )
  
      # Aggregate the three probabilities to produce membership vectors
      result = distance_vecs * outlier_vecs
      row_sums = result.sum(axis=1)
      result = result / row_sums[:, np.newaxis]
      result *= in_cluster_probs[:, np.newaxis]
  
      # Re-name variable to clarify 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 4 for calling a global function with example usage: all_points_membership_vectors_flat(clusterer, prediction_data, n_clusters, cluster_selection_epsilon) and returns: membership_vectors, np