code: def _random_indices(
      data,
      num_experiences: int,
      shuffle: bool = True,
      seed: Optional[int] = None,
      min_class_patterns_in_exp: int = 0,
  ) -> List[List[int]]:
      """Random indices splitter.
  
      Internal helper for `new_instances_benchmark.
  
      :param min_class_patterns_in_exp: the random split must respect the
          constraint of having at least `min_min_class_patterns_in_exp`
          samples per class.
  
      :return: a list of indices for each experience.
      """
      if seed is not None:
          torch.random.manual_seed(seed)
  
      ##############################
      # Validate function arguments
      ##############################
      if num_experiences < 1:
          raise ValueError(
              "Invalid number of experiences (n_experiences "
              "parameter): must be greater than 0"
          )
      if min_class_patterns_in_exp < 0:
          raise ValueError(
              "Invalid min_class_patterns_in_exp parameter: "
              "must be greater than or equal to 0"
          )
  
      ##############################
      # patterns -> experience assignment for train stream
      ##############################
      idxs_per_class = data.targets.val_to_idx
  
      # experience->idxs assignment
      exps_idxs: List[List[int]] = [[] for _ in range(num_experiences)]
  
      # validate `min_class_patterns_in_exp` argument
      min_class_patterns = min(
          [len(el) for el in idxs_per_class.values()]
      )
      if (
          min_class_patterns
          < num_experiences * min_class_patterns_in_exp
      ):
          raise ValueError(
              "min_class_patterns_in_exp constraint "
              "can't be satisfied"
          )
  
      for class_id, class_idxs in idxs_per_class.items():
          # INVARIANT: class_idxs keeps only indices that are not assigned yet. Whenever we add idxs to an experience, we remove them from class_idxs
  
          # first assign exactly min_class_patterns_in_exp.
          for eid in range(num_experiences):
              exps_idxs[eid].extend(
                  class_idxs[:min_class_patterns_in_exp]
              )
              class_idxs = class_idxs[min_class_patterns_in_exp:]
  
          # distribute equally among experiences
          samples_per_exp = len(class_idxs) // num_experiences
          for eid in range(num_experiences):
              exps_idxs[eid].extend(class_idxs[:samples_per_exp])
              class_idxs = class_idxs[samples_per_exp:]
  
          # distribute remaining patterns
          if len(class_idxs) > 0:
              if shuffle:
                  exps_remaining: Iterable[int] = torch.randperm(
                      num_experiences
                  ).tolist()[: len(class_idxs)]
              else:
                  exps_remaining = range(len(class_idxs))
  
              for eid in exps_remaining:
                  exps_idxs[eid].append(class_idxs[0])
                  class_idxs = class_idxs[1:]
  
      # sort to keep original order instead of class-order
      for ii in range(len(exps_idxs)):
          exps_idxs[ii].sort()
      return exps_idxs
  
imports: import warnings
  from copy import copy
  from typing import Iterable, Sequence, Optional, Dict, List, Protocol
  import torch
  from avalanche.benchmarks.utils.classification_dataset import ClassificationDataset, _as_taskaware_supervised_classification_dataset, TaskAwareSupervisedClassificationDataset
  from avalanche.benchmarks.utils.data import AvalancheDataset
  from avalanche.benchmarks.utils.data_attribute import DataAttribute
  from .dataset_scenario import _split_dataset_by_attribute, DatasetExperience
  from ..None import CLScenario, CLStream, EagerCLStream
label_desc: Use image node_id 3 for calling a global function with example usage: _random_indices(data, num_experiences, shuffle, seed, min_class_patterns_in_exp) and returns: exps_idxs