class_docstr: Builds ensembles out of runs that exist in the Backend
  
  This is used by EnsembleBuilderManager and created in a dask-client
  every time a run finishes and there is currently no EnsembleBuilder active.
docstr: Cut a list of runs into those to keep and those to delete
  
  If neither params are specified, this method should do nothing.
  
  In the case of multiple metrics, we interleave these according to the order of
  the provided metrics.
  
  Parameters
  ----------
  runs : Sequence[Run]
      The runs to check
  
  max_models : int | None = None
      The maximum amount of models to have on disk. Leave `None` for no effect
  
  memory_limit : float | None = None
      The memory limit in MB, leave `None` for no effect
  
  metrics: Sequence[Scorer] | None = None
      The metrics to consider for the runs, defaults to `self.metrics` passed
      during construction if `None`.
  
  Returns
  -------
  (keep: list[Run], delete: set[Run])
      The list of runs to keep and those to delete
docstr_tok: ["Cut","a","list","of","runs","into","those","to","keep","and","those","to","delete","If","neither","params","are","specified",",","this","method","should","do","nothing",".","In","the","case","of","multiple","metrics",",","we","interleave","these","according","to","the","order","of","the","provided","metrics",".","Parameters","--","--","--","--","--","runs",":","Sequence","[","Run","]","The","runs","to","check","max_models",":","int","|","None","=","None","The","maximum","amount","of","models","to","have","on","disk",".","Leave","`","None","`","for","no","effect","memory_limit",":","float","|","None","=","None","The","memory","limit","in","MB",",","leave","`","None","`","for","no","effect","metrics",":","Sequence","[","Scorer","]","|","None","=","None","The","metrics","to","consider","for","the","runs",",","defaults","to","`","self.metrics","`","passed","during","construction","if","`","None","`",".","Returns","--","--","--","-","(","keep",":","list","[","Run","]",",","delete",":","set","[","Run","]",")","The","list","of","runs","to","keep","and","those","to","delete"]
code: def requires_deletion(
      self,
      runs: Sequence[Run],
      *,
      max_models: int | None = None,
      memory_limit: float | None = None,
      metrics: Sequence[Scorer] | None = None,
  ) -> tuple[list[Run], set[Run]]:
      """Cut a list of runs into those to keep and those to delete
  
      If neither params are specified, this method should do nothing.
  
      In the case of multiple metrics, we interleave these according to the order of
      the provided metrics.
  
      Parameters
      ----------
      runs : Sequence[Run]
          The runs to check
  
      max_models : int | None = None
          The maximum amount of models to have on disk. Leave `None` for no effect
  
      memory_limit : float | None = None
          The memory limit in MB, leave `None` for no effect
  
      metrics: Sequence[Scorer] | None = None
          The metrics to consider for the runs, defaults to `self.metrics` passed
          during construction if `None`.
  
      Returns
      -------
      (keep: list[Run], delete: set[Run])
          The list of runs to keep and those to delete
      """
      if memory_limit is None and max_models is None:
          return list(runs), set()
  
      metrics = metrics if metrics is not None else self.metrics
  
      # We order the runs according to a roundrobin of the metrics
      # i.e. the 1st run will be best in metric[0],
      #      the 2nd run will be best in metric[1],
      #      the 3rd run will be second best in metric[0],
      #      the 4th run will be second best in metric[1],
      #       ... whoops, what would be the 5th run, third best in metric[0] was also
      #       ... the same as the 4th run. This was skipped
      #      the 5th run will be third best in metric[1]  **as we skipped above**
      #
      # With removing duplicates, this means if a run was already contained, it will
      # skip to the next member in the roundrobin fashion.
      sorted_runs = [
          sorted(
              runs,
              key=lambda r: (
                  r.losses.get(metric.name, np.inf),
                  r.num_run,
              ),
          )
          for metric in metrics
      ]
      keep = list(roundrobin(*sorted_runs, duplicates=False))
  
      delete: set[Run] = set()
  
      if max_models is not None and max_models < len(runs):
          keep, to_delete = cut(keep, max_models)
  
          if any(to_delete):
              self.logger.info(
                  "Limiting num of models via `max_models_on_disc`"
                  f" max_models={max_models}"
                  f" remaining={len(keep)}"
                  f" discarded={len(to_delete)}"
              )
              delete.update(to_delete)
  
      if memory_limit is not None:
          largest = max(runs, key=lambda r: r.mem_usage)
          cutoff = memory_limit - largest.mem_usage
  
          accumulated_mem_usage = accumulate(r.mem_usage for r in runs)
  
          cutpoint = findwhere(
              accumulated_mem_usage, lambda mem: mem > cutoff
          )
          keep, to_delete = cut(keep, cutpoint)
  
          if any(to_delete):
              self.logger.info(
                  "Limiting num of models via `memory_limit`"
                  f" memory_limit={memory_limit}"
                  f" cutoff={cutoff}"
                  f" largest={largest.mem_usage}"
                  f" remaining={len(keep)}"
                  f" discarded={len(to_delete)}"
              )
              delete.update(to_delete)
  
      return keep, delete
  
imports: from __future__ import annotations
  from typing import Any, Iterable, Mapping, Sequence, Type, cast
  import logging.handlers
  import multiprocessing
  import numbers
  import os
  import pickle
  import time
  import traceback
  from itertools import accumulate
  from pathlib import Path
  import numpy
  import pandas
  import pynisher
  from sklearn.utils.validation import check_random_state
  from autosklearn.automl_common.common.utils.backend import Backend
  from autosklearn.data.validation import SUPPORTED_FEAT_TYPES
  from autosklearn.data.xy_data_manager import XYDataManager
  from autosklearn.ensemble_building.run import Run, RunID
  from autosklearn.ensembles.abstract_ensemble import AbstractEnsemble
  from autosklearn.ensembles.ensemble_selection import EnsembleSelection
  from autosklearn.metrics import Scorer, calculate_loss, calculate_scores
  from autosklearn.util.disk import rmtree
  from autosklearn.util.functional import cut, findwhere, roundrobin, split
  from autosklearn.util.logging_ import get_named_client_logger
  from autosklearn.util.parallel import preload_modules
label_desc: Use image node_id 12 for calling the EnsembleBuilder obj's underlying member method code with example usage: obj.requires_deletion(runs) and returns: keep,  delete, list,  set