docs: def target_gene_indices(gene_names,
                          target_genes):
      """
      :param gene_names: list of gene names.
      :param target_genes: either int (the top n), 'all', or a collection (subset of gene_names).
      :return: the (column) indices of the target genes in the expression_matrix.
      """
  
      if isinstance(target_genes, list) and len(target_genes) == 0:
          return []
  
      if isinstance(target_genes, str) and target_genes.upper() == 'ALL':
          return list(range(len(gene_names)))
  
      elif isinstance(target_genes, int):
          top_n = target_genes
          assert top_n > 0
  
          return list(range(min(top_n, len(gene_names))))
  
      elif isinstance(target_genes, list):
          if not target_genes:  # target_genes is empty
              return target_genes
          elif all(isinstance(target_gene, str) for target_gene in target_genes):
              return [index for index, gene in enumerate(gene_names) if gene in target_genes]
          elif all(isinstance(target_gene, int) for target_gene in target_genes):
              return target_genes
          else:
              raise ValueError("Mixed types in target genes.")
  
      else:
          raise ValueError("Unable to interpret target_genes.")