class_docstr: :class:`SMCFilter` is the top-level interface for filtering via sequential
  monte carlo.
  
  The model and guide should be objects with two methods:
  ``.init(state, ...)`` and ``.step(state, ...)``, intended to be called
  first with :meth:`init` , then with :meth:`step` repeatedly.  These two
  methods should have the same signature as :class:`SMCFilter` 's
  :meth:`init` and :meth:`step` of this class, but with an extra first
  argument ``state`` that should be used to store all tensors that depend on
  sampled variables. The ``state`` will be a dict-like object,
  :class:`SMCState` , with arbitrary keys and :class:`torch.Tensor` values.
  Models can read and write ``state`` but guides can only read from it.
  
  Inference complexity is ``O(len(state) * num_time_steps)``, so to avoid
  quadratic complexity in Markov models, ensure that ``state`` has fixed size.
  
  :param object model: probabilistic model with ``init`` and ``step`` methods
  :param object guide: guide used for sampling,  with ``init`` and ``step``
      methods
  :param int num_particles: The number of particles used to form the
      distribution.
  :param int max_plate_nesting: Bound on max number of nested
      :func:`pyro.plate` contexts.
  :param float ess_threshold: Effective sample size threshold for deciding
      when to importance resample: resampling occurs when
      ``ess < ess_threshold * num_particles``.
code: def _update_weights(self, model_trace, guide_trace):
      # w_t <-w_{t-1}*p(y_t|z_t) * p(z_t|z_t-1)/q(z_t)
  
      model_trace = prune_subsample_sites(model_trace)
      guide_trace = prune_subsample_sites(guide_trace)
  
      model_trace.compute_log_prob()
      guide_trace.compute_log_prob()
  
      for name, guide_site in guide_trace.nodes.items():
          if guide_site["type"] == "sample":
              model_site = model_trace.nodes[name]
              log_p = (
                  model_site["log_prob"]
                  .reshape(self.num_particles, -1)
                  .sum(-1)
              )
              log_q = (
                  guide_site["log_prob"]
                  .reshape(self.num_particles, -1)
                  .sum(-1)
              )
              self.state._log_weights += log_p - log_q
              if not (self.state._log_weights.max() > -math.inf):
                  raise SMCFailed(
                      "Failed to find feasible hypothesis after site {}".format(
                          name
                      )
                  )
  
      for site in model_trace.nodes.values():
          if site["type"] == "sample" and site["is_observed"]:
              log_p = (
                  site["log_prob"]
                  .reshape(self.num_particles, -1)
                  .sum(-1)
              )
              self.state._log_weights += log_p
              if not (self.state._log_weights.max() > -math.inf):
                  raise SMCFailed(
                      "Failed to find feasible hypothesis after site {}".format(
                          site["name"]
                      )
                  )
  
      self.state._log_weights -= self.state._log_weights.max()
  
imports: import contextlib
  import math
  import torch
  import pyro
  import pyro.distributions
  import pyro.poutine
  from pyro.infer.util import is_validation_enabled
  from pyro.poutine.util import prune_subsample_sites
label_desc: Use image node_id 5 for calling the SMCFilter obj's underlying member method code with example usage: obj._update_weights(model_trace, guide_trace) without return types