docstr: Perform a leapfrog step and handle error cases.
docstr_tok: ["Perform","a","leapfrog","step","and","handle","error","cases","."]
code: def _single_step(self, left: State, epsilon: float):
      """Perform a leapfrog step and handle error cases."""
      right: State | None
      error: IntegrationError | None
      error_msg: str | None
      try:
          right = self.integrator.step(epsilon, left)
      except IntegrationError as err:
          error_msg = str(err)
          error = err
          right = None
      else:
          assert (
              right is not None
          )  # since there was no IntegrationError
          # h - H0
          energy_change = right.energy - self.start_energy
          if np.isnan(energy_change):
              energy_change = np.inf
  
          self.log_accept_sum = np.logaddexp(
              self.log_accept_sum, min(0, -energy_change)
          )
  
          if np.abs(energy_change) > np.abs(self.max_energy_change):
              self.max_energy_change = energy_change
          if energy_change < self.Emax:
              # Acceptance statistic
              # e^{H(q_0, p_0) - H(q_n, p_n)} max(1, e^{H(q_0, p_0) - H(q_n, p_n)})
              # Saturated Metropolis accept probability with Boltzmann weight
              log_size = -energy_change
              proposal = Proposal(
                  right.q.data,
                  right.q_grad,
                  right.energy,
                  right.model_logp,
                  right.index_in_trajectory,
              )
              tree = Subtree(
                  right, right, right.p.data, proposal, log_size
              )
              return tree, None, False
          else:
              error_msg = f"Energy change in leapfrog step is too large: {energy_change}."
              error = None
      finally:
          self.n_proposals += 1
      tree = Subtree(None, None, None, None, -np.inf)
      divergence_info = DivergenceInfo(error_msg, error, left, right)
      return tree, divergence_info, False
  
imports: from __future__ import annotations
  from collections import namedtuple
  import numpy
  from pymc.math import logbern
  from pymc.pytensorf import floatX
  from pymc.stats.convergence import SamplerWarning
  from pymc.step_methods.compound import Competence
  from pymc.step_methods.hmc import integration
  from pymc.step_methods.hmc.base_hmc import BaseHMC, DivergenceInfo, HMCStepData
  from pymc.step_methods.hmc.integration import IntegrationError, State
  from pymc.vartypes import continuous_types
label_desc: Use image node_id 3 for calling the _Tree obj's underlying member method code with example usage: obj._single_step(left, epsilon) and returns: tree,  divergence_info,  False, tree,  None,  False