def sampen(data, emb_dim=2, tolerance=None, dist=rowwise_chebyshev,
           debug_plot=False, debug_data=False, plot_file=None):
  """
  Computes the sample entropy of the given data.

  Explanation of the sample entropy:
    The sample entropy of a time series is defined as the negative natural
    logarithm of the conditional probability that two sequences similar for
    emb_dim points remain similar at the next point, excluding self-matches.

    A lower value for the sample entropy therefore corresponds to a higher
    probability indicating more self-similarity.

  Explanation of the algorithm:
    The algorithm constructs all subsequences of length emb_dim
    [s_1, s_2, s_3, ...] and then counts each pair (s_i, s_j) with i != j
    where dist(s_i, s_j) < tolerance. The same process is repeated for all
    subsequences of length emb_dim + 1. The sum of similar sequence pairs
    with length emb_dim + 1 is divided by the sum of similar sequence pairs
    with length emb_dim. The result of the algorithm is the negative logarithm
    of this ratio/probability.

  References:
    .. [se_1] J. S. Richman and J. R. Moorman, “Physiological time-series
       analysis using approximate entropy and sample entropy,”
       American Journal of Physiology-Heart and Circulatory Physiology,
       vol. 278, no. 6, pp. H2039–H2049, 2000.

  Reference code:
    .. [se_a] "sample_entropy" function in R-package "pracma",
        url: https://cran.r-project.org/web/packages/pracma/pracma.pdf

  Args:
    data (array-like of float):
      input data

  Kwargs:
    emb_dim (int):
      the embedding dimension (length of vectors to compare)
    tolerance (float):
      distance threshold for two template vectors to be considered equal
      (default: 0.2 * std(data))
    dist (function (2d-array, 1d-array) -> 1d-array):
      distance function used to calculate the distance between template
      vectors. Sampen is defined using ``rowwise_chebyshev``. You should only use
      something else, if you are sure that you need it.
    debug_plot (boolean):
      if True, a histogram of the individual distances for m and m+1
    debug_data (boolean):
      if True, debugging data will be returned alongside the result
    plot_file (str):
      if debug_plot is True and plot_file is not None, the plot will be saved
      under the given file name instead of directly showing it through
      ``plt.show()``

  Returns:
    float:
      the sample entropy of the data (negative logarithm of ratio between
      similar template vectors of length emb_dim + 1 and emb_dim)
    [float list, float list]:
      Lists of lists of the form ``[dists_m, dists_m1]`` containing the distances
      between template vectors for m (dists_m) and for m + 1 (dists_m1).
  """
  data = np.asarray(data)
    
  if tolerance is None:
    tolerance = 0.2 * np.std(data)
  n = len(data)

  # build matrix of "template vectors"
  # (all consecutive subsequences of length m)
  # x0 x1 x2 x3 ... xm-1
  # x1 x2 x3 x4 ... xm
  # x2 x3 x4 x5 ... xm+1
  # ...
  # x_n-m-1     ... xn-1

  # since we need two of these matrices for m = emb_dim and m = emb_dim +1,
  # we build one that is large enough => shape (emb_dim+1, n-emb_dim)

  # note that we ignore the last possible template vector with length emb_dim,
  # because this vector has no corresponding vector of length m+1 and thus does
  # not count towards the conditional probability
  # (otherwise first dimension would be n-emb_dim+1 and not n-emb_dim)
  tVecs = delay_embedding(np.asarray(data), emb_dim+1, lag=1)
  plot_data = []
  counts = []
  for m in [emb_dim, emb_dim + 1]:
    counts.append(0)
    plot_data.append([])
    # get the matrix that we need for the current m
    tVecsM = tVecs[:n - m + 1, :m]
    # successively calculate distances between each pair of template vectors
    for i in range(len(tVecsM) - 1):
      dsts = dist(tVecsM[i + 1:], tVecsM[i])
      if debug_plot:
        plot_data[-1].extend(dsts)
      # count how many distances are smaller than the tolerance
      counts[-1] += np.sum(dsts < tolerance)
  if counts[1] == 0:
    # log would be infinite => cannot determine saen
    saen = np.inf
  else:
    saen = -np.log(1.0 * counts[1] / counts[0])
  if debug_plot:
    plot_dists(plot_data, tolerance, m, title="sampEn = {:.3f}".format(saen),
               fname=plot_file)
  if debug_data:
    return (saen, plot_data)
  else:
    return saen
Computes the sample entropy of the given data.

  Explanation of the sample entropy:
    The sample entropy of a time series is defined as the negative natural
    logarithm of the conditional probability that two sequences similar for
    emb_dim points remain similar at the next point, excluding self-matches.

    A lower value for the sample entropy therefore corresponds to a higher
    probability indicating more self-similarity.

  Explanation of the algorithm:
    The algorithm constructs all subsequences of length emb_dim
    [s_1, s_2, s_3, ...] and then counts each pair (s_i, s_j) with i != j
    where dist(s_i, s_j) < tolerance. The same process is repeated for all
    subsequences of length emb_dim + 1. The sum of similar sequence pairs
    with length emb_dim + 1 is divided by the sum of similar sequence pairs
    with length emb_dim. The result of the algorithm is the negative logarithm
    of this ratio/probability.

  References:
    .. [se_1] J. S. Richman and J. R. Moorman, “Physiological time-series
       analysis using approximate entropy and sample entropy,”
       American Journal of Physiology-Heart and Circulatory Physiology,
       vol. 278, no. 6, pp. H2039–H2049, 2000.

  Reference code:
    .. [se_a] "sample_entropy" function in R-package "pracma",
        url: https://cran.r-project.org/web/packages/pracma/pracma.pdf

  Args:
    data (array-like of float):
      input data

  Kwargs:
    emb_dim (int):
      the embedding dimension (length of vectors to compare)
    tolerance (float):
      distance threshold for two template vectors to be considered equal
      (default: 0.2 * std(data))
    dist (function (2d-array, 1d-array) -> 1d-array):
      distance function used to calculate the distance between template
      vectors. Sampen is defined using ``rowwise_chebyshev``. You should only use
      something else, if you are sure that you need it.
    debug_plot (boolean):
      if True, a histogram of the individual distances for m and m+1
    debug_data (boolean):
      if True, debugging data will be returned alongside the result
    plot_file (str):
      if debug_plot is True and plot_file is not None, the plot will be saved
      under the given file name instead of directly showing it through
      ``plt.show()``

  Returns:
    float:
      the sample entropy of the data (negative logarithm of ratio between
      similar template vectors of length emb_dim + 1 and emb_dim)
    [float list, float list]:
      Lists of lists of the form ``[dists_m, dists_m1]`` containing the distances
      between template vectors for m (dists_m) and for m + 1 (dists_m1).