code: def generate_folds(
      num_rows, num_folds=10, strata=None, clusters=None
  ):
      """Generates folds for a given number of rows.
  
      :param num_rows: number of data instances
      :param num_folds: number of folds to use (default 10)
      :param strata: (optional) list of lists to indicate different
          sampling strata. Not all rows must be in a stratum. The number of
          rows per stratum must be larger than or equal to num_folds.
      :param clusters: (optional) list of lists indicating clustered instances.
          Clustered instances must be placed in a single fold to avoid
          information leaks.
      :returns: a list of folds, each fold is a list of instance indices
  
      >>> folds = generate_folds(num_rows=6, num_folds=2, clusters=[[1, 2]], strata=[[3,4]])
      >>> len(folds)
      2
      >>> i1 = [idx for idx, fold in enumerate(folds) if 1 in fold]
      >>> i2 = [idx for idx, fold in enumerate(folds) if 2 in fold]
      >>> i1 == i2
      True
      >>> i3 = [idx for idx, fold in enumerate(folds) if 3 in fold]
      >>> i4 = [idx for idx, fold in enumerate(folds) if 4 in fold]
      >>> i3 == i4
      False
  
      .. warning::
          Instances in strata are not necessarily spread out over all folds. Some
          folds may already be full due to clusters. This effect should be negligible.
  
      """
  
      # sizes per fold and initialization of folds
      sizes = _fold_sizes(num_rows, num_folds)
      folds = [[] for _ in range(num_folds)]
  
      # the folds that still need to be filled
      fill_queue = set(range(num_folds))
  
      # the instances that still need to be assigned
      instances = set(range(num_rows))
  
      if not strata:
          strata = []
  
      if not clusters:
          clusters = []
  
      # instances not in any stratum/cluster are treated as a final stratum
      if strata:
          assigned = set(it.chain(*strata))
      else:
          assigned = set()
      if clusters:
          assigned.update(it.chain(*clusters))
  
      if assigned:
          strata.append(
              list(filter(lambda x: x not in assigned, instances))
          )
      else:
          strata.append(list(instances))
  
      if clusters:
          # sort clusters by size
          sorted_cluster_indices, _ = zip(
              *sorted(
                  enumerate(clusters),
                  key=lambda x: len(x[1]),
                  reverse=True,
              )
          )
  
          # assign clusters
          for cluster_idx in sorted_cluster_indices:
              # retrieve eligible folds: folds that will not surpass maximum
              # when we assign given cluster to them
              cluster = clusters[cluster_idx]
              cluster_size = len(cluster)
              eligible = list(
                  filter(
                      lambda x: len(folds[x]) + cluster_size
                      <= sizes[x],
                      fill_queue,
                  )
              )
  
              if not eligible:
                  raise ValueError(
                      "Unable to assign all clusters to folds."
                  )
  
              # choose a fold at random
              fold_idx = random.choice(eligible)
              folds[fold_idx].extend(cluster)
  
              # update instances to-be-assigned
              instances.difference_update(cluster)
  
              # remove fold from fill_queue if it is full
              if len(folds[fold_idx]) >= sizes[fold_idx]:
                  fill_queue.remove(fold_idx)
  
      # assign strata
      for stratum in strata:
          permuted_stratum = random_permutation(
              list(filter(lambda x: x in instances, stratum[:]))
          )
          while permuted_stratum:
              eligible = list(
                  filter(lambda x: len(folds[x]) < sizes[x], fill_queue)
              )
  
              if not eligible:
                  raise ValueError(
                      "Unable to assign all instances to folds."
                  )
  
              eligible = random_permutation(eligible)
              for instance_idx, fold_idx in zip(
                  permuted_stratum[:], eligible
              ):
                  folds[fold_idx].append(instance_idx)
                  if len(folds[fold_idx]) >= sizes[fold_idx]:
                      fill_queue.remove(fold_idx)
                  instances.remove(instance_idx)
  
              permuted_stratum = permuted_stratum[len(eligible) :]
  
      return folds
  
imports: import math
  import random
  import itertools
  import functools
  import operator
  import array
  import inspect
label_desc: Use image node_id 5 for calling a global function with example usage: generate_folds(num_rows, num_folds, strata, clusters) and returns: folds