text: """
  @file
  @brief Helpers to compare executions.
  """
  from .validate_difference import measure_relative_difference
  
  
  def side_by_side_by_values(sessions, *args, inputs=None, **kwargs):
      """
      Compares the execution of two sessions.
      It calls method :meth:`OnnxInference.run
      <mlprodict.onnxrt.onnx_inference.OnnxInference.run>`
      with value ``intermediate=True`` and compares the results.
  
      @param      sessions        list of class @see cl OnnxInference
      @param      inputs          inputs
      @param      args            additional parameters for
                                  :meth:`OnnxInference.run
                                  <mlprodict.onnxrt.onnx_inference.OnnxInference.run`
      @param      kwargs          additional parameters for
                                  :meth:`OnnxInference.run
                                  <mlprodict.onnxrt.onnx_inference.OnnxInference.run`
      @return                     list of dictionaries
  
      The first session is considered as the baseline.
      See notebook :ref:`onnxsbsrst` for an example.
      If *inputs* is None, the function assumes
      *sessions* is a list of *tuple(sessions, inputs)*
      because sometimes inputs must be different.
      """
      if not kwargs.get('intermediate', True):
          raise ValueError("kwargs must not set intermediate to True")
      kwargs['intermediate'] = True
      verbose = kwargs.get('verbose', 0)
      fLOG = kwargs.get('fLOG', None)
  
      # run
      results = []
      for i, sess in enumerate(sessions):
          if isinstance(sess, tuple) and inputs is None:
              new_sess, new_inputs = sess
          else:
              new_sess = sess
              new_inputs = inputs
          if verbose > 0 and fLOG:
              fLOG('[side_by_side_by_values] run session {}/{}'.format(
                  i + 1, len(sessions)))
          res = new_sess.run(new_inputs, *args, **kwargs)
          results.append([(k, v) for k, v in res.items()])
  
      # same number of results?
      rows = []
      row = {"metric": "nb_results", 'step': -1}
      for i, res in enumerate(results):
          row["v[%d]" % i] = len(res)
      mnd = min(map(len, results))
      mxd = max(map(len, results))
      row['cmp'] = 'OK' if mnd == mxd else '!='
      rows.append(row)
  
      # analysis
      for i in range(mnd):
          row = {'step': i}
          res_row = [res[i] for res in results]
          names = [kv[0] for kv in res_row]
          min_n = min(names)
          max_n = max(names)
          if min_n != max_n:
              row['names'] = "{} -> {}".format(min_n, max_n)
          else:
              row['name'] = min_n
          row['metric'] = 'abs-diff'
  
          vals = []
          for j, r in enumerate(res_row):
              row['value[%d]' % j] = r[1]
              if hasattr(r[1], 'shape'):
                  row['shape[%d]' % j] = r[1].shape
  
              if j == 0:
                  row['v[%d]' % j] = 0
              else:
                  v = measure_relative_difference(res_row[0][1], r[1])
                  row['v[%d]' % j] = v
                  vals.append(v)
          diff = max(vals)
          if diff < 1e-5:
              row['cmp'] = 'OK'
          elif diff < 0.0001:
              row['cmp'] = 'e<0.0001'
          elif diff < 0.001:
              row['cmp'] = 'e<0.001'
          elif diff < 0.01:
              row['cmp'] = 'e<0.01'
          elif diff < 0.1:
              row['cmp'] = 'e<0.1'
          else:
              row['cmp'] = "ERROR->=%1.1f" % diff
          rows.append(row)
      return rows
  