docs: def is_reversible(T, mu=None, tol=1e-12):
      r"""Check reversibility of the given transition matrix.
  
      Parameters
      ----------
      T : (M, M) ndarray or scipy.sparse matrix
          Transition matrix
      mu : (M,) ndarray (optional)
           Test reversibility with respect to this vector
      tol : float (optional)
          Floating point tolerance to check with
  
      Returns
      -------
      is_reversible : bool
          True, if T is reversible, False otherwise
  
      Notes
      -----
      A transition matrix :math:`T=(t_{ij})` is reversible with respect
      to a probability vector :math:`\mu=(\mu_i)` if the follwing holds,
  
      .. math:: \mu_i \, t_{ij}= \mu_j \, t_{ji}.
  
      In this case :math:`\mu` is the stationary vector for :math:`T`,
      so that :math:`\mu^T T = \mu^T`.
  
      If the stationary vector is unknown it is computed from :math:`T`
      before reversibility is checked.
  
      A reversible transition matrix has purely real eigenvalues. The
      left eigenvectors :math:`(l_i)` can be computed from right
      eigenvectors :math:`(r_i)` via :math:`l_i=\mu_i r_i`.
  
      Examples
      --------
  
      >>> import numpy as np
      >>> from msmtools.analysis import is_reversible
  
      >>> P = np.array([[0.8, 0.1, 0.1], [0.5, 0.0, 0.5], [0.0, 0.1, 0.9]])
      >>> is_reversible(P)
      False
  
      >>> T = np.array([[0.9, 0.1, 0.0], [0.5, 0.0, 0.5], [0.0, 0.1, 0.9]])
      >>> is_reversible(T)
      True
  
      """
      # check input
      T = _types.ensure_ndarray_or_sparse(T, ndim=2, uniform=True, kind='numeric')
      mu = _types.ensure_float_vector_or_None(mu, require_order=True)
      # go
      if _issparse(T):
          return sparse.assessment.is_reversible(T, mu, tol)
      else:
          return dense.assessment.is_reversible(T, mu, tol)