code: def filter(configs, settings):
      
      if isinstance(configs, pd.DataFrame):
          configs = configs[['a', 'b', 'm', 'n']].values
  
      # assign short labels to Python functions
      filter_funcs = {
          'dd': _filter_dipole_dipole,
          'schlumberger': _filter_schlumberger,
      }
  
      # we need a list to fix the call order of filter functions
      keys = ['dd', 'schlumberger', ]
  
      allowed_keys = settings.get('only_types', filter_funcs.keys())
  
      results = {}
      # we operate iteratively on the configs, set the first round here
      # rows are iteratively set to nan when filters remove them!
      configs_filtered = configs.copy().astype(float)
  
      for key in keys:
          if key in allowed_keys:
              configs_filtered, indices_filtered = filter_funcs[key](
                  configs_filtered,
              )
              if len(indices_filtered) > 0:
                  results[key] = indices_filtered
  
      # add all remaining indices to the results dict
      results['not_sorted'] = np.where(
          ~np.all(np.isnan(configs_filtered), axis=1)
      )[0]
      return results
docs: Main entry function to filtering configuration types
  
      Parameters
      ----------
      configs: Nx4 array
          array containing A-B-M-N configurations
      settings: dict
          'only_types': ['dd', 'other'],  # filter only for those types
  
      Returns
      -------
      dict
          results dict containing filter results (indices) for all registered
          filter functions.  All remaining configs are stored under the keywords
          'remaining'