code: def skat(
      key_expr,
      weight_expr,
      y,
      x,
      covariates,
      logistic: Union[bool, Tuple[int, float]] = False,
      max_size: int = 46340,
      accuracy: float = 1e-6,
      iterations: int = 10000,
  ) -> Table:
      r"""Test each keyed group of rows for association by linear or logistic
      SKAT test.
  
      Examples
      --------
  
      Test each gene for association using the linear sequence kernel association
      test:
  
      >>> skat_table = hl.skat(key_expr=burden_ds.gene,
      ...                      weight_expr=burden_ds.weight,
      ...                      y=burden_ds.burden.pheno,
      ...                      x=burden_ds.GT.n_alt_alleles(),
      ...                      covariates=[1, burden_ds.burden.cov1, burden_ds.burden.cov2])
  
      .. caution::
  
         By default, the Davies algorithm iterates up to 10k times until an
         accuracy of 1e-6 is achieved. Hence a reported p-value of zero with no
         issues may truly be as large as 1e-6. The accuracy and maximum number of
         iterations may be controlled by the corresponding function parameters.
         In general, higher accuracy requires more iterations.
  
      .. caution::
  
         To process a group with :math:`m` rows, several copies of an
         :math:`m \times m` matrix of doubles must fit in worker memory. Groups
         with tens of thousands of rows may exhaust worker memory causing the
         entire job to fail. In this case, use the `max_size` parameter to skip
         groups larger than `max_size`.
  
      Warning
      -------
      :func:`.skat` considers the same set of columns (i.e., samples, points) for
      every group, namely those columns for which **all** covariates are defined.
      For each row, missing values of `x` are mean-imputed over these columns.
      As in the example, the intercept covariate ``1`` must be included
      **explicitly** if desired.
  
      Notes
      -----
  
      This method provides a scalable implementation of the score-based
      variance-component test originally described in
      `Rare-Variant Association Testing for Sequencing Data with the Sequence Kernel Association Test
      <https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3135811/>`__.
  
      Row weights must be non-negative. Rows with missing weights are ignored. In
      the R package ``skat``---which assumes rows are variants---default weights
      are given by evaluating the Beta(1, 25) density at the minor allele
      frequency. To replicate these weights in Hail using alternate allele
      frequencies stored in a row-indexed field `AF`, one can use the expression:
  
      >>> hl.dbeta(hl.min(ds2.AF), 1.0, 25.0) ** 2
  
      In the logistic case, the response `y` must either be numeric (with all
      present values 0 or 1) or Boolean, in which case true and false are coded
      as 1 and 0, respectively.
  
      The resulting :class:`.Table` provides the group's key (`id`), thenumber of
      rows in the group (`size`), the variance component score `q_stat`, the SKAT
      `p-value`, and a `fault` flag. For the toy example above, the table has the
      form:
  
      +-------+------+--------+---------+-------+
      |  id   | size | q_stat | p_value | fault |
      +=======+======+========+=========+=======+
      | geneA |   2  | 4.136  | 0.205   |   0   |
      +-------+------+--------+---------+-------+
      | geneB |   1  | 5.659  | 0.195   |   0   |
      +-------+------+--------+---------+-------+
      | geneC |   3  | 4.122  | 0.192   |   0   |
      +-------+------+--------+---------+-------+
  
      Groups larger than `max_size` appear with missing `q_stat`, `p_value`, and
      `fault`. The hard limit on the number of rows in a group is 46340.
  
      Note that the variance component score `q_stat` agrees with ``Q`` in the R
      package ``skat``, but both differ from :math:`Q` in the paper by the factor
      :math:`\frac{1}{2\sigma^2}` in the linear case and :math:`\frac{1}{2}` in
      the logistic case, where :math:`\sigma^2` is the unbiased estimator of
      residual variance for the linear null model. The R package also applies a
      "small-sample adjustment" to the null distribution in the logistic case
      when the sample size is less than 2000. Hail does not apply this
      adjustment.
  
      The fault flag is an integer indicating whether any issues occurred when
      running the Davies algorithm to compute the p-value as the right tail of a
      weighted sum of :math:`\chi^2(1)` distributions.
  
      +-------------+-----------------------------------------+
      | fault value | Description                             |
      +=============+=========================================+
      |      0      | no issues                               |
      +------+------+-----------------------------------------+
      |      1      | accuracy NOT achieved                   |
      +------+------+-----------------------------------------+
      |      2      | round-off error possibly significant    |
      +------+------+-----------------------------------------+
      |      3      | invalid parameters                      |
      +------+------+-----------------------------------------+
      |      4      | unable to locate integration parameters |
      +------+------+-----------------------------------------+
      |      5      | out of memory                           |
      +------+------+-----------------------------------------+
  
      Parameters
      ----------
      key_expr : :class:`.Expression`
          Row-indexed expression for key associated to each row.
      weight_expr : :class:`.Float64Expression`
          Row-indexed expression for row weights.
      y : :class:`.Float64Expression`
          Column-indexed response expression.
          If `logistic` is ``True``, all non-missing values must evaluate to 0 or
          1. Note that a :class:`.BooleanExpression` will be implicitly converted
          to a :class:`.Float64Expression` with this property.
      x : :class:`.Float64Expression`
          Entry-indexed expression for input variable.
      covariates : :obj:`list` of :class:`.Float64Expression`
          List of column-indexed covariate expressions.
      logistic : :obj:`bool` or :obj:`tuple` of :obj:`int` and :obj:`float`
          If false, use the linear test. If true, use the logistic test with no
          more than 25 logistic iterations and a convergence tolerance of 1e-6. If
          a tuple is given, use the logistic test with the tuple elements as the
          maximum nubmer of iterations and convergence tolerance, respectively.
      max_size : :obj:`int`
          Maximum size of group on which to run the test.
      accuracy : :obj:`float`
          Accuracy achieved by the Davies algorithm if fault value is zero.
      iterations : :obj:`int`
          Maximum number of iterations attempted by the Davies algorithm.
  
      Returns
      -------
      :class:`.Table`
          Table of SKAT results.
  
      """
      if hl.current_backend().requires_lowering:
          if logistic:
              kwargs = {"accuracy": accuracy, "iterations": iterations}
              if logistic is not True:
                  null_max_iterations, null_tolerance = logistic
                  kwargs["null_max_iterations"] = null_max_iterations
                  kwargs["null_tolerance"] = null_tolerance
              ht = hl._logistic_skat(
                  key_expr,
                  weight_expr,
                  y,
                  x,
                  covariates,
                  max_size,
                  **kwargs,
              )
          else:
              ht = hl._linear_skat(
                  key_expr,
                  weight_expr,
                  y,
                  x,
                  covariates,
                  max_size,
                  accuracy,
                  iterations,
              )
          ht = ht.select_globals()
          return ht
      mt = matrix_table_source("skat/x", x)
      raise_unless_entry_indexed("skat/x", x)
  
      analyze("skat/key_expr", key_expr, mt._row_indices)
      analyze("skat/weight_expr", weight_expr, mt._row_indices)
      analyze("skat/y", y, mt._col_indices)
  
      all_exprs = [key_expr, weight_expr, y]
      for e in covariates:
          all_exprs.append(e)
          analyze("skat/covariates", e, mt._col_indices)
  
      _warn_if_no_intercept("skat", covariates)
  
      # FIXME: remove this logic when annotation is better optimized
      if x in mt._fields_inverse:
          x_field_name = mt._fields_inverse[x]
          entry_expr = {}
      else:
          x_field_name = Env.get_uid()
          entry_expr = {x_field_name: x}
  
      y_field_name = "__y"
      weight_field_name = "__weight"
      key_field_name = "__key"
      cov_field_names = list(
          f"__cov{i}" for i in range(len(covariates))
      )
  
      mt = mt._select_all(
          col_exprs=dict(
              **{y_field_name: y},
              **dict(zip(cov_field_names, covariates)),
          ),
          row_exprs={
              weight_field_name: weight_expr,
              key_field_name: key_expr,
          },
          entry_exprs=entry_expr,
      )
  
      if logistic is True:
          use_logistic = True
          max_iterations = 25
          tolerance = 1e-6
      elif logistic is False:
          use_logistic = False
          max_iterations = 0
          tolerance = 0.0
      else:
          assert isinstance(logistic, tuple) and len(logistic) == 2
          use_logistic = True
          max_iterations, tolerance = logistic
  
      config = {
          "name": "Skat",
          "keyField": key_field_name,
          "weightField": weight_field_name,
          "xField": x_field_name,
          "yField": y_field_name,
          "covFields": cov_field_names,
          "logistic": use_logistic,
          "maxSize": max_size,
          "accuracy": accuracy,
          "iterations": iterations,
          "logistic_max_iterations": max_iterations,
          "logistic_tolerance": tolerance,
      }
  
      return Table(ir.MatrixToTableApply(mt._mir, config)).persist()
  
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 23 for calling a global function with example usage: skat(key_expr, weight_expr, y, x, covariates, logistic, max_size, accuracy, iterations) and returns: Table, ht