code: def pca(
      entry_expr, k=10, compute_loadings=False
  ) -> Tuple[List[float], Table, Table]:
      r"""Run principal component analysis (PCA) on numeric columns derived from a
      matrix table.
  
      Examples
      --------
  
      For a matrix table with variant rows, sample columns, and genotype entries,
      compute the top 2 PC sample scores and eigenvalues of the matrix of 0s and
      1s encoding missingness of genotype calls.
  
      >>> eigenvalues, scores, _ = hl.pca(hl.int(hl.is_defined(dataset.GT)),
      ...                                 k=2)
  
      Warning
      -------
        This method does **not** automatically mean-center or normalize each column.
        If desired, such transformations should be incorporated in `entry_expr`.
  
        Hail will return an error if `entry_expr` evaluates to missing, nan, or
        infinity on any entry.
  
      Notes
      -----
  
      PCA is run on the columns of the numeric matrix obtained by evaluating
      `entry_expr` on each entry of the matrix table, or equivalently on the rows
      of the **transposed** numeric matrix :math:`M` referenced below.
  
      PCA computes the SVD
  
      .. math::
  
        M = USV^T
  
      where columns of :math:`U` are left singular vectors (orthonormal in
      :math:`\mathbb{R}^n`), columns of :math:`V` are right singular vectors
      (orthonormal in :math:`\mathbb{R}^m`), and :math:`S=\mathrm{diag}(s_1, s_2,
      \ldots)` with ordered singular values :math:`s_1 \ge s_2 \ge \cdots \ge 0`.
      Typically one computes only the first :math:`k` singular vectors and values,
      yielding the best rank :math:`k` approximation :math:`U_k S_k V_k^T` of
      :math:`M`; the truncations :math:`U_k`, :math:`S_k` and :math:`V_k` are
      :math:`n \times k`, :math:`k \times k` and :math:`m \times k`
      respectively.
  
      From the perspective of the rows of :math:`M` as samples (data points),
      :math:`V_k` contains the loadings for the first :math:`k` PCs while
      :math:`MV_k = U_k S_k` contains the first :math:`k` PC scores of each
      sample. The loadings represent a new basis of features while the scores
      represent the projected data on those features. The eigenvalues of the Gramian
      :math:`MM^T` are the squares of the singular values :math:`s_1^2, s_2^2,
      \ldots`, which represent the variances carried by the respective PCs. By
      default, Hail only computes the loadings if the ``loadings`` parameter is
      specified.
  
      Scores are stored in a :class:`.Table` with the column key of the matrix
      table as key and a field `scores` of type ``array<float64>`` containing
      the principal component scores.
  
      Loadings are stored in a :class:`.Table` with the row key of the matrix
      table as key and a field `loadings` of type ``array<float64>`` containing
      the principal component loadings.
  
      The eigenvalues are returned in descending order, with scores and loadings
      given the corresponding array order.
  
      Parameters
      ----------
      entry_expr : :class:`.Expression`
          Numeric expression for matrix entries.
      k : :obj:`int`
          Number of principal components.
      compute_loadings : :obj:`bool`
          If ``True``, compute row loadings.
  
      Returns
      -------
      (:obj:`list` of :obj:`float`, :class:`.Table`, :class:`.Table`)
          List of eigenvalues, table with column scores, table with row loadings.
      """
      from hail.backend.service_backend import ServiceBackend
  
      if isinstance(hl.current_backend(), ServiceBackend):
          return _blanczos_pca(entry_expr, k, compute_loadings)
  
      raise_unless_entry_indexed("pca/entry_expr", entry_expr)
  
      mt = matrix_table_source("pca/entry_expr", entry_expr)
  
      #  FIXME: remove once select_entries on a field is free
      if entry_expr in mt._fields_inverse:
          field = mt._fields_inverse[entry_expr]
      else:
          field = Env.get_uid()
          mt = mt.select_entries(**{field: entry_expr})
      mt = mt.select_cols().select_rows().select_globals()
  
      t = Table(
          ir.MatrixToTableApply(
              mt._mir,
              {
                  "name": "PCA",
                  "entryField": field,
                  "k": k,
                  "computeLoadings": compute_loadings,
              },
          )
      ).persist()
  
      g = t.index_globals()
      scores = hl.Table.parallelize(g.scores, key=list(mt.col_key))
      if not compute_loadings:
          t = None
      return (
          hl.eval(g.eigenvalues),
          scores,
          None if t is None else t.drop("eigenvalues", "scores"),
      )
  
imports: from typing import List, Tuple
  import hail
  import hail.expr.aggregators
  from hail.expr.expressions import construct_expr
  from hail.expr import expr_float64, expr_call, raise_unless_entry_indexed, matrix_table_source
  from hail import ir
  from hail.table import Table
  from hail.typecheck import typecheck, oneof, nullable
  from hail.utils import FatalError
  from hail.utils.java import Env, info
  from hail.experimental import mt_to_table_of_ndarray
label_desc: Use image node_id 3 for calling a global function with example usage: pca(entry_expr, k, compute_loadings) and returns: hl,  scores,  unknown, _blanczos_pca