code: def ld_matrix(
      entry_expr, locus_expr, radius, coord_expr=None, block_size=None
  ) -> BlockMatrix:
      """Computes the windowed correlation (linkage disequilibrium) matrix between
      variants.
  
      Examples
      --------
      Consider the following dataset consisting of three variants with centimorgan
      coordinates and four samples:
  
      >>> data = [{'v': '1:1:A:C',       'cm': 0.1, 's': 'a', 'GT': hl.Call([0, 0])},
      ...         {'v': '1:1:A:C',       'cm': 0.1, 's': 'b', 'GT': hl.Call([0, 0])},
      ...         {'v': '1:1:A:C',       'cm': 0.1, 's': 'c', 'GT': hl.Call([0, 1])},
      ...         {'v': '1:1:A:C',       'cm': 0.1, 's': 'd', 'GT': hl.Call([1, 1])},
      ...         {'v': '1:2000000:G:T', 'cm': 0.9, 's': 'a', 'GT': hl.Call([0, 1])},
      ...         {'v': '1:2000000:G:T', 'cm': 0.9, 's': 'b', 'GT': hl.Call([1, 1])},
      ...         {'v': '1:2000000:G:T', 'cm': 0.9, 's': 'c', 'GT': hl.Call([0, 1])},
      ...         {'v': '1:2000000:G:T', 'cm': 0.9, 's': 'd', 'GT': hl.Call([0, 0])},
      ...         {'v': '2:1:C:G',       'cm': 0.2, 's': 'a', 'GT': hl.Call([0, 1])},
      ...         {'v': '2:1:C:G',       'cm': 0.2, 's': 'b', 'GT': hl.Call([0, 0])},
      ...         {'v': '2:1:C:G',       'cm': 0.2, 's': 'c', 'GT': hl.Call([1, 1])},
      ...         {'v': '2:1:C:G',       'cm': 0.2, 's': 'd', 'GT': hl.missing(hl.tcall)}]
      >>> ht = hl.Table.parallelize(data, hl.dtype('struct{v: str, s: str, cm: float64, GT: call}'))
      >>> ht = ht.transmute(**hl.parse_variant(ht.v))
      >>> mt = ht.to_matrix_table(row_key=['locus', 'alleles'], col_key=['s'], row_fields=['cm'])
  
      Compute linkage disequilibrium between all pairs of variants on the same
      contig and within two megabases:
  
      >>> ld = hl.ld_matrix(mt.GT.n_alt_alleles(), mt.locus, radius=2e6)
      >>> ld.to_numpy()
      array([[ 1.        , -0.85280287,  0.        ],
             [-0.85280287,  1.        ,  0.        ],
             [ 0.        ,  0.        ,  1.        ]])
  
      Within one megabases:
  
      >>> ld = hl.ld_matrix(mt.GT.n_alt_alleles(), mt.locus, radius=1e6)
      >>> ld.to_numpy()
      array([[1., 0., 0.],
             [0., 1., 0.],
             [0., 0., 1.]])
  
      Within one centimorgan:
  
      >>> ld = hl.ld_matrix(mt.GT.n_alt_alleles(), mt.locus, radius=1.0, coord_expr=mt.cm)
      >>> ld.to_numpy()
      array([[ 1.        , -0.85280287,  0.        ],
             [-0.85280287,  1.        ,  0.        ],
             [ 0.        ,  0.        ,  1.        ]])
  
      Within one centimorgan, and only calculate the upper triangle:
  
      >>> ld = hl.ld_matrix(mt.GT.n_alt_alleles(), mt.locus, radius=1.0, coord_expr=mt.cm)
      >>> ld = ld.sparsify_triangle()
      >>> ld.to_numpy()
      array([[ 1.        , -0.85280287,  0.        ],
             [ 0.        ,  1.        ,  0.        ],
             [ 0.        ,  0.        ,  1.        ]])
  
      Notes
      -----
      This method sparsifies the result of :meth:`row_correlation` using
      :func:`.linalg.utils.locus_windows` and
      :meth:`.BlockMatrix.sparsify_row_intervals`
      in order to only compute linkage disequilibrium between nearby
      variants. Use :meth:`row_correlation` directly to calculate correlation
      without windowing.
  
      More precisely, variants are 0-indexed by their order in the matrix table
      (see :meth:`~hail.MatrixTable.add_row_index`). Each variant is regarded as a vector of
      elements defined by `entry_expr`, typically the number of alternate alleles
      or genotype dosage. Missing values are mean-imputed within variant.
  
      The method produces a symmetric block-sparse matrix supported in a
      neighborhood of the diagonal. If variants :math:`i` and :math:`j` are on the
      same contig and within `radius` base pairs (inclusive) then the
      :math:`(i, j)` element is their
      `Pearson correlation coefficient <https://en.wikipedia.org/wiki/Pearson_correlation_coefficient>`__.
      Otherwise, the :math:`(i, j)` element is ``0.0``.
  
      Rows with a constant value (i.e., zero variance) will result in ``nan``
      correlation values. To avoid this, first check that all variants vary or
      filter out constant variants (for example, with the help of
      :func:`.aggregators.stats`).
  
      If the :meth:`.global_position` on `locus_expr` is not in ascending order,
      this method will fail. Ascending order should hold for a matrix table keyed
      by locus or variant (and the associated row table), or for a table that's
      been ordered by `locus_expr`.
  
      Set `coord_expr` to use a value other than position to define the windows.
      This row-indexed numeric expression must be non-missing, non-``nan``, on the
      same source as `locus_expr`, and ascending with respect to locus
      position for each contig; otherwise the method will raise an error.
  
      Warning
      -------
      See the warnings in :meth:`row_correlation`. In particular, for large
      matrices it may be preferable to run its stages separately.
  
      `entry_expr` and `locus_expr` are implicitly aligned by row-index, though
      they need not be on the same source. If their sources differ in the number
      of rows, an error will be raised; otherwise, unintended misalignment may
      silently produce unexpected results.
  
      Parameters
      ----------
      entry_expr : :class:`.Float64Expression`
          Entry-indexed numeric expression on matrix table.
      locus_expr : :class:`.LocusExpression`
          Row-indexed locus expression on a table or matrix table that is
          row-aligned with the matrix table of `entry_expr`.
      radius: :obj:`int` or :obj:`float`
          Radius of window for row values.
      coord_expr: :class:`.Float64Expression`, optional
          Row-indexed numeric expression for the row value on the same table or
          matrix table as `locus_expr`.
          By default, the row value is given by the locus position.
      block_size : :obj:`int`, optional
          Block size. Default given by :meth:`.BlockMatrix.default_block_size`.
  
      Returns
      -------
      :class:`.BlockMatrix`
          Windowed correlation matrix between variants.
          Row and column indices correspond to matrix table variant index.
      """
      starts_and_stops = hl.linalg.utils.locus_windows(
          locus_expr, radius, coord_expr, _localize=False
      )
      starts_and_stops = hl.tuple(
          [
              starts_and_stops[0].map(lambda i: hl.int64(i)),
              starts_and_stops[1].map(lambda i: hl.int64(i)),
          ]
      )
      ld = hl.row_correlation(entry_expr, block_size)
      return ld._sparsify_row_intervals_expr(
          starts_and_stops, blocks_only=False
      )
  
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 31 for calling a global function with example usage: ld_matrix(entry_expr, locus_expr, radius, coord_expr, block_size) and returns: ld