docs: def fingerprint_relaxation(T, p0, obs, tau=1, k=None, ncv=None):
      r"""Dynamical fingerprint for relaxation experiment.
  
      The dynamical fingerprint is given by the implied time-scale
      spectrum together with the corresponding amplitudes.
  
      Parameters
      ----------
      T : (M, M) ndarray or scipy.sparse matrix
          Transition matrix
      obs1 : (M,) ndarray
          Observable, represented as vector on state space
      obs2 : (M,) ndarray (optional)
          Second observable, for cross-correlations
      k : int (optional)
          Number of time-scales and amplitudes to compute
      tau : int (optional)
          Lag time of given transition matrix, for correct time-scales
      ncv : int (optional)
          The number of Lanczos vectors generated, `ncv` must be greater than k;
          it is recommended that ncv > 2*k
  
      Returns
      -------
      timescales : (N,) ndarray
          Time-scales of the transition matrix
      amplitudes : (N,) ndarray
          Amplitudes for the relaxation experiment
  
      See also
      --------
      relaxation, fingerprint_correlation
  
      References
      ----------
      .. [1] Noe, F, S Doose, I Daidone, M Loellmann, M Sauer, J D
          Chodera and J Smith. 2010. Dynamical fingerprints for probing
          individual relaxation processes in biomolecular dynamics with
          simulations and kinetic experiments. PNAS 108 (12): 4822-4827.
  
      Notes
      -----
      Fingerprints are a combination of time-scale and amplitude spectrum for
      a equilibrium correlation or a non-equilibrium relaxation experiment.
  
      **Relaxation**
  
      A relaxation experiment looks at the time dependent expectation
      value of an observable for a system out of equilibrium
  
      .. math:: \mathbb{E}_{w_{0}}[a(x, t)]=\sum_x w_0(x) a(x, t)=\sum_x w_0(x) \sum_y p^t(x, y) a(y).
  
      The fingerprint amplitudes :math:`\gamma_i` are given by
  
      .. math:: \gamma_i=\langle w_0, r_i\rangle \langle l_i, a \rangle.
  
      And the fingerprint time scales :math:`t_i` are given by
  
      .. math:: t_i=-\frac{\tau}{\log \lvert \lambda_i \rvert}.
  
      Examples
      --------
  
      >>> import numpy as np
      >>> from msmtools.analysis import fingerprint_relaxation
  
      >>> T = np.array([[0.9, 0.1, 0.0], [0.5, 0.0, 0.5], [0.0, 0.1, 0.9]])
      >>> p0 = np.array([1.0, 0.0, 0.0])
      >>> a = np.array([1.0, 0.0, 0.0])
      >>> ts, amp = fingerprint_relaxation(T, p0, a)
  
      >>> ts
      array([        inf,  9.49122158,  0.43429448])
  
      >>> amp
      array([ 0.45454545,  0.5       ,  0.04545455])
  
      """
      # check if square matrix and remember size
      T = _types.ensure_ndarray_or_sparse(T, ndim=2, uniform=True, kind='numeric')
      n = T.shape[0]
      # will not do fingerprint analysis for nonreversible matrices
      if not is_reversible(T):
          raise ValueError('Fingerprint calculation is not supported for nonreversible transition matrices. ')
      p0 = _types.ensure_ndarray(p0, ndim=1, size=n, kind='numeric')
      obs = _types.ensure_ndarray(obs, ndim=1, size=n, kind='numeric')
      # go
      if _issparse(T):
          return sparse.fingerprints.fingerprint_relaxation(T, p0, obs, tau=tau, k=k, ncv=ncv)
      else:
          return dense.fingerprints.fingerprint_relaxation(T, p0, obs, tau=tau, k=k)