code: def check_data_complete(data, parameter_columns):
      
  
      param_edges = [p[1:] for p in parameter_columns if isinstance(p, (Tuple, List))]  # strip out call column name
  
      # check no overlaps/gaps
      for p in param_edges:
          other_params = [p_ed[0] for p_ed in param_edges if p_ed != p]
          if other_params:
              sub_tables = data.groupby(list(other_params))
          else:
              sub_tables = {None: data}.items()
  
          n_p_total = len(set(data[p[0]]))
  
          for _, table in sub_tables:
  
              param_data = table[[p[0], p[1]]].copy().sort_values(by=p[0])
              start, end = param_data[p[0]].reset_index(drop=True), param_data[p[1]].reset_index(drop=True)
  
              if len(set(start)) < n_p_total:
                  raise ValueError(f'You must provide a value for every combination of {parameter_columns}.')
  
              if len(start) <= 1:
                  continue
              for i in range(1, len(start)):
                  e = end[i-1]
                  s = start[i]
                  if e > s or s == start[i-1]:
                      raise ValueError(f'Parameter data must not contain overlaps. Parameter {p} '
                                       f'contains overlapping data.')
                  if e < s:
                      raise NotImplementedError(f'Interpolation only supported for parameter columns '
                                                f'with continuous bins. Parameter {p} contains '
                                                f'non-continuous bins.')
docs: For any parameters specified with edges, make sure edges
      don't overlap and don't have any gaps. Assumes that edges are
      specified with ends and starts overlapping (but one exclusive and
      the other inclusive) so can check that end of previous == start
      of current.
  
      If multiple parameters, make sure all combinations of parameters
      are present in data.