| Title: | Simulate Outcomes of a Latent State Reinforcement Learning Model |
| Version: | 1.0.0 |
| Description: | Simulates outcomes of an updated version of the latent state reinforcement learning model originally described in Cochran and Cisler (2019) <doi:10.1371/journal.pcbi.1007331>. The package is designed to create results under all reasonable experiment setups, including different reinforcement schedules, number of cues, number of phases, and number of options per trial. Participants can be simulated using either fixed parameters or parameters drawn from a distribution. |
| License: | GPL (≥ 3) |
| URL: | https://osf.io/2whcu |
| Encoding: | UTF-8 |
| RoxygenNote: | 8.0.0 |
| NeedsCompilation: | no |
| Packaged: | 2026-09-08 19:41:12 UTC; marti |
| Author: | Martin Benada [aut, cre] |
| Maintainer: | Martin Benada <martinibenada@gmail.com> |
| Repository: | CRAN |
| Date/Publication: | 2026-09-17 09:30:09 UTC |
latentState: Simulate Outcomes of a Latent State Reinforcement Learning Model
Description
Simulates outcomes of an updated version of the latent state reinforcement learning model originally described in Cochran and Cisler (2019) doi:10.1371/journal.pcbi.1007331. The package is designed to create results under all reasonable experiment setups, including different reinforcement schedules, number of cues, number of phases, and number of options per trial. Participants can be simulated using either fixed parameters or parameters drawn from a distribution.
Author(s)
Maintainer: Martin Benada martinibenada@gmail.com
Authors:
Martin Benada martinibenada@gmail.com
See Also
Useful links:
Build a fixed, non-randomized trial world for use with run()
Description
Constructs the c_vec (cue array) and win (reward array)
needed for the my_world argument of run(), letting you
specify an exact trial-by-trial cue and reward sequence instead of
having one randomly generated from phase_def.
Usage
make_world(trial_patterns, reward, L = 10, features = NULL)
Arguments
trial_patterns |
Character vector, one element per trial, giving
the cues shown on each arm. Use letters for cues, |
reward |
Numeric vector, or list of numeric vectors. Gives the
reward value for each trial, applied identically to every arm on that
trial regardless of which arm is later chosen by the agent (unlike
|
L |
Integer. The total number of latent states the resulting
|
features |
Character vector, or |
Value
A list with three elements, matching the format run()
expects for my_world:
c_vecArray (
D x C x L x A x ntrials) of 0/1 cue activations, indicating which cues are active on each arm and trial, identical across every latent state.winArray (
D x A x ntrials) of reward values, with the same value broadcast across every arm on a given trial.type_seqA one-element list wrapping
trial_patterns, matching the phase-structured formatrun()produces internally.
Examples
my_world <- make_world(
trial_patterns = c("A", "A", "B", "A", "B"),
reward = c(1, 0, 1, 1, 0),
L = 10
)
phase_def <- list(phase1 = list(trials = list(A = 3, B = 2)))
result <- run(phase_def, n = 1, my_world = my_world)
Compare latent-state learning results across groups
Description
Overlays results from multiple run() calls (e.g. different
groups, conditions, or parameter settings) on the same plots, allowing
direct visual comparison. Cues are distinguished by color and groups by
line type (or by color alone, for the presentation-based plots).
Usage
plot_compare(
...,
plot = FALSE,
plot_avg = FALSE,
fixed_axis = TRUE,
plot_sd = FALSE,
plot_label = FALSE,
plot_shown = FALSE,
plot_cue = FALSE,
plot_appear = FALSE
)
Arguments
... |
One or more outputs of |
plot |
Logical. If |
plot_avg |
Logical. If |
fixed_axis |
Logical. If |
plot_sd |
Logical. If |
plot_label |
Logical. If |
plot_shown |
Logical. If |
plot_cue |
Logical. If |
plot_appear |
Logical. If |
Value
No return value. Called for its side effect of producing one or
more base R plots comparing latent-state values across the supplied
groups. Invisibly returns NULL.
Examples
phase_def <- list(phase1 = list(trials = list(A = 20, B = 20)))
ctrl <- run(phase_def, n = 5, alpha0 = "0.1")
treatment <- run(phase_def, n = 5, alpha0 = "0.3")
plot_compare(ctrl = ctrl, treatment = treatment, plot_avg = TRUE)
Simulate latent-state reinforcement learning across participants
Description
Simulates outcomes of an updated latent-state reinforcement learning model (based on Cochran & Cisler, 2019) across one or more participants, under a user-specified experimental design. For full mathematical details of the underlying latent-state learning model, including changes from the original Cochran & Cisler model, see the supplementary materials on OSF: https://osf.io/2whcu
Usage
run(
phase_def,
n = 1,
seed = 42,
alpha0 = "0.2",
alpha1 = "0.05",
alpha2 = "0.05",
gamma = "0.01",
eta = "1.2",
delta = "0.6",
sigma0 = "0.5",
tau = "10",
lambda = "1",
pseudo = NULL,
block = NULL,
probabilistic = FALSE,
features = NULL,
V_noise_sd = 0,
ncop = 10,
group = "ctrl",
prev = 0,
ITI = NULL,
ezITI = NULL,
chi = "1",
contextShift = NULL,
my_world = NULL,
initialex = NULL,
plot = FALSE,
plot_all = FALSE,
plot_label = FALSE,
plot_arm = FALSE,
plot_mu = FALSE,
plot_mu_all = FALSE,
plot_shown = FALSE,
plot_cue = FALSE,
plot_sd = FALSE,
plot_raw = FALSE,
plot_raw_all = FALSE,
plot_q = FALSE,
plot_q_all = FALSE,
plot_sigma = FALSE,
plot_sigma_all = FALSE,
plot_appears = FALSE,
fixed_axis = TRUE
)
Arguments
phase_def |
A named list defining the task structure. Each element
represents one phase of the experiment and must contain two entries,
A simple example using a single reward dimension and one option per
trial is shown below. In phase 1, cue
phase_def <- list(
phase1 = list(
trials = list(A = 6, AB = 6),
rewards = list(c(A = 1))
),
phase2 = list(
trials = list(A = 8, AB = 16)
)
)
In experiments with multiple arms (choices), indicate the cues shown on
each arm within a trial type name, separating arms with See Examples below for a |
n |
Integer. The number of participants to simulate. Each participant
is run independently through the full task defined by |
seed |
Integer. A random seed passed to |
alpha0 |
Character string. The learning rate controlling how quickly
associative strengths ( |
alpha1 |
Character string. The learning rate controlling how quickly
the variance estimate ( |
alpha2 |
Character string. The learning rate controlling how quickly
the effort matrix ( |
gamma |
Character string. Controls the rate at which latent-state
beliefs drift toward a uniform distribution over active states between
trials. This same drift also determines the prior belief
assigned to a newly created latent state: when a new state is added, it
is initialized with a prior belief of |
eta |
Character string. The change-point threshold: a new latent
state is created once the accumulated change-point statistic reaches or
exceeds this value. Must evaluate to a non-negative numeric value,
where higher values make new-state creation less likely (requiring
stronger, sustained evidence of a change before splitting off a new
state). Passed as a string so it can specify either a fixed value (e.g.
|
delta |
Character string. A penalty that makes it harder for a new
latent state to be created. Each trial, this penalty is subtracted from
the evidence accumulating for a new state; if the evidence that trial
isn't strong enough to outweigh the penalty, the accumulated evidence
for a new state will decrease rather than increase. Higher
values raise the bar for what counts as strong enough evidence, so with
a large |
sigma0 |
Character string. The agent's initial assumption about how
much variability in outcomes is "expected," used to judge whether a
prediction error is surprising enough to be considered evidence for a new state. A
higher |
tau |
Character string. The inverse temperature parameter controlling
how deterministic choices are. Higher values make the agent more likely
to consistently pick the option with the highest expected value, while
lower values make choices more random, giving lower-valued options a
better chance of being picked anyway. Must evaluate to a positive
numeric value. Passed as a string so it can specify either a fixed
value (e.g. |
lambda |
Character string. Controls how much more strongly beliefs
update on trials that are especially informative about which latent
state is active. Informativeness is measured by how unevenly the
evidence favors one state over the others on that trial.
When one state clearly stands out, |
pseudo |
Integer or |
block |
Integer, numeric vector, or |
probabilistic |
Logical. If |
features |
Character vector, or To track only a subset of these – for example, dropping |
V_noise_sd |
Numeric. Standard deviation of Gaussian noise added to
the agent's associative strengths ( |
ncop |
Integer >= 1. Maximum number of latent states the agent can create. Default is 10. |
group |
Character. Label for this batch's experimental group
(e.g. |
prev |
Integer. Offset added to subject IDs in the long-format
output ( |
ITI |
List of numeric vectors, or For example, with |
ezITI |
List, or For example, with |
chi |
Character. The number of "rumination" iterations the agent
performs on a single trial's outcome before moving to the next trial.
Higher values let the agent update its associative strengths
repeatedly from the same outcome, simulating extra "thinking time"
between trials. The actual number of iterations used is capped by the
|
contextShift |
Numeric vector, or For example, |
my_world |
List, or |
initialex |
Numeric array, or |
plot |
Logical. If |
plot_all |
Logical. Same as |
plot_label |
Logical. If |
plot_arm |
Logical. If |
plot_mu |
Logical. If |
plot_mu_all |
Logical. Same as |
plot_shown |
Logical. If |
plot_cue |
Logical. If |
plot_sd |
Logical. If |
plot_raw |
Logical. If |
plot_raw_all |
Logical. Same as |
plot_q |
Logical. If |
plot_q_all |
Logical. Same as |
plot_sigma |
Logical. If |
plot_sigma_all |
Logical. Same as |
plot_appears |
Logical. If |
fixed_axis |
Logical. If |
Value
A list of length n, one element per participant. Each
element is itself a list containing:
arm_chosenInteger vector of length
ntrialsgiving the arm chosen by the agent on each trial.win_receivedMatrix (
ntrials x D) of the reward outcome received on each trial, for each reward dimension.lsbMatrix (
ntrials x L) of latent-state beliefs at the start of each trial, wherencopis the total number of latent states.LmaxInteger vector of length
ntrialsgiving the number of active latent states at each trial.qNumeric vector of length
ntrialsgiving the change-point statistic after that trial's reward but before any new-state creation/reset (the value used for plotting).sigmaNumeric vector of length
ntrialsgiving the agent's variance estimate at the start of each trial.muArray (
ntrials x D x A) of the overall expected valueVof each arm, for each reward dimension, before the agent's choice on each trial.mu_rawArray (
ntrials x D x L x A) of the unweighted expected value of each arm, shown separately for each latent state, for each reward dimension.VNamed list with one entry per base cue, each a matrix (
ntrials x D) of that cue's overall associative strength over trials.V_cueNamed list with one entry per base cue, each a matrix (presentations x D) of that cue's own overall value, recorded only on trials where the cue was shown.
V_rawNamed list with one entry per base cue, each an array (
ntrials x D x L) of that cue's raw (unweighted) associative strength in every latent state over trials.V_shownNamed list with one entry per trial type (e.g.
"A","AB"), each a matrix (presentations x D) of the agent's total V whenever that exact trial type was the chosen arm.V_appearNamed list with one entry per base cue, each a matrix (presentations x D) of the agent's total V on the chosen arm, recorded whenever that cue was part of the chosen arm.
BArray (
ntrials x C x C x D x L) giving the effort matrix, which governs cue associability, for every cue pair, reward dimension, and latent state, at every trial.parThe full parameter and task configuration used to generate this participant. The most useful pieces are
ls(the exact parameters used for this participant, e.g.alpha0,eta,delta) andtau(the inverse-temperature parameter used). The remaining fields (D,C,A,ntrials,base_cues,ITI, etc.) describe the task's structure and are mainly used internally (e.g. byplot_compare()) to recover cue counts, trial counts, and timing.worldList of the two arrays defining what was presented each trial:
c_vec(D x C x L x A x ntrials), which cues were active per dimension, latent state, and arm; andwin(D x A x ntrials), the reward generated for each arm and dimension, regardless of the agent's choice. Also includestype_seq, which is a list showing the order of cues presented to this participant.longList (one entry per phase) of data frames combining every cue type presented in that phase, in long format, for
D = 1only, intended for running an ANOVA using the ezANOVA package. Columns are:subject, the participant ID (i + prev, offset so IDs don't collide across combinedrun()calls);group, the batch label from thegroupargument;cue_type, the trial type or arm segment (e.g."A","AB") this row belongs to;presentation, the ordinal position of this row among all presentations of that cue type within this phase;V, the agent's overall associative value on that presentation; and, whenblockis specified,block, the block number that presentation falls into.
References
Cochran, A. L., & Cisler, J. M. (2019). A flexible and generalizable model of online latent-state learning. PLOS Computational Biology, 15(9). doi:10.1371/journal.pcbi.1007331
Examples
phase_def <- list(
phase1 = list(
trials = list(
A_B = 20,
B_A = 10,
AB_C = 12,
C_AB = 6,
B_0 = 5
),
rewards = list(
D1 = c(A = 0.80, B = 0.20, AB = 0.50),
D2 = c(A = 0.60, B = 0.00, AB = 0.00)
)
),
phase2 = list(
trials = list(
A_B = 15,
B_A = 15,
AB_C = 8,
C_AB = 8
),
rewards = list(
D1 = c(A = 0.10, B = 0.50, C = 0.00, AB = 0.25),
D2 = c(A = 0.00, B = 0.60, AB = 0.00)
)
)
)
result <- run(phase_def, n = 5)