code: def matrix_and_mvn_to_funsor(
      matrix, mvn, event_dims=(), x_name="value_x", y_name="value_y"
  ):
      """
      Convert a noisy affine function to a Gaussian. The noisy affine function is
      defined as::
  
          y = x @ matrix + mvn.sample()
  
      The result is a non-normalized Gaussian funsor with two real inputs,
      ``x_name`` and ``y_name``, corresponding to a conditional distribution of
      real vector ``y` given real vector ``x``.
  
      :param torch.Tensor matrix: A matrix with rightmost shape ``(x_size, y_size)``.
      :param mvn: A multivariate normal distribution with
          ``event_shape == (y_size,)``.
      :type mvn: torch.distributions.MultivariateNormal or
          torch.distributions.Independent of torch.distributions.Normal
      :param tuple event_dims: A tuple of names for rightmost dimensions.
          These will be assigned to ``result.inputs`` of type ``Bint``.
      :param str x_name: The name of the ``x`` random variable.
      :param str y_name: The name of the ``y`` random variable.
      :return: A funsor with given ``real_inputs`` and possibly additional
          Bint inputs.
      :rtype: funsor.terms.Funsor
      """
      assert isinstance(
          mvn, torch.distributions.MultivariateNormal
      ) or (
          isinstance(mvn, torch.distributions.Independent)
          and isinstance(mvn.base_dist, torch.distributions.Normal)
      )
      assert isinstance(matrix, torch.Tensor)
      x_size, y_size = matrix.shape[-2:]
      assert mvn.event_shape == (y_size,)
  
      # Handle diagonal normal distributions as an efficient special case.
      if isinstance(mvn, torch.distributions.Independent):
          # Create an i-batched Gaussian over x and y_i.
          log_prob = -0.5 * y_size * math.log(
              2 * math.pi
          ) - mvn.base_dist.scale.log().sum(-1)
          log_prob = tensor_to_funsor(log_prob, event_dims)
  
          matrix_x = ops.transpose(matrix, -1, -2)  # [...,Y,X]
          matrix_y = ops.new_full(
              matrix_x, matrix_x.shape[:-1] + (1,), -1.0
          )  # [...,Y,1]
          matrix_xy = ops.cat([matrix_x, matrix_y], -1)  # [...,Y,X+1]
          prec_sqrt = (matrix_xy / mvn.base_dist.scale[..., None])[
              ..., None
          ]
          white_vec = (-mvn.base_dist.loc / mvn.base_dist.scale)[
              ..., None
          ]
  
          i = Variable(gensym("i"), Bint[y_size])
          y_i = Variable(gensym(f"{y_name}_i"), Real)
          inputs = log_prob.inputs.copy()
          inputs[i.name] = i.output
          inputs[x_name] = Reals[x_size]
          inputs[y_i.name] = Real
          g_i = Gaussian(
              white_vec=white_vec, prec_sqrt=prec_sqrt, inputs=inputs
          )
  
          # Convert to a joint Gaussian over x and y, possibly lazily.
          # This expands the y part of the matrix from linear to square,
          # incurring asymptotic increase O((X+1)Y) ==> O((X+Y)Y).
          #
          #   [ ? ? ? ? ? | ? ]      [ ? ? ? ? ? | ? . . . ]
          #   [ ? ? ? ? ? | ? ] ===> [ ? ? ? ? ? | . ? . . ]
          #   [ ? ? ? ? ? | ? ]      [ ? ? ? ? ? | . . ? . ]
          #   [ ? ? ? ? ? | ? ]      [ ? ? ? ? ? | . . . ? ]
          g = Independent(g_i, y_name, i.name, y_i.name)
          # Equivalently, g_i(**{y_i.name: y[i]}).reduce(ops.add, i)
          return g + log_prob
  
      # Create a rank-y Gaussian over (x,y).
      log_prob = -0.5 * y_size * math.log(
          2 * math.pi
      ) - mvn.scale_tril.diagonal(dim1=-1, dim2=-2).log().sum(-1)
      log_prob = tensor_to_funsor(log_prob, event_dims)
  
      prec_sqrt_y = ops.transpose(
          ops.triangular_inv(mvn.scale_tril), -1, -2
      )
      prec_sqrt_xy = matrix @ prec_sqrt_y
      prec_sqrt_yy = (-prec_sqrt_y).expand(
          prec_sqrt_xy.shape[:-2] + (-1, -1)
      )
      prec_sqrt = ops.cat([prec_sqrt_xy, prec_sqrt_yy], -2)
      white_vec = (-mvn.loc[..., None, :] @ prec_sqrt_y)[..., 0, :]
      white_vec = white_vec.expand(prec_sqrt.shape[:-2] + (-1,))
  
      # Note the round trip tensor_to_funsor(...).data strips leading 1's from the shape.
      white_vec = tensor_to_funsor(white_vec, event_dims, 1)
      prec_sqrt = tensor_to_funsor(prec_sqrt, event_dims, 2)
      inputs = white_vec.inputs.copy()
      inputs[x_name] = Reals[x_size]
      inputs[y_name] = Reals[y_size]
      g = Gaussian(
          white_vec=white_vec.data,
          prec_sqrt=prec_sqrt.data,
          inputs=inputs,
      )
      return g + log_prob
  
imports: import math
  from collections import OrderedDict
  import torch
  import funsor.ops
  from funsor.cnf import Contraction
  from funsor.delta import Delta
  from funsor.domains import Array, Bint, Real, Reals
  from funsor.gaussian import Gaussian
  from funsor.interpreter import gensym
  from funsor.tensor import Tensor
  from funsor.terms import Independent, Variable, to_data, to_funsor
label_desc: Use image node_id 9 for calling a global function with example usage: matrix_and_mvn_to_funsor(matrix, mvn, event_dims, x_name, y_name) and returns: unknown, unknown