code: def _evaluate_means_assertion(to_reduce, expected, axis, atol, rtol):
      """Evaluates `assertAllMeansClose` assertion quality.
  
      The results of the evaluation are packed into a list of `_Result`
      objects (one per batch member), which can then be post-processed for
      presentation depending on the medium.
  
      Args:
        to_reduce: Numpy array of samples, presumed IID along `axis`.
          Other dimensions are taken to be batch dimensions.
        expected: Numpy array of expected mean values.  Must broadcast
          with the reduction of `to_reduce` along `axis`.
        axis: Python `int` giving the reduction axis.
        atol: Python `float`, absolute tolerance for the means.
        rtol: Python `float`, relative tolerance for the means.
  
      Returns:
        results: A Python list of `_Result` objects, one for each batch member.
      """
      assert isinstance(
          axis, int
      ), "TODO(cgs): Handle multiple reduction axes"
  
      # Normalize so we correctly handle negative axes below.
      axis = axis if axis >= 0 else axis + len(to_reduce.shape)
  
      # Compute reduction size
      reduction_size = to_reduce.shape[axis]
  
      # Pull the axis to be reduced to the front, so we can iterate over
      # the others
      permutation = np.concatenate(
          [
              [axis],
              np.arange(0, axis, dtype=np.int32),
              np.arange(axis + 1, len(to_reduce.shape), dtype=np.int32),
          ],
          axis=0,
      )
      to_reduce = np.transpose(to_reduce, permutation)
  
      # Broadcast everything.  The subtlety is that we protect the top
      # axis of to_reduce, because that's now the reduction axis.  For
      # that we need to broadcast underneath it.
      batch_example = np.zeros(
          to_reduce.shape[1:], dtype=to_reduce.dtype
      )
      for array in [expected, atol, rtol]:
          batch_example = batch_example + np.zeros_like(
              array, dtype=batch_example.dtype
          )
      # Rank-expand to_reduce, in case the batch had more dimensions.
      # Doing this explicitly to keep the reduction axis on top and to
      # avoid broadcasting it.
      while len(to_reduce.shape) <= len(batch_example.shape):
          to_reduce = to_reduce[:, np.newaxis, ...]
  
      to_reduce = to_reduce + batch_example
      expected = expected + batch_example
      atol = atol + batch_example
      rtol = rtol + batch_example
  
      # Iterate over batch members
      results = []
      for indices in np.ndindex(to_reduce.shape[1:]):
          sub_to_reduce = to_reduce
          sub_expected = expected
          sub_atol = atol
          sub_rtol = rtol
  
          for index in indices:
              sub_to_reduce = sub_to_reduce[:, index, ...]
              sub_expected = sub_expected[index, ...]
              sub_atol = sub_atol[index, ...]
              sub_rtol = sub_rtol[index, ...]
  
          tolerance = sub_atol + sub_rtol * np.abs(sub_expected)
          bootstrap, gaussian = _evaluate_one_batch_member(
              sub_to_reduce, sub_expected, reduction_size, tolerance
          )
          results.append(
              _Result(
                  indices,
                  reduction_size,
                  sub_expected,
                  tolerance,
                  bootstrap,
                  gaussian,
              )
          )
  
      return results
  
imports: import collections
  import numpy
  import scipy.optimize
  import scipy.stats
label_desc: Use image node_id 8 for calling a global function with example usage: _evaluate_means_assertion(to_reduce, expected, axis, atol, rtol) and returns: results