class_docstr: Superclass to implement Hamiltonian/hybrid monte carlo.
docstr: Perform a single HMC iteration.
docstr_tok: ["Perform","a","single","HMC","iteration","."]
code: def astep(self, q0: RaveledVars) -> tuple[RaveledVars, StatsType]:
      """Perform a single HMC iteration."""
      perf_start = time.perf_counter()
      process_start = time.process_time()
  
      p0 = self.potential.random()
      p0 = RaveledVars(p0, q0.point_map_info)
  
      start = self.integrator.compute_state(q0, p0)
  
      warning: SamplerWarning | None = None
      if not np.isfinite(start.energy):
          model = self._model
          check_test_point_dict = model.point_logps()
          check_test_point = np.asarray(
              list(check_test_point_dict.values())
          )
          error_logp = check_test_point[
              (np.abs(check_test_point) >= 1e20)
              | np.isnan(check_test_point)
          ]
          self.potential.raise_ok(q0.point_map_info)
          message_energy = (
              "Bad initial energy, check any log probabilities that "
              f"are inf or -inf, nan or very small:\n{error_logp}"
          )
          warning = SamplerWarning(
              WarningType.BAD_ENERGY,
              message_energy,
              "critical",
              self.iter_count,
          )
          raise SamplingError(f"Bad initial energy: {warning}")
  
      adapt_step = self.tune and self.adapt_step_size
      step_size = self.step_adapt.current(adapt_step)
      self.step_size = step_size
  
      if self._step_rand is not None:
          step_size = self._step_rand(step_size)
  
      hmc_step = self._hamiltonian_step(start, p0.data, step_size)
  
      perf_end = time.perf_counter()
      process_end = time.process_time()
  
      self.step_adapt.update(hmc_step.accept_stat, adapt_step)
      self.potential.update(
          hmc_step.end.q, hmc_step.end.q_grad, self.tune
      )
      if hmc_step.divergence_info:
          info = hmc_step.divergence_info
          point = None
          point_dest = None
          info_store = None
          if self.tune:
              kind = WarningType.TUNING_DIVERGENCE
          else:
              kind = WarningType.DIVERGENCE
              self._num_divs_sample += 1
              # We don't want to fill up all memory with divergence info
              if self._num_divs_sample < 100 and info.state is not None:
                  point = DictToArrayBijection.rmap(info.state.q)
  
              if (
                  self._num_divs_sample < 100
                  and info.state_div is not None
              ):
                  point_dest = DictToArrayBijection.rmap(
                      info.state_div.q
                  )
  
              if self._num_divs_sample < 100:
                  info_store = info
          warning = SamplerWarning(
              kind,
              info.message,
              "debug",
              self.iter_count,
              info.exec_info,
              divergence_point_source=point,
              divergence_point_dest=point_dest,
              divergence_info=info_store,
          )
  
      self.iter_count += 1
  
      stats: dict[str, Any] = {
          "tune": self.tune,
          "diverging": bool(hmc_step.divergence_info),
          "perf_counter_diff": perf_end - perf_start,
          "process_time_diff": process_end - process_start,
          "perf_counter_start": perf_start,
          "warning": warning,
      }
  
      stats.update(hmc_step.stats)
      stats.update(self.step_adapt.stats())
      stats.update(self.potential.stats())
  
      return hmc_step.end.q, [stats]
  
imports: from __future__ import annotations
  import logging
  import time
  from abc import abstractmethod
  from typing import Any, NamedTuple
  import numpy
  from pymc.blocking import DictToArrayBijection, RaveledVars, StatsType
  from pymc.exceptions import SamplingError
  from pymc.model import Point, modelcontext
  from pymc.pytensorf import floatX
  from pymc.stats.convergence import SamplerWarning, WarningType
  from pymc.step_methods import step_sizes
  from pymc.step_methods.arraystep import GradientSharedStep
  from pymc.step_methods.hmc import integration
  from pymc.step_methods.hmc.integration import IntegrationError, State
  from pymc.step_methods.hmc.quadpotential import QuadPotentialDiagAdapt, quad_potential
  from pymc.tuning import guess_scaling
  from pymc.util import get_value_vars_from_user_vars
label_desc: Use image node_id 3 for calling the BaseHMC obj's underlying member method code with example usage: obj.astep(q0) and returns: hmc_step,  list