class_docstr: Non-normalized Gaussian distribution.
  
  This represents an arbitrary semidefinite quadratic function, which can be
  interpreted as a rank-deficient scaled Gaussian distribution. The precision
  matrix may have zero eigenvalues, thus it may be impossible to work
  directly with the covariance matrix.
  
  :param torch.Tensor log_normalizer: a normalization constant, which is mainly used to keep
      track of normalization terms during contractions.
  :param torch.Tensor info_vec: information vector, which is a scaled version of the mean
      ``info_vec = precision @ mean``. We use this represention to make gaussian contraction
      fast and stable.
  :param torch.Tensor precision: precision matrix of this gaussian.
class_docstr_tok: ["Non-normalized","Gaussian","distribution",".","This","represents","an","arbitrary","semidefinite","quadratic","function",",","which","can","be","interpreted","as","a","rank-deficient","scaled","Gaussian","distribution",".","The","precision","matrix","may","have","zero","eigenvalues",",","thus","it","may","be","impossible","to","work","directly","with","the","covariance","matrix",".",":","param","torch.Tensor","log_normalizer",":","a","normalization","constant",",","which","is","mainly","used","to","keep","track","of","normalization","terms","during","contractions",".",":","param","torch.Tensor","info_vec",":","information","vector",",","which","is","a","scaled","version","of","the","mean","``","info_vec","=","precision","@","mean","``",".","We","use","this","represention","to","make","gaussian","contraction","fast","and","stable",".",":","param","torch.Tensor","precision",":","precision","matrix","of","this","gaussian","."]
docstr: Marginalizing out variables on either side of the event dimension::
  
      g.marginalize(left=n).event_logsumexp() = g.logsumexp()
      g.marginalize(right=n).event_logsumexp() = g.logsumexp()
  
  and for data ``x``:
  
      g.condition(x).event_logsumexp()
        = g.marginalize(left=g.dim() - x.size(-1)).log_density(x)
code: def marginalize(self, left=0, right=0) -> "Gaussian":
      """
      Marginalizing out variables on either side of the event dimension::
  
          g.marginalize(left=n).event_logsumexp() = g.logsumexp()
          g.marginalize(right=n).event_logsumexp() = g.logsumexp()
  
      and for data ``x``:
  
          g.condition(x).event_logsumexp()
            = g.marginalize(left=g.dim() - x.size(-1)).log_density(x)
      """
      if left == 0 and right == 0:
          return self
      if left > 0 and right > 0:
          raise NotImplementedError
      n = self.dim()
      n_b = left + right
      a = slice(left, n - right)  # preserved
      b = slice(None, left) if left else slice(n - right, None)
  
      P_aa = self.precision[..., a, a]
      P_ba = self.precision[..., b, a]
      P_bb = self.precision[..., b, b]
      P_b = safe_cholesky(P_bb)
      P_a = triangular_solve(P_ba, P_b, upper=False)
      P_at = P_a.transpose(-1, -2)
      precision = P_aa - matmul(P_at, P_a)
  
      info_a = self.info_vec[..., a]
      info_b = self.info_vec[..., b]
      b_tmp = triangular_solve(info_b.unsqueeze(-1), P_b, upper=False)
      info_vec = info_a - matmul(P_at, b_tmp).squeeze(-1)
  
      log_normalizer = (
          self.log_normalizer
          + 0.5 * n_b * math.log(2 * math.pi)
          - P_b.diagonal(dim1=-2, dim2=-1).log().sum(-1)
          + 0.5 * b_tmp.squeeze(-1).pow(2).sum(-1)
      )
      return Gaussian(log_normalizer, info_vec, precision)
  
imports: import math
  from typing import Optional, Tuple, Union
  import torch
  from torch.distributions.utils import lazy_property
  from torch.nn.functional import pad
  from pyro.distributions.util import broadcast_shape
  from pyro.ops.tensor_utils import matmul, matvecmul, safe_cholesky, triangular_solve
label_desc: Use image node_id 16 for calling the Gaussian obj's underlying member method code with example usage: obj.marginalize(left, right) and returns: Gaussian, self