Source code for poulet_py.tools.generators

try:
    from random import shuffle
    from typing import Any, Literal
except ImportError as e:
    msg = """
Missing 'tools' module. Install options:
- Module:       pip install poulet_py[tools]
- Full:         pip install poulet_py[all]
"""
    raise ImportError(msg) from e


[docs] def generate_stimulus_sequence( n: int, *, stimuli_options: list[Any], mode: Literal["random", "fixed"] = "random", ) -> list[Any]: """ Generate a list of trials with specified stimuli distribution. Parameters ---------- n : int Number of trials to generate. Must be divisible by the number of stimuli options when mode is 'random' or when multiple stimuli are provided in 'fixed' mode. stimuli_options : List[Any] List of possible stimulus values. For a single stimulus, all trials will use it. For multiple stimuli, distribution depends on mode. mode : {'random', 'fixed'}, optional Distribution mode: - 'random': Shuffled trials with equal representation of each stimulus - 'fixed': Trials use stimuli in sequence (or single stimulus repeated) (default: 'random') Returns ------- List[Any] Generated list of stimuli for each trial Raises ------ ValueError If n is not divisible by number of stimuli options (for relevant modes), or if mode is invalid. Notes ----- - For 'random' mode with multiple stimuli, each appears exactly n//len(stimuli_options) times. - For 'fixed' mode with multiple stimuli, stimuli are repeated in sequence until n is reached. - For 'fixed' mode with single stimulus, that stimulus is repeated n times. Examples -------- >>> generate_trials(4, stimuli_options=[1, 2], mode="random") [2, 1, 2, 1] # Random order with equal representation >>> generate_trials(3, stimuli_options=[5], mode="fixed") [5, 5, 5] """ n_stim = len(stimuli_options) if n_stim == 0: msg = "stimuli_options cannot be empty" raise ValueError(msg) # Validate input for modes that require equal representation if mode == "random" or (mode == "fixed" and n_stim > 1): if n % n_stim != 0: msg = f"Number of trials ({n}) must be divisible by the number" "of stimuli ({n_stim}) for equal representation in mode '{mode}'." raise ValueError(msg) if mode == "random": # Create balanced representation then shuffle trials = stimuli_options * (n // n_stim) shuffle(trials) return trials elif mode == "fixed": if n_stim == 1: return stimuli_options * n # For multiple stimuli in fixed mode, repeat the sequence return (stimuli_options * ((n // n_stim) + 1))[:n] msg = f"Invalid mode '{mode}'. Choose 'random' or 'fixed'." raise ValueError(msg)