code: def filter_alleles(mt: MatrixTable, f: Callable) -> MatrixTable:
      """Filter alternate alleles.
  
      .. include:: ../_templates/req_tvariant.rst
  
      Examples
      --------
      Keep SNPs:
  
      >>> ds_result = hl.filter_alleles(ds, lambda allele, i: hl.is_snp(ds.alleles[0], allele))
  
      Keep alleles with AC > 0:
  
      >>> ds_result = hl.filter_alleles(ds, lambda a, allele_index: ds.info.AC[allele_index - 1] > 0)
  
      Update the AC field of the resulting dataset:
  
      >>> updated_info = ds_result.info.annotate(AC = ds_result.new_to_old.map(lambda i: ds_result.info.AC[i-1]))
      >>> ds_result = ds_result.annotate_rows(info = updated_info)
  
      Notes
      -----
      The following new fields are generated:
  
       - `old_locus` (``locus``) -- The old locus, before filtering and computing
         the minimal representation.
       - `old_alleles` (``array<str>``) -- The old alleles, before filtering and
         computing the minimal representation.
       - `old_to_new` (``array<int32>``) -- An array that maps old allele index to
         new allele index. Its length is the same as `old_alleles`. Alleles that
         are filtered are missing.
       - `new_to_old` (``array<int32>``) -- An array that maps new allele index to
         the old allele index. Its length is the same as the modified `alleles`
         field.
  
      If all alternate alleles of a variant are filtered out, the variant itself
      is filtered out.
  
      **Using** `f`
  
      The `f` argument is a function or lambda evaluated per alternate allele to
      determine whether that allele is kept. If `f` evaluates to ``True``, the
      allele is kept. If `f` evaluates to ``False`` or missing, the allele is
      removed.
  
      `f` is a function that takes two arguments: the allele string (of type
      :class:`.StringExpression`) and the allele index (of type
      :class:`.Int32Expression`), and returns a boolean expression. This can
      be either a defined function or a lambda. For example, these two usages
      are equivalent:
  
      (with a lambda)
  
      >>> ds_result = hl.filter_alleles(ds, lambda allele, i: hl.is_snp(ds.alleles[0], allele))
  
      (with a defined function)
  
      >>> def filter_f(allele, allele_index):
      ...     return hl.is_snp(ds.alleles[0], allele)
      >>> ds_result = hl.filter_alleles(ds, filter_f)
  
      Warning
      -------
      :func:`.filter_alleles` does not update any fields other than `locus` and
      `alleles`. This means that row fields like allele count (AC) and entry
      fields like allele depth (AD) can become meaningless unless they are also
      updated. You can update them with :meth:`.annotate_rows` and
      :meth:`.annotate_entries`.
  
      See Also
      --------
      :func:`.filter_alleles_hts`
  
      Parameters
      ----------
      mt : :class:`.MatrixTable`
          Dataset.
      f : callable
          Function from (allele: :class:`.StringExpression`, allele_index:
          :class:`.Int32Expression`) to :class:`.BooleanExpression`
  
      Returns
      -------
      :class:`.MatrixTable`
      """
      require_row_key_variant(mt, "filter_alleles")
      inclusion = hl.range(0, hl.len(mt.alleles)).map(
          lambda i: (i == 0)
          | hl.bind(lambda ii: f(mt.alleles[ii], ii), i)
      )
  
      # old locus, old alleles, new to old, old to new
      mt = mt.annotate_rows(
          __allele_inclusion=inclusion,
          old_locus=mt.locus,
          old_alleles=mt.alleles,
      )
      new_to_old = (
          hl.enumerate(mt.__allele_inclusion)
          .filter(lambda elt: elt[1])
          .map(lambda elt: elt[0])
      )
      old_to_new_dict = hl.dict(
          hl.enumerate(
              hl.enumerate(mt.alleles).filter(
                  lambda elt: mt.__allele_inclusion[elt[0]]
              )
          ).map(lambda elt: (elt[1][1], elt[0]))
      )
  
      old_to_new = hl.bind(
          lambda d: mt.alleles.map(lambda a: d.get(a)), old_to_new_dict
      )
      mt = mt.annotate_rows(
          old_to_new=old_to_new, new_to_old=new_to_old
      )
      new_locus_alleles = hl.min_rep(
          mt.locus, mt.new_to_old.map(lambda i: mt.alleles[i])
      )
      mt = mt.annotate_rows(
          __new_locus=new_locus_alleles.locus,
          __new_alleles=new_locus_alleles.alleles,
      )
      mt = mt.filter_rows(hl.len(mt.__new_alleles) > 1)
      left = mt.filter_rows(
          (mt.locus == mt.__new_locus)
          & (mt.alleles == mt.__new_alleles)
      )
  
      right = mt.filter_rows(
          (mt.locus != mt.__new_locus)
          | (mt.alleles != mt.__new_alleles)
      )
      right = right.key_rows_by(
          locus=right.__new_locus, alleles=right.__new_alleles
      )
      return left.union_rows(right, _check_cols=False).drop(
          "__allele_inclusion", "__new_locus", "__new_alleles"
      )
  
imports: import builtins
  import itertools
  import math
  from typing import Dict, Callable, Optional, Union, Tuple, List
  import hail
  import hail
  import hail.expr.aggregators
  from hail import ir
  from hail.expr import Expression, ExpressionException, expr_float64, expr_call, expr_any, expr_numeric, expr_locus, analyze, raise_unless_entry_indexed, raise_unless_row_indexed, matrix_table_source, table_source, raise_unless_column_indexed
  from hail.expr.types import tbool, tarray, tfloat64, tint32
  from hail.genetics.reference_genome import reference_genome_type
  from hail.linalg import BlockMatrix
  from hail.matrixtable import MatrixTable
  from hail.methods.misc import require_biallelic, require_row_key_variant
  from hail.stats import LinearMixedModel
  from hail.table import Table
  from hail.typecheck import typecheck, nullable, numeric, oneof, sized_tupleof, sequenceof, enumeration, anytype
  from hail.utils import wrap_to_list, new_temp_file, FatalError
  from hail.utils.java import Env, info, warning
  from .None import pca
  from .None import relatedness
  from ..backend.spark_backend import SparkBackend
label_desc: Use image node_id 33 for calling a global function with example usage: filter_alleles(mt, f) and returns: left