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
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.
    
avalanche/benchmarks/scenarios/supervised.py