class_docstr: Simple Hamiltonian Monte Carlo kernel, where ``step_size`` and ``num_steps``
  need to be explicitly specified by the user.
  
  **References**
  
  [1] `MCMC Using Hamiltonian Dynamics`,
  Radford M. Neal
  
  :param model: Python callable containing Pyro primitives.
  :param potential_fn: Python callable calculating potential energy with input
      is a dict of real support parameters.
  :param float step_size: Determines the size of a single step taken by the
      verlet integrator while computing the trajectory using Hamiltonian
      dynamics. If not specified, it will be set to 1.
  :param float trajectory_length: Length of a MCMC trajectory. If not
      specified, it will be set to ``step_size x num_steps``. In case
      ``num_steps`` is not specified, it will be set to :math:`2\pi`.
  :param int num_steps: The number of discrete steps over which to simulate
      Hamiltonian dynamics. The state at the end of the trajectory is
      returned as the proposal. This value is always equal to
      ``int(trajectory_length / step_size)``.
  :param bool adapt_step_size: A flag to decide if we want to adapt step_size
      during warm-up phase using Dual Averaging scheme.
  :param bool adapt_mass_matrix: A flag to decide if we want to adapt mass
      matrix during warm-up phase using Welford scheme.
  :param bool full_mass: A flag to decide if mass matrix is dense or diagonal.
  :param dict transforms: Optional dictionary that specifies a transform
      for a sample site with constrained support to unconstrained space. The
      transform should be invertible, and implement `log_abs_det_jacobian`.
      If not specified and the model has sites with constrained support,
      automatic transformations will be applied, as specified in
      :mod:`torch.distributions.constraint_registry`.
  :param int max_plate_nesting: Optional bound on max number of nested
      :func:`pyro.plate` contexts. This is required if model contains
      discrete sample sites that can be enumerated over in parallel.
  :param bool jit_compile: Optional parameter denoting whether to use
      the PyTorch JIT to trace the log density computation, and use this
      optimized executable trace in the integrator.
  :param dict jit_options: A dictionary contains optional arguments for
      :func:`torch.jit.trace` function.
  :param bool ignore_jit_warnings: Flag to ignore warnings from the JIT
      tracer when ``jit_compile=True``. Default is False.
  :param float target_accept_prob: Increasing this value will lead to a smaller
      step size, hence the sampling will be slower and more robust. Default to 0.8.
  :param callable init_strategy: A per-site initialization function.
      See :ref:`autoguide-initialization` section for available functions.
  :param min_stepsize (float): Lower bound on stepsize in adaptation strategy.
  :param max_stepsize (float): Upper bound on stepsize in adaptation strategy.
  
  .. note:: Internally, the mass matrix will be ordered according to the order
      of the names of latent variables, not the order of their appearance in
      the model.
  
  Example:
  
      >>> true_coefs = torch.tensor([1., 2., 3.])
      >>> data = torch.randn(2000, 3)
      >>> dim = 3
      >>> labels = dist.Bernoulli(logits=(true_coefs * data).sum(-1)).sample()
      >>>
      >>> def model(data):
      ...     coefs_mean = torch.zeros(dim)
      ...     coefs = pyro.sample('beta', dist.Normal(coefs_mean, torch.ones(3)))
      ...     y = pyro.sample('y', dist.Bernoulli(logits=(coefs * data).sum(-1)), obs=labels)
      ...     return y
      >>>
      >>> hmc_kernel = HMC(model, step_size=0.0855, num_steps=4)
      >>> mcmc = MCMC(hmc_kernel, num_samples=500, warmup_steps=100)
      >>> mcmc.run(data)
      >>> mcmc.get_samples()['beta'].mean(0)  # doctest: +SKIP
      tensor([ 0.9819,  1.9258,  2.9737])
code: def _find_reasonable_step_size(self, z):
      step_size = self.step_size
  
      # We are going to find a step_size which make accept_prob (Metropolis correction)
      # near the target_accept_prob. If accept_prob:=exp(-delta_energy) is small,
      # then we have to decrease step_size; otherwise, increase step_size.
      try:
          potential_energy = self.potential_fn(z)
      # handle exceptions as defined in the exception registry
      except Exception as e:
          if any(h(e) for h in _EXCEPTION_HANDLERS.values()):
              # skip finding reasonable step size
              return step_size
          else:
              raise e
  
      r, r_unscaled = self._sample_r(name="r_presample_0")
      energy_current = (
          self._kinetic_energy(r_unscaled) + potential_energy
      )
      # This is required so as to avoid issues with autograd when model
      # contains transforms with cache_size > 0 (https://github.com/pyro-ppl/pyro/issues/2292)
      z = {k: v.clone() for k, v in z.items()}
      z_new, r_new, z_grads_new, potential_energy_new = velocity_verlet(
          z,
          r,
          self.potential_fn,
          self.mass_matrix_adapter.kinetic_grad,
          step_size,
      )
      r_new_unscaled = self.mass_matrix_adapter.unscale(r_new)
      energy_new = (
          self._kinetic_energy(r_new_unscaled) + potential_energy_new
      )
      delta_energy = energy_new - energy_current
      # direction=1 means keep increasing step_size, otherwise decreasing step_size.
      # Note that the direction is -1 if delta_energy is `NaN` which may be the
      # case for a diverging trajectory (e.g. in the case of evaluating log prob
      # of a value simulated using a large step size for a constrained sample site).
      direction = 1 if self._direction_threshold < -delta_energy else -1
  
      # define scale for step_size: 2 for increasing, 1/2 for decreasing
      step_size_scale = 2**direction
      direction_new = direction
      # keep scale step_size until accept_prob crosses its target
      t = 0
      while (
          direction_new == direction
          and self._min_stepsize < step_size < self._max_stepsize
      ):
          t += 1
          step_size = step_size_scale * step_size
          r, r_unscaled = self._sample_r(
              name="r_presample_{}".format(t)
          )
          energy_current = (
              self._kinetic_energy(r_unscaled) + potential_energy
          )
          (
              z_new,
              r_new,
              z_grads_new,
              potential_energy_new,
          ) = velocity_verlet(
              z,
              r,
              self.potential_fn,
              self.mass_matrix_adapter.kinetic_grad,
              step_size,
          )
          r_new_unscaled = self.mass_matrix_adapter.unscale(r_new)
          energy_new = (
              self._kinetic_energy(r_new_unscaled)
              + potential_energy_new
          )
          delta_energy = energy_new - energy_current
          direction_new = (
              1 if self._direction_threshold < -delta_energy else -1
          )
      step_size = max(step_size, self._min_stepsize)
      step_size = min(step_size, self._max_stepsize)
      return step_size
  
imports: import math
  from collections import OrderedDict
  import torch
  import pyro
  import pyro.distributions
  from pyro.distributions.testing.fakes import NonreparameterizedNormal
  from pyro.distributions.util import scalar_like
  from pyro.infer.autoguide import init_to_uniform
  from pyro.infer.mcmc.adaptation import WarmupAdapter
  from pyro.infer.mcmc.mcmc_kernel import MCMCKernel
  from pyro.infer.mcmc.util import initialize_model
  from pyro.ops.integrator import _EXCEPTION_HANDLERS, potential_grad, velocity_verlet
  from pyro.util import optional, torch_isnan
label_desc: Use image node_id 4 for calling the HMC obj's underlying member method code with example usage: obj._find_reasonable_step_size(z) and returns: step_size, step_size