docs: def get_rank_based_enrichment(
              self,
              ranked_genes: List[str],
              pval_thresh: float = 0.05,
              X_frac: float = 0.25,
              X_min: int = 5,
              L: int = None,
              adjust_pval_thresh: bool = True,
              escore_pval_thresh: float = None,
              exact_pval: str = 'always',
              gene_set_ids: List[str] = None,
              table: np.ndarray = None) -> RankBasedGSEResult:
          """Test for gene set enrichment at the top of a ranked list of genes.
  
          This function uses the XL-mHG test to identify enriched gene sets.
  
          This function also calculates XL-mHG E-scores for the enriched gene
          sets, using ``escore_pval_thresh`` as the p-value threshold "psi".
  
          Parameters
          ----------
          ranked_gene_ids : list of str
              The ranked list of gene IDs.
          pval_thresh : float, optional
              The p-value threshold used to determine significance.
              See also ``adjust_pval_thresh``. [0.05]
          X_frac : float, optional
              The min. fraction of genes from a gene set required for enrichment. [0.25]
          X_min : int, optional
              The min. no. of genes from a gene set required for enrichment. [5]
          L : int, optional
              The lowest cutoff to test for enrichment. If ``None``,
              int(0.25*(no. of genes)) will be used. [None]
          adjust_pval_thresh : bool, optional
              Whether to adjust the p-value thershold for multiple testing,
              using the Bonferroni method. [True]
          escore_pval_thresh : float or None, optional
              The "psi" p-value threshold used in calculating E-scores. If
              ``None``, will be set to p-value threshold. [None]
          exact_pval : str
              Choices are: "always", "if_significant", "if_necessary". Parameter
              will be passed to `xlmhg.get_xlmhg_test_result`. ["always"]
          gene_set_ids : list of str or None, optional
              A list of gene set IDs to specify which gene sets should be tested for enrichment. If ``None``, all gene sets will be tested. [None]
          table : 2-dim numpy.ndarray of type numpy.longdouble or None, optional
              The dynamic programming table used by the algorithm for calculating XL-mHG p-values. Passing this avoids memory re-allocation when calling this function repetitively. [None]
  
          Returns
          -------
          list of `RankBasedGSEResult`
              A list of all significantly enriched gene sets. 
          """
  
          # make sure X_frac is a float (e.g., if specified as 0)
          X_frac = float(X_frac)
  
          if table is not None:
              if not np.issubdtype(table.dtype, np.longdouble):
                  raise TypeError('The provided array for storing the dynamic '
                                  'programming table must be of type '
                                  '"longdouble"!')
  
          if L is None:
              L = int(len(ranked_genes)/4.0)
  
          gene_set_coll = self._gene_set_coll
          gene_memberships = self._gene_memberships
  
          # postpone this
          if escore_pval_thresh is None:
              # if no separate E-score p-value threshold is specified, use the
              # p-value threshold (this results in conservative E-scores)
              logger.warning('No E-score p-value threshold supplied. '
                             'The E-score p-value threshold will be set to the'
                             'global significance threshold. This will result '
                             'in conservative E-scores.')
  
          # test only some terms?
          if gene_set_ids is not None:
              gs_indices = np.int64([self._gene_set_coll.index(id_)
                                     for id_ in gene_set_ids])
              gene_sets = [gene_set_coll[id_] for id_ in gene_set_ids]
              gene_set_coll = GeneSetCollection(gene_sets)
              gene_memberships = gene_memberships[:, gs_indices]  # not a view!
  
          # reorder rows in annotation matrix to match the given gene ranking
          # also exclude genes not in the ranking
          unknown = 0
          L_adj = L
          sel = []
          filtered_genes = []
          logger.debug('Looking up indices for %d genes...' % len(ranked_genes))
          for i, g in enumerate(ranked_genes):
              try:
                  idx = self._gene_indices[g]
              except KeyError:
                  unknown += 1
                  # adjust L if the gene was above the original L cutoff
                  if i < L:
                      L_adj -= 1
              else:
                  sel.append(idx)
                  filtered_genes.append(g)
          sel = np.int64(sel)
          logger.debug('Adjusted L: %d', L_adj)
  
          # the following also copies the data (not a view)
          gene_memberships = gene_memberships[sel, :]
          N, m = gene_memberships.shape
          if unknown > 0:
              # Some genes in the ranked list were unknown (i.e., not present in
              # the specified genome).
              logger.warn('%d / %d unknown genes (%.1f %%), will be ignored.',
                          unknown, len(ranked_genes),
                          100 * (unknown / float(len(ranked_genes))))
  
  
          # Determine the number of gene set genes above the L'th cutoff,
          # for all gene sets. This quantity is useful, because we don't need
          # to perform any more work for gene sets that have less than X genes
          # above the cutoff.
          k_above_L = np.sum(gene_memberships[:L_adj, :], axis=0, dtype=np.int64)
  
          # Determine the number of genes below the L'th cutoff, for all gene
          # sets.
          k_below_L = np.sum(gene_memberships[L_adj:, :], axis=0, dtype=np.int64)
  
          # Determine the total number K of genes in each gene set that are
          # present in the ranked list (this is equal to k_above_L + k_below_L)
          K_vec = k_above_L + k_below_L
  
          # Determine the largest K across all gene sets.
          K_max = np.amax(K_vec)
  
          # Determine X for all gene sets.
          X = np.amax(
              np.c_[np.tile(X_min, m), np.int64(np.ceil(X_frac * K_vec))],
              axis=1)
  
          # Determine the number of tests (we do not conduct a test if the
          # total number of gene set genes in the ranked list is below X).
          num_tests = np.sum(K_vec-X >= 0)
          logger.info('Conducting %d tests.', num_tests)
  
          # determine Bonferroni-corrected p-value, if desired
          final_pval_thresh = pval_thresh
          if adjust_pval_thresh and num_tests > 0:
              final_pval_thresh /= float(num_tests)
              logger.info('Using Bonferroni-corrected p-value threshold: %.1e',
                          final_pval_thresh)
  
          if escore_pval_thresh is None:
              escore_pval_thresh = final_pval_thresh
  
          elif escore_pval_thresh < final_pval_thresh:
              logger.warning('The E-score p-value threshold is smaller than '
                             'the p-value threshold. Setting E-score p-value '
                             'threshold to the p-value threshold.')
              escore_pval_thresh = final_pval_thresh
  
          # Prepare the matrix that holds the dynamic programming table for
          # the calculation of the XL-mHG p-value.
          if table is None:
              table = np.empty((K_max+1, N+1), dtype=np.longdouble)
          else:
              if table.shape[0] < K_max+1 or table.shape[1] < N+1:
                  raise ValueError(
                      'The supplied array is too small (%d x %d) to hold the '
                      'entire dynamic programming table. The required size is'
                      '%d x %d (rows x columns).'
                      % (table.shape[0], table.shape[1], K_max+1, N+1))
  
          # find enriched GO terms
          # logger.info('Testing %d gene sets for enrichment...', m)
          logger.debug('(N=%d, X_frac=%.2f, X_min=%d, L=%d; K_max=%d)',
                       len(ranked_genes), X_frac, X_min, L, K_max)
  
          enriched = []
          num_tests = 0  # number of tests conducted
          for j in range(m):
              # determine gene set-specific value for X
              X = max(X_min, int(ceil(X_frac * float(K_vec[j]))))
  
              # Determine significance of gene set enrichment using the XL-mHG
              # test (only if there are at least X gene set genes in the list).
              if K_vec[j] >= X:
                  num_tests += 1
  
                  # We only need to perform the XL-mHG test if there are enough
                  # gene set genes above the L'th cutoff (otherwise, pval = 1.0).
                  if k_above_L[j] >= X:
                      # perform test
  
                      # Determine the ranks of the gene set genes in the
                      # ranked list.
                      indices = np.uint16(np.nonzero(gene_memberships[:, j])[0])
                      res = xlmhg.get_xlmhg_test_result(
                          N, indices, X, L, pval_thresh=final_pval_thresh,
                          escore_pval_thresh=escore_pval_thresh,
                          exact_pval=exact_pval, table=table)
  
                      # check if gene set is significantly enriched
                      if res.pval <= final_pval_thresh:
                          # generate RankedGSEResult
                          ind_genes = [ranked_genes[i] for i in indices]
                          gse_result = RankBasedGSEResult(
                              gene_set_coll[j], N, indices, ind_genes,
                              X, L, res.stat, res.cutoff, res.pval,
                              escore_pval_thresh=escore_pval_thresh
                          )
                          enriched.append(gse_result)
  
          # report results
          q = len(enriched)
          ignored = m - num_tests
          if ignored > 0:
              logger.debug('%d / %d gene sets (%.1f%%) had less than X genes '
                           'annotated with them and were ignored.',
                           ignored, m, 100 * (ignored / float(m)))
  
          logger.info('%d / %d gene sets were found to be significantly '
                      'enriched (p-value <= %.1e).', q, m, final_pval_thresh)
  
          return enriched