class_docstr: Hidden Markov Model with discrete latent state and arbitrary observation
  distribution. This uses [1] to parallelize over time, achieving
  O(log(time)) parallel complexity.
  
  The event_shape of this distribution includes time on the left::
  
      event_shape = (num_steps,) + observation_dist.event_shape
  
  This distribution supports any combination of homogeneous/heterogeneous
  time dependency of ``transition_logits`` and ``observation_dist``. However,
  because time is included in this distribution's event_shape, the
  homogeneous+homogeneous case will have a broadcastable event_shape with
  ``num_steps = 1``, allowing :meth:`log_prob` to work with arbitrary length
  data::
  
      # homogeneous + homogeneous case:
      event_shape = (1,) + observation_dist.event_shape
  
  This class should be interchangeable with
  :class:`pyro.distributions.hmm.DiscreteHMM` .
  
  **References:**
  
  [1] Simo Sarkka, Angel F. Garcia-Fernandez (2019)
      "Temporal Parallelization of Bayesian Filters and Smoothers"
      https://arxiv.org/pdf/1905.13002.pdf
  
  :param ~torch.Tensor initial_logits: A logits tensor for an initial
      categorical distribution over latent states. Should have rightmost size
      ``state_dim`` and be broadcastable to ``batch_shape + (state_dim,)``.
  :param ~torch.Tensor transition_logits: A logits tensor for transition
      conditional distributions between latent states. Should have rightmost
      shape ``(state_dim, state_dim)`` (old, new), and be broadcastable to
      ``batch_shape + (num_steps, state_dim, state_dim)``.
  :param ~torch.distributions.Distribution observation_dist: A conditional
      distribution of observed data conditioned on latent state. The
      ``.batch_shape`` should have rightmost size ``state_dim`` and be
      broadcastable to ``batch_shape + (num_steps, state_dim)``. The
      ``.event_shape`` may be arbitrary.
code: def expand(self, batch_shape, _instance=None):
      new = self._get_checked_instance(DiscreteHMM, _instance)
      batch_shape = torch.Size(batch_shape)
      new._has_rsample = self._has_rsample
      new._init = self._init + tensor_to_funsor(
          torch.zeros(batch_shape)
      )
      new._trans = self._trans
      new._obs = self._obs
      super(DiscreteHMM, new).__init__(
          self.funsor_dist,
          batch_shape,
          self.event_shape,
          self.dtype,
          validate_args=False,
      )
      new.validate_args = self.__dict__.get("_validate_args")
      return new
  
imports: from collections import OrderedDict
  import torch
  import funsor.ops
  from funsor.domains import Bint, Reals
  from funsor.interpretations import eager, lazy, moment_matching
  from funsor.pyro.convert import dist_to_funsor, funsor_to_cat_and_mvn, funsor_to_tensor, matrix_and_mvn_to_funsor, mvn_to_funsor, tensor_to_funsor
  from funsor.pyro.distribution import FunsorDistribution
  from funsor.sum_product import MarkovProduct, naive_sequential_sum_product, sequential_sum_product
  from funsor.terms import Variable
  from funsor.util import broadcast_shape
label_desc: Use image node_id 5 for calling the DiscreteHMM obj's underlying member method code with example usage: obj.expand(batch_shape, _instance) and returns: new